Use ImageDecoder in ImageView.getDrawableFromUri

Bug: 63909536
Test: Existing CTS tests

ImageDecoder will bypass the InputStream if possible, allowing it to be
more efficient. In addition, it handles density scaling differently;
instead of using more RAM to scale the image up, it results in scaling
at draw time.

Change-Id: Ied7c0865a736f9ef0de367299264e18ccc3e0b92
This commit is contained in:
Leon Scroggins III
2018-01-31 14:59:29 -05:00
parent ce9bcc4977
commit 046a99ebbb
2 changed files with 29 additions and 17 deletions

View File

@@ -23,10 +23,12 @@ import android.annotation.TestApi;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.ImageDecoder;
import android.graphics.Matrix;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
@@ -53,7 +55,6 @@ import android.widget.RemoteViews.RemoteView;
import com.android.internal.R;
import java.io.IOException;
import java.io.InputStream;
/**
* Displays image resources, for example {@link android.graphics.Bitmap}
@@ -946,21 +947,15 @@ public class ImageView extends View {
}
} else if (ContentResolver.SCHEME_CONTENT.equals(scheme)
|| ContentResolver.SCHEME_FILE.equals(scheme)) {
InputStream stream = null;
try {
stream = mContext.getContentResolver().openInputStream(uri);
return Drawable.createFromResourceStream(sCompatUseCorrectStreamDensity
? getResources() : null, null, stream, null);
} catch (Exception e) {
Resources res = sCompatUseCorrectStreamDensity ? getResources() : null;
ImageDecoder.Source src = ImageDecoder.createSource(mContext.getContentResolver(),
uri, res);
return ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
});
} catch (IOException e) {
Log.w(LOG_TAG, "Unable to open content: " + uri, e);
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
Log.w(LOG_TAG, "Unable to close content: " + uri, e);
}
}
}
} else {
return Drawable.createFromPath(uri.toString());

View File

@@ -74,7 +74,7 @@ public final class ImageDecoder implements AutoCloseable {
int getDensity() { return Bitmap.DENSITY_NONE; }
/* @hide */
int computeDstDensity() {
final int computeDstDensity() {
Resources res = getResources();
if (res == null) {
return Bitmap.getDefaultDensity();
@@ -122,13 +122,19 @@ public final class ImageDecoder implements AutoCloseable {
}
private static class ContentResolverSource extends Source {
ContentResolverSource(@NonNull ContentResolver resolver, @NonNull Uri uri) {
ContentResolverSource(@NonNull ContentResolver resolver, @NonNull Uri uri,
@Nullable Resources res) {
mResolver = resolver;
mUri = uri;
mResources = res;
}
private final ContentResolver mResolver;
private final Uri mUri;
private final Resources mResources;
@Nullable
Resources getResources() { return mResources; }
@Override
public ImageDecoder createImageDecoder() throws IOException {
@@ -511,7 +517,18 @@ public final class ImageDecoder implements AutoCloseable {
@NonNull
public static Source createSource(@NonNull ContentResolver cr,
@NonNull Uri uri) {
return new ContentResolverSource(cr, uri);
return new ContentResolverSource(cr, uri, null);
}
/**
* Provide Resources for density scaling.
*
* @hide
*/
@NonNull
public static Source createSource(@NonNull ContentResolver cr,
@NonNull Uri uri, @Nullable Resources res) {
return new ContentResolverSource(cr, uri, res);
}
/**