Выбор фотографий

Диалоговое окно выбора фотографий появляется вместе с медиафайлами на вашем устройстве. Выберите фотографию, чтобы поделиться ею с приложением.
Рисунок 1. Инструмент выбора фотографий предоставляет интуитивно понятный пользовательский интерфейс для обмена фотографиями с вашим приложением.

Панель выбора фотографий предоставляет интерактивный интерфейс, отображающий пользователю его медиатеку, отсортированную по дате от самой новой к самой старой. Как показано в руководстве по лучшим практикам обеспечения конфиденциальности , панель выбора фотографий предоставляет безопасный встроенный способ для пользователей предоставлять вашему приложению доступ только к выбранным изображениям и видео, а не ко всей медиатеке.

Пользователи, у которых на устройстве установлены подходящие облачные медиапровайдеры, также могут выбирать фотографии и видео, хранящиеся удаленно. Узнайте больше об облачных медиапровайдерах .

Инструмент обновляется автоматически, предоставляя пользователям вашего приложения расширенные функциональные возможности с течением времени без необходимости внесения каких-либо изменений в код.

Используйте контракты Jetpack Activity.

Для упрощения интеграции средства выбора фотографий необходимо включить библиотеку androidx.activity версии 1.7.0 или выше.

Для запуска средства выбора фотографий используйте следующие контракты результатов действий:

Если средство выбора фотографий недоступно на устройстве, библиотека автоматически вызывает вместо него действие интента ACTION_OPEN_DOCUMENT . Этот интент поддерживается на устройствах под управлением Android 4.4 (уровень API 19) или выше. Проверить доступность средства выбора фотографий на конкретном устройстве можно, вызвав метод isPhotoPickerAvailable() .

Выберите один медиафайл

Для выбора отдельного медиафайла используйте контракт результата действия PickVisualMedia , как показано в следующем фрагменте кода:

Мнения

// Registers a photo picker activity launcher in single-select mode.
val pickMedia = registerForActivityResult(PickVisualMedia()) { uri ->
    // Callback is invoked after the user selects a media item or closes the
    // photo picker.
    if (uri != null) {
        Log.d("PhotoPicker", "Selected URI: $uri")
    } else {
        Log.d("PhotoPicker", "No media selected")
    }
}

// Include only one of the following calls to launch(), depending on the types
// of media that you want to let the user choose from.

// Launch the photo picker and let the user choose images and videos.
pickMedia.launch(PickVisualMediaRequest(PickVisualMedia.ImageAndVideo))

// Launch the photo picker and let the user choose only images.
pickMedia.launch(PickVisualMediaRequest(PickVisualMedia.ImageOnly))

// Launch the photo picker and let the user choose only videos.
pickMedia.launch(PickVisualMediaRequest(PickVisualMedia.VideoOnly))

// Launch the photo picker and let the user choose only images/videos of a
// specific MIME type, such as GIFs.
val mimeType = "image/gif"
pickMedia.launch(PickVisualMediaRequest(PickVisualMedia.SingleMimeType(mimeType)))

Мнения

// Registers a photo picker activity launcher in single-select mode.
ActivityResultLauncher<PickVisualMediaRequest> pickMedia =
        registerForActivityResult(new PickVisualMedia(), uri -> {
    // Callback is invoked after the user selects a media item or closes the
    // photo picker.
    if (uri != null) {
        Log.d("PhotoPicker", "Selected URI: " + uri);
    } else {
        Log.d("PhotoPicker", "No media selected");
    }
});

// Include only one of the following calls to launch(), depending on the types
// of media that you want to let the user choose from.

// Launch the photo picker and let the user choose images and videos.
pickMedia.launch(new PickVisualMediaRequest.Builder()
        .setMediaType(PickVisualMedia.ImageAndVideo.INSTANCE)
        .build());

// Launch the photo picker and let the user choose only images.
pickMedia.launch(new PickVisualMediaRequest.Builder()
        .setMediaType(PickVisualMedia.ImageOnly.INSTANCE)
        .build());

// Launch the photo picker and let the user choose only videos.
pickMedia.launch(new PickVisualMediaRequest.Builder()
        .setMediaType(PickVisualMedia.VideoOnly.INSTANCE)
        .build());

// Launch the photo picker and let the user choose only images/videos of a
// specific MIME type, such as GIFs.
String mimeType = "image/gif";
pickMedia.launch(new PickVisualMediaRequest.Builder()
        .setMediaType(new PickVisualMedia.SingleMimeType(mimeType))
        .build());

Сочинить

// Registers a photo picker activity launcher in single-select mode.
val pickMedia = rememberLauncherForActivityResult(PickVisualMedia()) { uri ->
    // Callback is invoked after the user selects a media item or closes the
    // photo picker.
    if (uri != null) {
        Log.d("PhotoPicker", "Selected URI: $uri")
    } else {
        Log.d("PhotoPicker", "No media selected")
    }
}

// Include only one of the following calls to launch(), depending on the types
// of media that you want to let the user choose from.

// Launch the photo picker and let the user choose images and videos.
pickMedia.launch(PickVisualMediaRequest(PickVisualMedia.ImageAndVideo))

// Launch the photo picker and let the user choose only images.
pickMedia.launch(PickVisualMediaRequest(PickVisualMedia.ImageOnly))

// Launch the photo picker and let the user choose only videos.
pickMedia.launch(PickVisualMediaRequest(PickVisualMedia.VideoOnly))

// Launch the photo picker and let the user choose only images/videos of a
// specific MIME type, such as GIFs.
val mimeType = "image/gif"
pickMedia.launch(PickVisualMediaRequest(PickVisualMedia.SingleMimeType(mimeType)))

Выберите несколько медиафайлов

Для выбора нескольких медиафайлов установите максимальное количество выбираемых медиафайлов, как показано в следующем фрагменте кода.

Мнения

// Registers a photo picker activity launcher in multi-select mode.
// In this example, the app lets the user select up to 5 media files.
val pickMultipleMedia =
        registerForActivityResult(PickMultipleVisualMedia(5)) { uris ->
    // Callback is invoked after the user selects media items or closes the
    // photo picker.
    if (uris.isNotEmpty()) {
        Log.d("PhotoPicker", "Number of items selected: ${uris.size}")
    } else {
        Log.d("PhotoPicker", "No media selected")
    }
}

// For this example, launch the photo picker and let the user choose images
// and videos. If you want the user to select a specific type of media file,
// use the overloaded versions of launch(), as shown in the section about how
// to select a single media item.
pickMultipleMedia.launch(PickVisualMediaRequest(PickVisualMedia.ImageAndVideo))

Мнения

// Registers a photo picker activity launcher in multi-select mode.
// In this example, the app lets the user select up to 5 media files.
ActivityResultLauncher<PickVisualMediaRequest> pickMultipleMedia =
        registerForActivityResult(new PickMultipleVisualMedia(5), uris -> {
    // Callback is invoked after the user selects media items or closes the
    // photo picker.
    if (!uris.isEmpty()) {
        Log.d("PhotoPicker", "Number of items selected: " + uris.size());
    } else {
        Log.d("PhotoPicker", "No media selected");
    }
});

// For this example, launch the photo picker and let the user choose images
// and videos. If you want the user to select a specific type of media file,
// use the overloaded versions of launch(), as shown in the section about how
// to select a single media item.
pickMultipleMedia.launch(new PickVisualMediaRequest.Builder()
        .setMediaType(PickVisualMedia.ImageAndVideo.INSTANCE)
        .build());

Сочинить

// Registers a photo picker activity launcher in multi-select mode.
// In this example, the app lets the user select up to 5 media files.
val pickMultipleMedia =
        rememberLauncherForActivityResult(PickMultipleVisualMedia(5)) { uris ->
    // Callback is invoked after the user selects media items or closes the
    // photo picker.
    if (uris.isNotEmpty()) {
        Log.d("PhotoPicker", "Number of items selected: ${uris.size}")
    } else {
        Log.d("PhotoPicker", "No media selected")
    }
}

// For this example, launch the photo picker and let the user choose images
// and videos. If you want the user to select a specific type of media file,
// use the overloaded versions of launch(), as shown in the section about how
// to select a single media item.
pickMultipleMedia.launch(PickVisualMediaRequest(PickVisualMedia.ImageAndVideo))

Платформа ограничивает максимальное количество файлов, которые пользователь может выбрать в окне выбора фотографий. Чтобы получить доступ к этому ограничению, вызовите метод getPickImagesMaxLimit() . На устройствах, где окно выбора фотографий не поддерживается, это ограничение игнорируется.

Доступность устройства

Функция выбора фотографий доступна на устройствах, отвечающих следующим критериям:

Older devices that run Android 4.4 (API level 19) through Android 10 (API level 29) and Android Go devices running Android 11 or 12 that support Google Play services can install a backported version of the photo picker. To enable the automatic installation of the backported photo picker module through Google Play services, add the following entry to the <application> tag in your app's manifest file:

<!-- Trigger Google Play services to install the backported photo picker module. -->
<service android:name="com.google.android.gms.metadata.ModuleDependencies"
         android:enabled="false"
         android:exported="false"
         tools:ignore="MissingClass">
    <intent-filter>
        <action android:name="com.google.android.gms.metadata.MODULE_DEPENDENCIES" />
    </intent-filter>
    <meta-data android:name="photopicker_activity:0:required" android:value="" />
</service>

Сохранение доступа к медиафайлам

По умолчанию система предоставляет вашему приложению доступ к медиафайлам до перезагрузки устройства или остановки приложения. Если ваше приложение выполняет длительную работу, например, загрузку большого файла в фоновом режиме, вам может потребоваться сохранить этот доступ на более длительный период времени. Для этого вызовите метод takePersistableUriPermission() :

Котлин

val flag = Intent.FLAG_GRANT_READ_URI_PERMISSION
context.contentResolver.takePersistableUriPermission(uri, flag)

Java

int flag = Intent.FLAG_GRANT_READ_URI_PERMISSION;
context.contentResolver.takePersistableUriPermission(uri, flag);

Обработка HDR-видео с транскодированием

Android 13 (API 33) introduced the capability to capture High Dynamic Range (HDR) videos . While HDR offers a richer visual experience, some older apps might not be equipped to handle these newer formats, leading to issues like unnatural color rendition during playback (such as green-tinted faces). To address this compatibility gap, the photo picker offers a transcoding feature that can automatically convert HDR videos to Standard Dynamic Range (SDR) format before providing them to the requesting app.

Основная цель транскодирования в Photo Picker — обеспечить единообразное и визуально точное отображение медиаконтента в более широком спектре приложений, даже тех, которые еще не имеют явной поддержки HDR. Транскодируя HDR-видео в SDR, Photo Picker стремится улучшить совместимость приложений и обеспечить бесперебойную работу пользователя.

Как работает транскодирование при выборе фотографий

Функция транскодирования HDR в окне выбора фотографий по умолчанию отключена. Чтобы включить эту функцию, ваше приложение должно явно указать свои возможности обработки медиаформатов при запуске окна выбора фотографий.

Ваше приложение предоставляет средства обработки мультимедиа для средства выбора фотографий. Это происходит при запуске средства выбора фотографий с использованием библиотеки AndroidX Activity путем добавления mediaCapabilities в PickVisualMediaRequest.Builder . Для упрощения этого процесса в PickVisualMediaRequest.Builder добавлен новый API-интерфейс setMediaCapabilitiesForTranscoding(capabilities: MediaCapabilities?) .

Вы можете управлять поведением транскодирования HDR с помощью класса MediaCapabilities . Предоставьте объект MediaCapabilities точно указывающий, какие типы HDR поддерживает ваше приложение (например, TYPE_HLG10 , TYPE_HDR10 , TYPE_HDR10_PLUS , TYPE_DOLBY_VISION ).

Чтобы полностью отключить транскодирование, передайте null для MediaCapabilities . Любой тип HDR , не указанный явно в предоставленных вами возможностях, будет считаться неподдерживаемым. Этот API поддерживается на Android 13 (уровень API 33) и выше и аннотирован @RequiresApi(Build.VERSION_CODES.TIRAMISU) .

import androidx.activity.result.PickVisualMediaRequest
import androidx.activity.result.contract.ActivityResultContracts.PickVisualMedia
import androidx.annotation.RequiresApi
import android.os.Build
import android.util.Log
import android.provider.MediaStore

// Registers a photo picker activity launcher.
val pickMedia = registerForActivityResult(PickVisualMedia()) { uri ->
    // Callback invoked after media selected or picker activity closed.
    if (uri != null) {
        Log.d("photo picker", "Selected URI: $uri")
    } else {
        Log.d("photo picker", "No media selected")
    }
}

@RequiresApi(Build.VERSION_CODES.TIRAMISU)
fun launchPhotoPickerWithTranscodingSupport() {
    val mediaCapabilities = MediaCapabilities.Builder()
        .addSupportedHdrType(MediaCapabilities.HdrType.TYPE_HLG10)
        .build()

    // Launch the photo picker and let the user choose only videos with
    // transcoding enabled.
    pickMedia.launch(PickVisualMediaRequest.Builder()
        .setMediaType(PickVisualMedia.VideoOnly)
        .setMediaCapabilitiesForTranscoding(mediaCapabilities)
        .build())
}

Транскодирование с помощью инструмента выбора фотографий основано как на возможностях приложения в работе с медиафайлами, так и на выбранном видео. Если транскодирование выполнено, возвращается URI транскодированного видео.

Важные моменты, которые следует учитывать при транскодировании HDR.

  • Производительность и хранение: транскодирование требует времени на обработку и создает новый файл, что занимает место на диске.
  • Ограничение по длительности видео: для обеспечения баланса между удобством использования и ограничениями по объему памяти, продолжительность видео ограничена 1 минутой.
  • Управление кэшированными файлами: кэшированные транскодированные файлы периодически очищаются во время простоя и технического обслуживания, чтобы предотвратить чрезмерное использование памяти.
  • Доступность на устройстве: Транскодирование при выборе фотографий поддерживается на Android 13 (уровень API 33) и более поздних версиях .
  • Интеграция AndroidX Activity: Убедитесь, что вы используете версию 1.11.0-alpha01 или более позднюю альфа/бета/RC/стабильную версию библиотеки AndroidX Activity, поскольку она включает необходимый API setMediaCapabilitiesForTranscoding .