From b52c8a1a8f31490106cb37fae9a97a0bc1347583 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Fri, 8 Jun 2018 00:46:40 -0700 Subject: [PATCH] Use ImageDecoder API on P and higher quality decodes on non-low ram devices --- .../com/limelight/grid/AppGridAdapter.java | 6 +- .../grid/assets/DiskAssetLoader.java | 86 ++++++++++++++----- 2 files changed, 64 insertions(+), 28 deletions(-) diff --git a/app/src/main/java/com/limelight/grid/AppGridAdapter.java b/app/src/main/java/com/limelight/grid/AppGridAdapter.java index 17b56bce..8add8ebd 100644 --- a/app/src/main/java/com/limelight/grid/AppGridAdapter.java +++ b/app/src/main/java/com/limelight/grid/AppGridAdapter.java @@ -1,7 +1,6 @@ package com.limelight.grid; import android.app.Activity; -import android.graphics.BitmapFactory; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; @@ -46,13 +45,10 @@ public class AppGridAdapter extends GenericGridAdapter { } LimeLog.info("Art scaling divisor: " + scalingDivisor); - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inSampleSize = (int) scalingDivisor; - this.loader = new CachedAppAssetLoader(computer, scalingDivisor, new NetworkAssetLoader(context, uniqueId), new MemoryAssetLoader(), - new DiskAssetLoader(context.getCacheDir())); + new DiskAssetLoader(context)); } public void cancelQueuedOperations() { diff --git a/app/src/main/java/com/limelight/grid/assets/DiskAssetLoader.java b/app/src/main/java/com/limelight/grid/assets/DiskAssetLoader.java index 1582ebc4..d17bc327 100644 --- a/app/src/main/java/com/limelight/grid/assets/DiskAssetLoader.java +++ b/app/src/main/java/com/limelight/grid/assets/DiskAssetLoader.java @@ -1,7 +1,11 @@ package com.limelight.grid.assets; +import android.app.ActivityManager; +import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.graphics.ImageDecoder; +import android.os.Build; import com.limelight.LimeLog; import com.limelight.utils.CacheHelper; @@ -19,10 +23,19 @@ public class DiskAssetLoader { private static final int STANDARD_ASSET_WIDTH = 300; private static final int STANDARD_ASSET_HEIGHT = 400; + private final boolean isLowRamDevice; private final File cacheDir; - public DiskAssetLoader(File cacheDir) { - this.cacheDir = cacheDir; + public DiskAssetLoader(Context context) { + this.cacheDir = context.getCacheDir(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + this.isLowRamDevice = + ((ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE)).isLowRamDevice(); + } + else { + // Use conservative low RAM behavior on very old devices + this.isLowRamDevice = true; + } } public boolean checkCacheExists(CachedAppAssetLoader.LoaderTuple tuple) { @@ -66,28 +79,55 @@ public class DiskAssetLoader { return null; } - // Lookup bounds of the downloaded image - BitmapFactory.Options decodeOnlyOptions = new BitmapFactory.Options(); - decodeOnlyOptions.inJustDecodeBounds = true; - BitmapFactory.decodeFile(file.getAbsolutePath(), decodeOnlyOptions); - if (decodeOnlyOptions.outWidth <= 0 || decodeOnlyOptions.outHeight <= 0) { - // Dimensions set to -1 on error. Return value always null. - return null; + Bitmap bmp; + + // For OSes prior to P, we have to use the ugly BitmapFactory API + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) { + // Lookup bounds of the downloaded image + BitmapFactory.Options decodeOnlyOptions = new BitmapFactory.Options(); + decodeOnlyOptions.inJustDecodeBounds = true; + BitmapFactory.decodeFile(file.getAbsolutePath(), decodeOnlyOptions); + if (decodeOnlyOptions.outWidth <= 0 || decodeOnlyOptions.outHeight <= 0) { + // Dimensions set to -1 on error. Return value always null. + return null; + } + + LimeLog.info("Tuple "+tuple+" has cached art of size: "+decodeOnlyOptions.outWidth+"x"+decodeOnlyOptions.outHeight); + + // Load the image scaled to the appropriate size + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inSampleSize = calculateInSampleSize(decodeOnlyOptions, + STANDARD_ASSET_WIDTH / sampleSize, + STANDARD_ASSET_HEIGHT / sampleSize); + if (isLowRamDevice) { + options.inPreferredConfig = Bitmap.Config.RGB_565; + options.inDither = true; + } + else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + options.inPreferredConfig = Bitmap.Config.HARDWARE; + } + + bmp = BitmapFactory.decodeFile(file.getAbsolutePath(), options); + if (bmp != null) { + LimeLog.info("Tuple "+tuple+" decoded from disk cache with sample size: "+options.inSampleSize); + } } - - LimeLog.info("Tuple "+tuple+" has cached art of size: "+decodeOnlyOptions.outWidth+"x"+decodeOnlyOptions.outHeight); - - // Load the image scaled to the appropriate size - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inSampleSize = calculateInSampleSize(decodeOnlyOptions, - STANDARD_ASSET_WIDTH / sampleSize, - STANDARD_ASSET_HEIGHT / sampleSize); - options.inPreferredConfig = Bitmap.Config.RGB_565; - options.inDither = true; - Bitmap bmp = BitmapFactory.decodeFile(file.getAbsolutePath(), options); - - if (bmp != null) { - LimeLog.info("Tuple "+tuple+" decoded from disk cache with sample size: "+options.inSampleSize); + else { + // On P, we can get a bitmap back in one step with ImageDecoder + try { + bmp = ImageDecoder.decodeBitmap(ImageDecoder.createSource(file), new ImageDecoder.OnHeaderDecodedListener() { + @Override + public void onHeaderDecoded(ImageDecoder imageDecoder, ImageDecoder.ImageInfo imageInfo, ImageDecoder.Source source) { + imageDecoder.setTargetSize(STANDARD_ASSET_WIDTH, STANDARD_ASSET_HEIGHT); + if (isLowRamDevice) { + imageDecoder.setMemorySizePolicy(ImageDecoder.MEMORY_POLICY_LOW_RAM); + } + } + }); + } catch (IOException e) { + e.printStackTrace(); + return null; + } } return bmp;