summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Dubrovsky <dubrovsky@google.com>2021-05-22 05:06:06 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2021-05-22 05:06:06 +0000
commit0eac02491d87bfaa53c004d6dfc32063e14e9562 (patch)
tree0332108f03c2b5eeb4c345d0d3ed44c36cf93adf
parenta9018531f6cc4835f58d665054f2c24868b11c61 (diff)
parent522bfd9e7976f0288ef893b3c80ac02d9a75b329 (diff)
downloaddevelopment-0eac02491d87bfaa53c004d6dfc32063e14e9562.tar.gz
Merge "Update ReceiveContentDemo to follow the API docs for URI permissions" into sc-dev
-rw-r--r--samples/ReceiveContentDemo/src/com/example/android/receivecontent/AttachmentsRecyclerViewAdapter.java5
-rw-r--r--samples/ReceiveContentDemo/src/com/example/android/receivecontent/MyReceiver.java68
-rw-r--r--samples/ReceiveContentDemo/src/com/example/android/receivecontent/Utils.java12
3 files changed, 53 insertions, 32 deletions
diff --git a/samples/ReceiveContentDemo/src/com/example/android/receivecontent/AttachmentsRecyclerViewAdapter.java b/samples/ReceiveContentDemo/src/com/example/android/receivecontent/AttachmentsRecyclerViewAdapter.java
index cfdf32d6d..9e25d0fe0 100644
--- a/samples/ReceiveContentDemo/src/com/example/android/receivecontent/AttachmentsRecyclerViewAdapter.java
+++ b/samples/ReceiveContentDemo/src/com/example/android/receivecontent/AttachmentsRecyclerViewAdapter.java
@@ -25,6 +25,7 @@ import androidx.appcompat.widget.AppCompatImageView;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
final class AttachmentsRecyclerViewAdapter extends
@@ -49,6 +50,10 @@ final class AttachmentsRecyclerViewAdapter extends
mAttachments.add(uri);
}
+ public void addAttachments(Collection<Uri> uris) {
+ mAttachments.addAll(uris);
+ }
+
public void clearAttachments() {
mAttachments.clear();
}
diff --git a/samples/ReceiveContentDemo/src/com/example/android/receivecontent/MyReceiver.java b/samples/ReceiveContentDemo/src/com/example/android/receivecontent/MyReceiver.java
index bb180e6cc..37612eeb1 100644
--- a/samples/ReceiveContentDemo/src/com/example/android/receivecontent/MyReceiver.java
+++ b/samples/ReceiveContentDemo/src/com/example/android/receivecontent/MyReceiver.java
@@ -16,7 +16,6 @@
package com.example.android.receivecontent;
-import android.content.ClipData;
import android.content.ClipDescription;
import android.content.ContentResolver;
import android.content.Context;
@@ -37,6 +36,8 @@ import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.List;
/**
* Sample {@link OnReceiveContentListener} implementation that accepts all URIs, and delegates
@@ -65,13 +66,7 @@ final class MyReceiver implements OnReceiveContentListener {
ContentInfo uriContent = split.first;
ContentInfo remaining = split.second;
if (uriContent != null) {
- ContentResolver contentResolver = view.getContext().getContentResolver();
- ClipData clip = uriContent.getClip();
- for (int i = 0; i < clip.getItemCount(); i++) {
- Uri uri = clip.getItemAt(i).getUri();
- String mimeType = contentResolver.getType(uri);
- receive(view, uri, mimeType);
- }
+ receive(view.getContext(), uriContent);
}
// Return anything that we didn't handle ourselves. This preserves the default platform
// behavior for text and anything else for which we are not implementing custom handling.
@@ -82,34 +77,43 @@ final class MyReceiver implements OnReceiveContentListener {
* Handles incoming content URIs. If the content is an image, stores it as an attachment in the
* app's private storage. If the content is any other type, simply shows a toast with the type
* of the content and its size in bytes.
+ *
+ * <p><strong>Important:</strong> It is significant that we pass along the {@code payload}
+ * object to the worker thread that will process the content, because URI permissions are tied
+ * to the payload object's lifecycle. If that object is not passed along, it could be garbage
+ * collected and permissions would be revoked prematurely (before we have a chance to process
+ * the content).
*/
- private void receive(@NonNull View view, @NonNull Uri uri, @NonNull String mimeType) {
- Log.i(Logcat.TAG, "Receiving " + mimeType + ": " + uri);
- if (ClipDescription.compareMimeTypes(mimeType, "image/*")) {
- createAttachment(uri, mimeType);
- } else {
- showMessage(view, uri, mimeType);
- }
- }
-
- /**
- * Reads the image at the given URI and writes it to private storage. Then shows the image in
- * the UI by passing the URI pointing to the locally stored copy to the recycler view adapter.
- */
- private void createAttachment(@NonNull Uri uri, @NonNull String mimeType) {
- ListenableFuture<Uri> addAttachmentFuture = MyExecutors.bg().submit(() ->
- mAttachmentsRepo.write(uri)
- );
- Futures.addCallback(addAttachmentFuture, new FutureCallback<Uri>() {
+ private void receive(@NonNull Context context, @NonNull ContentInfo payload) {
+ Context applicationContext = context.getApplicationContext();
+ ContentResolver contentResolver = applicationContext.getContentResolver();
+ ListenableFuture<List<Uri>> addAttachmentsFuture = MyExecutors.bg().submit(() -> {
+ List<Uri> uris = Utils.collectUris(payload.getClip());
+ List<Uri> localUris = new ArrayList<>(uris.size());
+ for (Uri uri : uris) {
+ String mimeType = contentResolver.getType(uri);
+ Log.i(Logcat.TAG, "Processing " + mimeType + ": " + uri);
+ if (ClipDescription.compareMimeTypes(mimeType, "image/*")) {
+ // Read the image at the given URI and write it to private storage.
+ localUris.add(mAttachmentsRepo.write(uri));
+ } else {
+ showMessage(applicationContext, uri, mimeType);
+ }
+ }
+ return localUris;
+ });
+ Futures.addCallback(addAttachmentsFuture, new FutureCallback<List<Uri>>() {
@Override
- public void onSuccess(Uri result) {
- mAttachmentsRecyclerViewAdapter.addAttachment(result);
+ public void onSuccess(List<Uri> localUris) {
+ // Show the image in the UI by passing the URI pointing to the locally stored copy
+ // to the recycler view adapter.
+ mAttachmentsRecyclerViewAdapter.addAttachments(localUris);
mAttachmentsRecyclerViewAdapter.notifyDataSetChanged();
+ Log.i(Logcat.TAG, "Processed content: " + payload);
}
@Override
public void onFailure(@NonNull Throwable t) {
- Log.e(Logcat.TAG,
- "Error receiving content: uri=" + uri + ", mimeType" + mimeType, t);
+ Log.e(Logcat.TAG,"Error processing content: " + payload, t);
}
}, MyExecutors.main());
}
@@ -118,8 +122,8 @@ final class MyReceiver implements OnReceiveContentListener {
* Reads the size of the given content URI and shows a toast with the type of the content and
* its size in bytes.
*/
- private void showMessage(@NonNull View view, @NonNull Uri uri, @NonNull String mimeType) {
- Context applicationContext = view.getContext().getApplicationContext();
+ private void showMessage(@NonNull Context applicationContext,
+ @NonNull Uri uri, @NonNull String mimeType) {
MyExecutors.bg().execute(() -> {
ContentResolver contentResolver = applicationContext.getContentResolver();
long lengthBytes;
diff --git a/samples/ReceiveContentDemo/src/com/example/android/receivecontent/Utils.java b/samples/ReceiveContentDemo/src/com/example/android/receivecontent/Utils.java
index 5e43f7f60..39662289c 100644
--- a/samples/ReceiveContentDemo/src/com/example/android/receivecontent/Utils.java
+++ b/samples/ReceiveContentDemo/src/com/example/android/receivecontent/Utils.java
@@ -18,6 +18,7 @@ package com.example.android.receivecontent;
import android.content.ClipData;
import android.content.ClipDescription;
+import android.net.Uri;
import android.util.Pair;
import android.view.ContentInfo;
@@ -71,4 +72,15 @@ final class Utils {
}
return clip;
}
+
+ public static List<Uri> collectUris(ClipData clip) {
+ List<Uri> uris = new ArrayList<>(clip.getItemCount());
+ for (int i = 0; i < clip.getItemCount(); i++) {
+ Uri uri = clip.getItemAt(i).getUri();
+ if (uri != null) {
+ uris.add(uri);
+ }
+ }
+ return uris;
+ }
}