Rich content insertion

Figure 1. The unified API provides a single place to handle incoming content regardless of the specific UI mechanism, such as pasting from the long-press menu or using drag-and-drop.

Users love images, videos, and other expressive content, but inserting and moving this content in apps is not always easy. To make it simple for your apps to receive rich content, we’re introducing a new unified API that lets you accept content from any source: clipboard, keyboard, or drag and drop.

You can attach a new interface, OnReceiveContentListener, to UI components and get a callback when content is inserted through any mechanism. The callback becomes the single place for your code to handle receiving all content, from plain and styled text to markup, images, videos, audio files, and others.

For backward compatibility with previous Android versions, we’ve also added the new API to AndroidX (available in Core 1.5.0-beta1 and Appcompat 1.3.0-beta-01), which we recommend you use when implementing this feature.

Overview

With the existing APIs, each UI mechanism—such as the long-press menu or drag and drop—has its own corresponding API. This means that you have to integrate with each API separately, adding similar code for each mechanism that inserts content:

Figure 2. Previously your app would need to implement a different API for each UI mechanism for inserting content.

The unified API consolidates these different code paths by creating a single API to implement, so you can focus on your app-specific logic and let the platform handle the rest:

Figure 3. The new unified API lets you implement a single API that supports all UI mechanisms.

This approach also means that when new ways of inserting content are added to the platform, you don't need to make additional code changes to enable support in your app. If your app needs to implement full customization for a particular use case, you can still use the existing APIs, which will continue to work the same way.

Implementation

The new API is a listener interface with a single method, OnReceiveContentListener. To support older versions of the Android platform, we recommend using the matching OnReceiveContentListener interface in the AndroidX Core library.

To use the API, start implementing the listener by specifying what types of content your app can handle:

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

After specifying all the content MIME types that your app supports, implement the rest of the listener:

 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) {
             ClipData clip = uriContent.getClip();
             for (int i = 0; i < clip.getItemCount(); i++) {
                 Uri uri = clip.getItemAt(i).getUri();
                 // App-specific logic to handle the URI ...
             }
         }
         // 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;
     }
 }

If your app already supports sharing with Intents, you can reuse your app-specific logic for handling content URIs. Return any remaining data to delegate handling of that data to the platform.

After implementing your listener, set the listener in the constructor of your app's UI element:

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());
     }
}

Comparison with the keyboard image API

You can think of the unified content API as the next version of the existing keyboard image API. The new API supports the functionality of the keyboard image API as well as some additional features:

Action or feature Supported by keyboard image API Supported by unified API
Insert from the keyboard Yes (API level 24 and higher) Yes (API level 24 and higher)
Insert using Paste from long-press menu No Yes
Insert using drag and drop No Yes (API level 24 and higher)