Merge "Use openPipeHelper() for streaming IconsContentProvider data." into rvc-dev am: 100ae78d72
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/12000566 Change-Id: Icddb0e7bb1d58cd9e4ff788817accc76c635427e
This commit is contained in:
@@ -27,6 +27,7 @@ import android.os.ParcelFileDescriptor;
|
|||||||
import android.os.ParcelFileDescriptor.AutoCloseOutputStream;
|
import android.os.ParcelFileDescriptor.AutoCloseOutputStream;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.util.Pair;
|
||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.server.textclassifier.IconsUriHelper.ResourceInfo;
|
import com.android.server.textclassifier.IconsUriHelper.ResourceInfo;
|
||||||
@@ -34,6 +35,7 @@ import com.android.server.textclassifier.IconsUriHelper.ResourceInfo;
|
|||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A content provider that is used to access icons returned from the TextClassifier service.
|
* A content provider that is used to access icons returned from the TextClassifier service.
|
||||||
@@ -46,32 +48,40 @@ import java.io.OutputStream;
|
|||||||
public final class IconsContentProvider extends ContentProvider {
|
public final class IconsContentProvider extends ContentProvider {
|
||||||
|
|
||||||
private static final String TAG = "IconsContentProvider";
|
private static final String TAG = "IconsContentProvider";
|
||||||
|
private static final String MIME_TYPE = "image/png";
|
||||||
|
|
||||||
|
private final PipeDataWriter<Pair<ResourceInfo, Integer>> mWriter =
|
||||||
|
(writeSide, uri, mimeType, bundle, args) -> {
|
||||||
|
try (OutputStream out = new AutoCloseOutputStream(writeSide)) {
|
||||||
|
final ResourceInfo res = args.first;
|
||||||
|
final int userId = args.second;
|
||||||
|
final Drawable drawable = Icon.createWithResource(res.packageName, res.id)
|
||||||
|
.loadDrawableAsUser(getContext(), userId);
|
||||||
|
getBitmap(drawable).compress(Bitmap.CompressFormat.PNG, 100, out);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "Error retrieving icon for uri: " + uri, e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ParcelFileDescriptor openFile(Uri uri, String mode) {
|
public ParcelFileDescriptor openFile(Uri uri, String mode) {
|
||||||
try {
|
final ResourceInfo res = IconsUriHelper.getInstance().getResourceInfo(uri);
|
||||||
final ResourceInfo res = IconsUriHelper.getInstance().getResourceInfo(uri);
|
if (res == null) {
|
||||||
final Drawable drawable = Icon.createWithResource(res.packageName, res.id)
|
Log.e(TAG, "No icon found for uri: " + uri);
|
||||||
.loadDrawableAsUser(getContext(), UserHandle.getCallingUserId());
|
return null;
|
||||||
final byte[] data = getBitmapData(drawable);
|
|
||||||
final ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
|
|
||||||
final ParcelFileDescriptor readSide = pipe[0];
|
|
||||||
final ParcelFileDescriptor writeSide = pipe[1];
|
|
||||||
try (OutputStream out = new AutoCloseOutputStream(writeSide)) {
|
|
||||||
out.write(data);
|
|
||||||
return readSide;
|
|
||||||
}
|
|
||||||
} catch (IOException | RuntimeException e) {
|
|
||||||
Log.e(TAG, "Error retrieving icon for uri: " + uri, e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
final Pair<ResourceInfo, Integer> args = new Pair(res, UserHandle.getCallingUserId());
|
||||||
|
return openPipeHelper(uri, MIME_TYPE, /* bundle= */ null, args, mWriter);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "Error opening pipe helper for icon at uri: " + uri, e);
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private static Bitmap getBitmap(Drawable drawable) {
|
||||||
* Returns the bitmap data for the specified drawable.
|
|
||||||
*/
|
|
||||||
@VisibleForTesting
|
|
||||||
public static byte[] getBitmapData(Drawable drawable) {
|
|
||||||
if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
|
if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
|
||||||
throw new IllegalStateException("The icon is zero-sized");
|
throw new IllegalStateException("The icon is zero-sized");
|
||||||
}
|
}
|
||||||
@@ -85,16 +95,24 @@ public final class IconsContentProvider extends ContentProvider {
|
|||||||
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
|
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
|
||||||
drawable.draw(canvas);
|
drawable.draw(canvas);
|
||||||
|
|
||||||
final ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
return bitmap;
|
||||||
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
|
}
|
||||||
final byte[] byteArray = stream.toByteArray();
|
|
||||||
bitmap.recycle();
|
/**
|
||||||
return byteArray;
|
* Returns true if the drawables are considered the same.
|
||||||
|
*/
|
||||||
|
@VisibleForTesting
|
||||||
|
public static boolean sameIcon(Drawable one, Drawable two) {
|
||||||
|
final ByteArrayOutputStream stream1 = new ByteArrayOutputStream();
|
||||||
|
getBitmap(one).compress(Bitmap.CompressFormat.PNG, 100, stream1);
|
||||||
|
final ByteArrayOutputStream stream2 = new ByteArrayOutputStream();
|
||||||
|
getBitmap(two).compress(Bitmap.CompressFormat.PNG, 100, stream2);
|
||||||
|
return Arrays.equals(stream1.toByteArray(), stream2.toByteArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getType(Uri uri) {
|
public String getType(Uri uri) {
|
||||||
return "image/png";
|
return MIME_TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -50,8 +50,7 @@ public final class IconsContentProviderTest {
|
|||||||
|
|
||||||
final Drawable actual = Icon.createWithContentUri(uri).loadDrawable(context);
|
final Drawable actual = Icon.createWithContentUri(uri).loadDrawable(context);
|
||||||
assertThat(actual).isNotNull();
|
assertThat(actual).isNotNull();
|
||||||
assertThat(IconsContentProvider.getBitmapData(actual))
|
assertThat(IconsContentProvider.sameIcon(actual, expected)).isTrue();
|
||||||
.isEqualTo(IconsContentProvider.getBitmapData(expected));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
Reference in New Issue
Block a user