Some polish for DragAndDropAcrossApp sample

1. Do not re-create an image file if it already exists.
(this prevents a nasty race when DropTarget will try to read
a partially written file when restoring the image on
an activity resize).

2. Do not use ClipDescription.MIMETYPE_TEXT_URILIST
with a "content" scheme URI, use the actual MIME type
instead (this is what JavaDoc explicitly requires).

3. Do not call requestDragAndDrop permissions if
a dropped content is not a "content" scheme URI.

4. Add a checkbox to control permissions release explicitly.
Without it the image restore behavior is confusing.

5. Remove mention of "text" from the explanatory message.

Change-Id: Iedd1306687286d051a3a1b768f95c800fb3d5cd4
diff --git a/ui/window/DragAndDropAcrossApps/DragSource/src/main/java/com/example/android/dragsource/DragSourceFragment.java b/ui/window/DragAndDropAcrossApps/DragSource/src/main/java/com/example/android/dragsource/DragSourceFragment.java
index a9cd7c4..5b92fc9 100644
--- a/ui/window/DragAndDropAcrossApps/DragSource/src/main/java/com/example/android/dragsource/DragSourceFragment.java
+++ b/ui/window/DragAndDropAcrossApps/DragSource/src/main/java/com/example/android/dragsource/DragSourceFragment.java
@@ -158,7 +158,7 @@
                 // Add an optional clip description that that contains an extra String that is
                 // read out by the target app.
                 final ClipDescription clipDescription = new ClipDescription("", new String[]{
-                        ClipDescription.MIMETYPE_TEXT_URILIST});
+                        getContext().getContentResolver().getType(imageUri)});
                 // Extras are stored within a PersistableBundle.
                 PersistableBundle extras = new PersistableBundle(1);
                 // Add a String that the target app will display.
@@ -202,7 +202,9 @@
 
         // Copy a drawable from resources to the internal directory.
         File newFile = new File(filePath, targetName);
-        copyImageResourceToFile(sourceResourceId, newFile);
+        if (!newFile.exists()) {
+            copyImageResourceToFile(sourceResourceId, newFile);
+        }
 
         // Make the file accessible via the FileProvider and retrieve its URI.
         return FileProvider.getUriForFile(getContext(), CONTENT_AUTHORITY, newFile);
diff --git a/ui/window/DragAndDropAcrossApps/DropTarget/src/main/java/com/example/android/droptarget/DropTargetFragment.java b/ui/window/DragAndDropAcrossApps/DropTarget/src/main/java/com/example/android/droptarget/DropTargetFragment.java
index 4b1cdb1..9705e2b 100644
--- a/ui/window/DragAndDropAcrossApps/DropTarget/src/main/java/com/example/android/droptarget/DropTargetFragment.java
+++ b/ui/window/DragAndDropAcrossApps/DropTarget/src/main/java/com/example/android/droptarget/DropTargetFragment.java
@@ -20,6 +20,7 @@
 
 import android.app.Activity;
 import android.content.ClipDescription;
+import android.content.ContentResolver;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.PersistableBundle;
@@ -31,6 +32,7 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.CheckBox;
 import android.widget.ImageView;
 
 /**
@@ -58,6 +60,8 @@
 
     private Uri mImageUri;
 
+    private CheckBox mReleasePermissionCheckBox;
+
     @Nullable
     @Override
     public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@@ -79,6 +83,8 @@
             }
         }
 
+        mReleasePermissionCheckBox = (CheckBox) rootView.findViewById(R.id.release_checkbox);
+
         return rootView;
     }
 
@@ -102,35 +108,52 @@
             // Read the string from the clip description extras.
             Log.d(TAG, "ClipDescription extra: " + getExtra(event));
 
-            // Request permissions to access the uri that was dropped.
             Log.d(TAG, "Setting image source to: " + uri.toString());
             mImageUri = uri;
-            DragAndDropPermissionsCompat dropPermissions = ActivityCompat
-                    .requestDragAndDropPermissions(getActivity(), event);
-            Log.d(TAG, "Requesting permissions.");
 
-            if (dropPermissions == null) {
-                // Permission could not be obtained.
-                Log.d(TAG, "Drop permission request failed.");
-                return false;
+            if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
+                // Accessing a "content" scheme Uri requires a permission grant.
+                DragAndDropPermissionsCompat dropPermissions = ActivityCompat
+                        .requestDragAndDropPermissions(getActivity(), event);
+                Log.d(TAG, "Requesting permissions.");
+
+                if (dropPermissions == null) {
+                    // Permission could not be obtained.
+                    Log.d(TAG, "Drop permission request failed.");
+                    return false;
+                }
+
+                final boolean result = super.setImageUri(view, event, uri);
+
+                if (mReleasePermissionCheckBox.isChecked()) {
+                    /* Release the permissions if you are done with the URI.
+                     Note that you may need to hold onto the permission until later if other
+                     operations are performed on the content. For instance, releasing the
+                     permissions here will prevent onCreateView from properly restoring the
+                     ImageView state.
+                     If permissions are not explicitly released, the permission grant will be
+                     revoked when the activity is destroyed.
+                     */
+                    dropPermissions.release();
+                    Log.d(TAG, "Permissions released.");
+                }
+
+                return result;
+            } else {
+                // Other schemes (such as "android.resource") do not require a permission grant.
+                return super.setImageUri(view, event, uri);
             }
-
-            ((ImageView) view).setImageURI(uri);
-
-            /* Release the permissions now that we are done with the URI. Note that you may
-             need to hold onto the permission until later if other operations are performed on the
-             content.
-             If permissions are not explicitly released, the permission grant will be revoked when
-             the activity is destroyed.
-             */
-            dropPermissions.release();
-            Log.d(TAG, "Permissions released.");
-
-            return super.setImageUri(view, event, uri);
         }
 
         @Override
         public boolean onDrag(View view, DragEvent event) {
+            // DragTarget is peeking into the MIME types of the dragged event in order to ignore
+            // non-image drags completely.
+            // DragSource does not do that but rejects non-image content once a drop has happened.
+            ClipDescription clipDescription = event.getClipDescription();
+            if (clipDescription != null && !clipDescription.hasMimeType("image/*")) {
+                return false;
+            }
             // Callback received when image is being dragged.
             return super.onDrag(view, event);
         }
diff --git a/ui/window/DragAndDropAcrossApps/DropTarget/src/main/res/layout/fragment_droptarget.xml b/ui/window/DragAndDropAcrossApps/DropTarget/src/main/res/layout/fragment_droptarget.xml
index 328247d..6721171 100644
--- a/ui/window/DragAndDropAcrossApps/DropTarget/src/main/res/layout/fragment_droptarget.xml
+++ b/ui/window/DragAndDropAcrossApps/DropTarget/src/main/res/layout/fragment_droptarget.xml
@@ -36,11 +36,28 @@
             android:pointerIcon="crosshair"
             android:scaleType="centerCrop" />
 
-        <TextView
-            android:layout_width="match_parent"
+        <LinearLayout
+            android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_margin="@dimen/text_margin"
-            android:text="@string/image_target_prompt" />
-
+            android:layout_margin="@dimen/section_margin"
+            android:gravity="center"
+            android:orientation="vertical">
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_margin="@dimen/text_margin"
+                android:text="@string/image_target_prompt" />
+            <CheckBox
+                android:id="@+id/release_checkbox"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/release_checkbox_text"/>
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="@dimen/text_margin"
+                android:layout_marginRight="@dimen/text_margin"
+                android:text="@string/release_checkbox_note" />
+        </LinearLayout>
     </LinearLayout>
 </ScrollView>
\ No newline at end of file
diff --git a/ui/window/DragAndDropAcrossApps/DropTarget/src/main/res/values/strings.xml b/ui/window/DragAndDropAcrossApps/DropTarget/src/main/res/values/strings.xml
index 5fb290c..585a789 100644
--- a/ui/window/DragAndDropAcrossApps/DropTarget/src/main/res/values/strings.xml
+++ b/ui/window/DragAndDropAcrossApps/DropTarget/src/main/res/values/strings.xml
@@ -20,5 +20,9 @@
 
     <string name="image_target_prompt">Drop image here.\nThe app will request permission from the source app before displaying the image.</string>
 
-    <string name="intro_message">This sample demonstrates drag and drop functionality and is the \'target\' app for this sample. It shows how data can be received when dragged from another app.\nOpen the \'DragSource\' sample app next to this one and try dragging an image or text into the space below.</string>
+    <string name="intro_message">This sample demonstrates drag and drop functionality and is the \'target\' app for this sample. It shows how data can be received when dragged from another app.\nOpen the \'DragSource\' sample app next to this one and try dragging an image into the space below.</string>
+
+    <string name="release_checkbox_text">Release permissions immediately after a drop</string>
+
+    <string name="release_checkbox_note">Releasing permissions will prevent the image from being properly restored after the activity has been resized.</string>
 </resources>