Tarik lalu lepas dalam mode multi-aplikasi

Perangkat yang menjalankan Android 7.0 (API level 24) atau yang lebih tinggi mendukung mode multi-aplikasi, yang memungkinkan pengguna memindahkan data dari satu aplikasi ke aplikasi lainnya dengan menarik lalu melepas.

Aplikasi sumber, tempat operasi dimulai, menyediakan data. Aplikasi target, tempat operasi berakhir, menerima data.

Saat pengguna mulai menarik konten, aplikasi sumber harus menetapkan flag DRAG_FLAG_GLOBAL untuk menunjukkan bahwa pengguna dapat menarik data ke aplikasi lain.

Karena data berpindah melintasi batas aplikasi, aplikasi membagikan akses ke data menggunakan URI konten. Hal ini memerlukan hal berikut:

  • Aplikasi sumber harus menetapkan salah satu dari tanda DRAG_FLAG_GLOBAL_URI_READ dan DRAG_FLAG_GLOBAL_URI_WRITE, atau dua-duanya, yang bergantung pada akses baca atau tulis ke data yang ingin diberikan oleh aplikasi sumber ke aplikasi target.
  • Aplikasi target harus segera memanggil requestDragAndDropPermissions() sebelum menangani data yang ditarik pengguna ke dalam aplikasi. Jika aplikasi target tidak lagi memerlukan akses ke data yang ditarik, aplikasi tersebut dapat memanggil release() pada objek yang ditampilkan dari requestDragAndDropPermissions(). Jika tidak, izin akan dirilis saat aktivitas yang memuatnya dihancurkan. Jika implementasi Anda melibatkan memulai Aktivitas baru untuk memproses URI yang dihapus, Anda perlu memberikan izin yang sama kepada Aktivitas baru. Anda harus menetapkan data klip dan tanda:

    Kotlin

    intent.setClipData(clipData)
    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
    

    Java

    intent.setClipData(clipData);
    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    

Cuplikan kode berikut menunjukkan cara merilis akses hanya baca ke data yang ditarik segera setelah operasi lepas pengguna berlangsung. Lihat contoh Drag-And-Drop di GitHub untuk mengetahui contoh yang lebih lengkap.

Aktivitas sumber

Kotlin

// Drag a file stored in an images/ directory in internal storage.
val internalImagesDir = File(context.filesDir, "images")
val imageFile = File(internalImagesDir, imageFilename)
val uri = FileProvider.getUriForFile(context, contentAuthority, imageFile)

val listener = OnDragStartListener@{ view: View, _: DragStartHelper ->
    val clipData = ClipData(ClipDescription("Image Description",
                                            arrayOf("image/*")),
                            ClipData.Item(uri))
    // Must include DRAG_FLAG_GLOBAL to permit dragging data between apps.
    // This example provides read-only access to the data.
    val flags = View.DRAG_FLAG_GLOBAL or View.DRAG_FLAG_GLOBAL_URI_READ
    return@OnDragStartListener view.startDragAndDrop(clipData,
                                                     View.DragShadowBuilder(view),
                                                     null,
                                                     flags)
}

// Container where the image originally appears in the source app.
val srcImageView = findViewById<ImageView>(R.id.imageView)

// Detect and start the drag event.
DragStartHelper(srcImageView, listener).apply {
    attach()
}

Java

// Drag a file stored in an images/ directory in internal storage.
File internalImagesDir = new File(context.getFilesDir(), "images");
File imageFile = new File(internalImagesDir, imageFilename);
final Uri uri = FileProvider.getUriForFile(context, contentAuthority, imageFile);

// Container where the image originally appears in the source app.
ImageView srcImageView = findViewById(R.id.imageView);

// Enable the view to detect and start the drag event.
new DragStartHelper(srcImageView, (view, helper) -> {
    ClipData clipData = new ClipData(new ClipDescription("Image Description",
                                                          new String[] {"image/*"}),
                                     new ClipData.Item(uri));
    // Must include DRAG_FLAG_GLOBAL to permit dragging data between apps.
    // This example provides read-only access to the data.
    int flags = View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_READ;
    return view.startDragAndDrop(clipData,
                                 new View.DragShadowBuilder(view),
                                 null,
                                 flags);
}).attach();

Aktivitas target

Kotlin

// Container where the image is to be dropped in the target app.
val targetImageView = findViewById<ImageView>(R.id.imageView)

targetImageView.setOnDragListener { view, event ->

    when (event.action) {

        ACTION_DROP -> {
            val imageItem: ClipData.Item = event.clipData.getItemAt(0)
            val uri = imageItem.uri

            // Request permission to access the image data being dragged into
            // the target activity's ImageView element.
            val dropPermissions = requestDragAndDropPermissions(event)
            (view as ImageView).setImageURI(uri)

            // Release the permission immediately afterward because it's no
            // longer needed.
            dropPermissions.release()
            return@setOnDragListener true
        }

        // Implement logic for other DragEvent cases here.

        // An unknown action type is received.
        else -> {
            Log.e("DragDrop Example", "Unknown action type received by View.OnDragListener.")
            return@setOnDragListener false
        }

    }
}

Java

// Container where the image is to be dropped in the target app.
ImageView targetImageView = findViewById(R.id.imageView);

targetImageView.setOnDragListener( (view, event) -> {

    switch (event.getAction()) {

        case ACTION_DROP:
            ClipData.Item imageItem = event.getClipData().getItemAt(0);
            Uri uri = imageItem.getUri();

            // Request permission to access the image data being dragged into
            // the target activity's ImageView element.
            DragAndDropPermissions dropPermissions =
                requestDragAndDropPermissions(event);

            ((ImageView)view).setImageURI(uri);

            // Release the permission immediately afterward because it's no
            // longer needed.
            dropPermissions.release();

            return true;

        // Implement logic for other DragEvent cases here.

        // An unknown action type was received.
        default:
            Log.e("DragDrop Example","Unknown action type received by View.OnDragListener.");
            break;
    }

    return false;
});