Tarik lalu lepas pada mode multi-aplikasi

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

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

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

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

  • Aplikasi sumber harus menetapkan salah satu atau kedua DRAG_FLAG_GLOBAL_URI_READ dan DRAG_FLAG_GLOBAL_URI_WRITE yang bergantung pada akses baca atau tulis ke data yang diberikan aplikasi sumber yang ingin diberikan ke aplikasi target.
  • Aplikasi target harus memanggil requestDragAndDropPermissions() tepat sebelum menangani data yang ditarik pengguna ke dalam aplikasi. Jika aplikasi target tidak lagi membutuhkan akses ke data yang ditarik, aplikasi dapat lalu panggil release() aktif objek yang ditampilkan dari requestDragAndDropPermissions(). Jika tidak, izin akan dirilis saat aktivitas yang memuatnya dihancurkan. Jika penerapan Anda melibatkan dimulainya Aktivitas baru untuk memproses menghapus URI, Anda harus memberikan izin yang sama kepada Aktivitas baru. Anda harus menyetel 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 terjadi. Lihat Demo Tarik lalu Lepas di GitHub untuk 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;
});