Получайте богатый контент

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

Пользователи любят изображения, видео и другой выразительный контент, но вставка и перемещение этого контента в приложениях не всегда просты. Чтобы упростить приложениям получение расширенного контента, Android 12 (уровень API 31) представляет унифицированный API, который позволяет вашему приложению принимать контент из любого источника: буфера обмена, клавиатуры или путем перетаскивания.

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

Для обеспечения обратной совместимости с предыдущими версиями Android этот API также доступен в AndroidX, начиная с Core 1.7 и Appcompat 1.4 , которые мы рекомендуем использовать при реализации этой функциональности.

Обзор

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

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

API OnReceiveContentListener объединяет эти различные пути выполнения кода, создавая единый API для реализации, позволяя вам сосредоточиться на логике, специфичной для вашего приложения, а платформа позаботится обо всем остальном:

Изображение, демонстрирующее упрощенный унифицированный API.
Рисунок 3. Унифицированный API позволяет реализовать единый API, поддерживающий все механизмы пользовательского интерфейса.

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

Выполнение

API представляет собой интерфейс слушателя с единственным методом, OnReceiveContentListener . Для поддержки более старых версий платформы Android мы рекомендуем использовать соответствующий интерфейс OnReceiveContentListener из библиотеки AndroidX Core.

Для использования API необходимо реализовать обработчик событий, указав, какие типы контента может обрабатывать ваше приложение:

Котлин

object MyReceiver : OnReceiveContentListener {
    val MIME_TYPES = arrayOf("image/*", "video/*")
    
    // ...
    
    override fun onReceiveContent(view: View, payload: ContentInfoCompat): ContentInfoCompat? {
        TODO("Not yet implemented")
    }
}

Java

public class MyReceiver implements OnReceiveContentListener {
     public static final String[] MIME_TYPES = new String[] {"image/*", "video/*"};
     // ...
}

После указания всех MIME-типов контента, поддерживаемых вашим приложением, реализуйте остальную часть обработчика событий:

Котлин

class MyReceiver : OnReceiveContentListener {
    override fun onReceiveContent(view: View, contentInfo: ContentInfoCompat): ContentInfoCompat {
        val split = contentInfo.partition { item: ClipData.Item -> item.uri != null }
        val uriContent = split.first
        val remaining = split.second
        if (uriContent != null) {
            // App-specific logic to handle the URI(s) in uriContent.
        }
        // Return anything that your app didn't handle. This preserves the
        // default platform behavior for text and anything else that you aren't
        // implementing custom handling for.
        return remaining
    }

    companion object {
        val MIME_TYPES = arrayOf("image/*", "video/*")
    }
}

Java

 public class MyReceiver implements OnReceiveContentListener {
     public static final String[] MIME_TYPES = new String[] {"image/*", "video/*"};

     @Override
     public ContentInfoCompat onReceiveContent(View view, ContentInfoCompat contentInfo) {
         Pair<ContentInfoCompat, ContentInfoCompat> split = contentInfo.partition(
                 item -> item.getUri() != null);
         ContentInfo uriContent = split.first;
         ContentInfo remaining = split.second;
         if (uriContent != null) {
             // App-specific logic to handle the URI(s) in uriContent.
         }
         // Return anything that your app didn't handle. This preserves the
         // default platform behavior for text and anything else that you aren't
         // implementing custom handling for.
         return remaining;
     }
 }

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

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

Котлин

class MyActivity : Activity() {
    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // ...
        val myInput = findViewById(R.id.my_input)
        ViewCompat.setOnReceiveContentListener(myInput, MyReceiver.MIME_TYPES, MyReceiver())
    }
}

Java

public class MyActivity extends Activity {
     @Override
     public void onCreate(Bundle savedInstanceState) {
         // ...

         AppCompatEditText myInput = findViewById(R.id.my_input);
         ViewCompat.setOnReceiveContentListener(myInput, MyReceiver.MIME_TYPES, new MyReceiver());
     }
}

Разрешения URI

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

Обычно ваше приложение обрабатывает URI контента в службе или активности. Для длительной обработки используйте WorkManager . При реализации этого механизма расширьте права доступа к целевой службе или активности, передав контент с помощью Intent.setClipData и установив флаг FLAG_GRANT_READ_URI_PERMISSION .

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

Пользовательские виды

Если ваше приложение использует собственный подкласс View , убедитесь, что обработчик OnReceiveContentListener не пропускается.

Если ваш класс View переопределяет метод onCreateInputConnection , используйте метод InputConnectionCompat.createWrapper из API Jetpack для настройки InputConnection .

Если ваш класс View переопределяет метод onTextContextMenuItem , делегируйте вызов методу super, когда пункт меню имеет R.id.paste или R.id.pasteAsPlainText .

Сравнение с API обработки изображений клавиатуры.

API OnReceiveContentListener можно рассматривать как следующую версию существующего API для отображения изображений на клавиатуре . Этот унифицированный API поддерживает функциональность API для отображения изображений на клавиатуре, а также некоторые дополнительные возможности. Совместимость с устройствами и функциями зависит от того, используете ли вы библиотеку Jetpack или нативные API из Android SDK.

Таблица 1. Поддерживаемые функции и уровни API для Jetpack.
Действие или функция Поддерживается API изображений клавиатуры Поддерживается унифицированным API.
Вставить с клавиатуры Да (уровень API 13 и выше) Да (уровень API 13 и выше)
Вставить с помощью функции «Вставить» из меню «Нажмите и удерживайте». Нет Да
Вставка с помощью перетаскивания. Нет Да (уровень API 24 и выше)
Таблица 2. Поддерживаемые функции и уровни API для собственных API.
Действие или функция Поддерживается API изображений клавиатуры Поддерживается унифицированным API.
Вставить с клавиатуры Да (уровень API 25 и выше) Да (Android 12 и выше)
Вставить с помощью функции «Вставить» из меню «Нажмите и удерживайте». Нет
Вставка с помощью перетаскивания. Нет