Android 7.0 (API 수준 24) 이상을 실행하는 기기에서는 사용자가 드래그 앤 드롭을 통해 한 앱에서 다른 앱으로 데이터를 이동할 수 있는 멀티 윈도우 모드를 지원합니다.
작업이 시작되는 소스 앱에서 데이터를 제공합니다. 작업이 종료되는 타겟 앱에서 데이터를 수신합니다.
사용자가 콘텐츠를 드래그하기 시작하면 소스 앱은 DRAG_FLAG_GLOBAL
플래그를 설정하여 사용자가 데이터를 다른 앱으로 드래그할 수 있음을 나타내야 합니다.
데이터는 앱 경계를 넘어 이동하므로 앱은 콘텐츠 URI를 사용하여 데이터 액세스를 공유합니다. 이를 위해서는 다음이 필요합니다.
- 소스 앱은 소스 앱이 타겟 앱에 부여하려는 데이터에 관한 읽기 또는 쓰기 액세스 권한에 따라
DRAG_FLAG_GLOBAL_URI_READ
플래그와DRAG_FLAG_GLOBAL_URI_WRITE
플래그 중 하나 또는 둘 다를 설정해야 합니다. - 타겟 앱은 사용자가 앱으로 드래그하는 데이터를 처리하기 직전에
requestDragAndDropPermissions()
를 호출해야 합니다. 타겟 앱이 더 이상 드래그된 데이터에 액세스할 필요가 없다면 앱은requestDragAndDropPermissions()
에서 반환된 객체에서release()
를 호출할 수 있습니다. 그렇게 하지 않으면 포함하는 활동이 소멸될 때 권한이 해제됩니다. 구현 시 삭제된 URI를 처리하기 위해 새 활동을 시작하는 경우 새 활동에 동일한 권한을 부여해야 합니다. 클립 데이터와 플래그를 설정해야 합니다.Kotlin
intent.setClipData(clipData) intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
Java
intent.setClipData(clipData); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
다음 코드 스니펫은 사용자 드롭 작업이 실행된 직후 드래그된 데이터에 대한 읽기 전용 액세스 권한을 해제하는 방법을 보여줍니다. 전체 예는 GitHub의 드래그 앤 드롭 데모를 참고하세요.
소스 활동
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();
목표 활동
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; });