Merge "Update ReceiveContentDemo to follow the API docs for URI permissions" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
0eac02491d
@@ -25,6 +25,7 @@ import androidx.appcompat.widget.AppCompatImageView;
|
|||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
final class AttachmentsRecyclerViewAdapter extends
|
final class AttachmentsRecyclerViewAdapter extends
|
||||||
@@ -49,6 +50,10 @@ final class AttachmentsRecyclerViewAdapter extends
|
|||||||
mAttachments.add(uri);
|
mAttachments.add(uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addAttachments(Collection<Uri> uris) {
|
||||||
|
mAttachments.addAll(uris);
|
||||||
|
}
|
||||||
|
|
||||||
public void clearAttachments() {
|
public void clearAttachments() {
|
||||||
mAttachments.clear();
|
mAttachments.clear();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
package com.example.android.receivecontent;
|
package com.example.android.receivecontent;
|
||||||
|
|
||||||
import android.content.ClipData;
|
|
||||||
import android.content.ClipDescription;
|
import android.content.ClipDescription;
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@@ -37,6 +36,8 @@ import com.google.common.util.concurrent.Futures;
|
|||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sample {@link OnReceiveContentListener} implementation that accepts all URIs, and delegates
|
* Sample {@link OnReceiveContentListener} implementation that accepts all URIs, and delegates
|
||||||
@@ -65,13 +66,7 @@ final class MyReceiver implements OnReceiveContentListener {
|
|||||||
ContentInfo uriContent = split.first;
|
ContentInfo uriContent = split.first;
|
||||||
ContentInfo remaining = split.second;
|
ContentInfo remaining = split.second;
|
||||||
if (uriContent != null) {
|
if (uriContent != null) {
|
||||||
ContentResolver contentResolver = view.getContext().getContentResolver();
|
receive(view.getContext(), uriContent);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Return anything that we didn't handle ourselves. This preserves the default platform
|
// 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.
|
// 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
|
* 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
|
* 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.
|
* 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) {
|
private void receive(@NonNull Context context, @NonNull ContentInfo payload) {
|
||||||
Log.i(Logcat.TAG, "Receiving " + mimeType + ": " + uri);
|
Context applicationContext = context.getApplicationContext();
|
||||||
if (ClipDescription.compareMimeTypes(mimeType, "image/*")) {
|
ContentResolver contentResolver = applicationContext.getContentResolver();
|
||||||
createAttachment(uri, mimeType);
|
ListenableFuture<List<Uri>> addAttachmentsFuture = MyExecutors.bg().submit(() -> {
|
||||||
} else {
|
List<Uri> uris = Utils.collectUris(payload.getClip());
|
||||||
showMessage(view, uri, mimeType);
|
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/*")) {
|
||||||
* Reads the image at the given URI and writes it to private storage. Then shows the image in
|
// Read the image at the given URI and write it to private storage.
|
||||||
* the UI by passing the URI pointing to the locally stored copy to the recycler view adapter.
|
localUris.add(mAttachmentsRepo.write(uri));
|
||||||
*/
|
} else {
|
||||||
private void createAttachment(@NonNull Uri uri, @NonNull String mimeType) {
|
showMessage(applicationContext, uri, mimeType);
|
||||||
ListenableFuture<Uri> addAttachmentFuture = MyExecutors.bg().submit(() ->
|
}
|
||||||
mAttachmentsRepo.write(uri)
|
}
|
||||||
);
|
return localUris;
|
||||||
Futures.addCallback(addAttachmentFuture, new FutureCallback<Uri>() {
|
});
|
||||||
|
Futures.addCallback(addAttachmentsFuture, new FutureCallback<List<Uri>>() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(Uri result) {
|
public void onSuccess(List<Uri> localUris) {
|
||||||
mAttachmentsRecyclerViewAdapter.addAttachment(result);
|
// 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();
|
mAttachmentsRecyclerViewAdapter.notifyDataSetChanged();
|
||||||
|
Log.i(Logcat.TAG, "Processed content: " + payload);
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void onFailure(@NonNull Throwable t) {
|
public void onFailure(@NonNull Throwable t) {
|
||||||
Log.e(Logcat.TAG,
|
Log.e(Logcat.TAG,"Error processing content: " + payload, t);
|
||||||
"Error receiving content: uri=" + uri + ", mimeType" + mimeType, t);
|
|
||||||
}
|
}
|
||||||
}, MyExecutors.main());
|
}, 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
|
* Reads the size of the given content URI and shows a toast with the type of the content and
|
||||||
* its size in bytes.
|
* its size in bytes.
|
||||||
*/
|
*/
|
||||||
private void showMessage(@NonNull View view, @NonNull Uri uri, @NonNull String mimeType) {
|
private void showMessage(@NonNull Context applicationContext,
|
||||||
Context applicationContext = view.getContext().getApplicationContext();
|
@NonNull Uri uri, @NonNull String mimeType) {
|
||||||
MyExecutors.bg().execute(() -> {
|
MyExecutors.bg().execute(() -> {
|
||||||
ContentResolver contentResolver = applicationContext.getContentResolver();
|
ContentResolver contentResolver = applicationContext.getContentResolver();
|
||||||
long lengthBytes;
|
long lengthBytes;
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package com.example.android.receivecontent;
|
|||||||
|
|
||||||
import android.content.ClipData;
|
import android.content.ClipData;
|
||||||
import android.content.ClipDescription;
|
import android.content.ClipDescription;
|
||||||
|
import android.net.Uri;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
import android.view.ContentInfo;
|
import android.view.ContentInfo;
|
||||||
|
|
||||||
@@ -71,4 +72,15 @@ final class Utils {
|
|||||||
}
|
}
|
||||||
return clip;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user