1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.test.uibench.leanback; 17 18 import android.content.Context; 19 import android.graphics.Bitmap; 20 import android.graphics.Canvas; 21 import android.graphics.Color; 22 import android.graphics.Paint; 23 import android.os.AsyncTask; 24 import androidx.collection.LruCache; 25 import android.util.DisplayMetrics; 26 import android.widget.ImageView; 27 28 /** 29 * This class simulates a typical Bitmap memory cache with up to 1.5 times of screen pixels. 30 * The sample bitmap is generated in worker threads in AsyncTask.THREAD_POOL_EXECUTOR. 31 * The class does not involve decoding, disk cache i/o, network i/o, as the test is mostly focusing 32 * on the graphics side. 33 * There will be two general use cases for cards in leanback test: 34 * 1. As a typical app, each card has its own id and load its own Bitmap, the test result will 35 * include impact of texture upload. 36 * 2. All cards share same id/Bitmap and there wont be texture upload. 37 */ 38 public class BitmapLoader { 39 40 /** 41 * Caches bitmaps with bytes adds up to 1.5 x screen 42 * DO NOT CHANGE this defines baseline of test result. 43 */ 44 static final float CACHE_SIZE_TO_SCREEN = 1.5f; 45 /** 46 * 4 bytes per pixel for RGBA_8888 47 */ 48 static final int BYTES_PER_PIXEL = 4; 49 50 static LruCache<Long, Bitmap> sLruCache; 51 static Paint sTextPaint = new Paint(); 52 53 static { 54 sTextPaint.setColor(Color.BLACK); 55 } 56 57 /** 58 * get or initialize LruCache, the max is set to full screen pixels. 59 */ getLruCache(Context context)60 static LruCache<Long, Bitmap> getLruCache(Context context) { 61 if (sLruCache == null) { 62 DisplayMetrics metrics = context.getResources().getDisplayMetrics(); 63 int width = metrics.widthPixels; 64 int height = metrics.heightPixels; 65 int maxBytes = (int) (width * height * BYTES_PER_PIXEL * CACHE_SIZE_TO_SCREEN); 66 sLruCache = new LruCache<Long, Bitmap>(maxBytes) { 67 @Override 68 protected int sizeOf(Long key, Bitmap value) { 69 return value.getByteCount(); 70 } 71 }; 72 } 73 return sLruCache; 74 } 75 76 static class BitmapAsyncTask extends AsyncTask<Void, Void, Bitmap> { 77 78 ImageView mImageView; 79 long mId; 80 int mWidth; 81 int mHeight; 82 BitmapAsyncTask(ImageView view, long id, int width, int height)83 BitmapAsyncTask(ImageView view, long id, int width, int height) { 84 mImageView = view; 85 mId = id; 86 mImageView.setTag(this); 87 mWidth = width; 88 mHeight = height; 89 } 90 91 @Override doInBackground(Void... voids)92 protected Bitmap doInBackground(Void... voids) { 93 // generate a sample bitmap: white background and text showing id 94 Bitmap bitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888); 95 Canvas canvas = new Canvas(bitmap); 96 canvas.drawARGB(0xff, 0xff, 0xff, 0xff); 97 canvas.drawText(Long.toString(mId), 0f, mHeight / 2, sTextPaint); 98 canvas.setBitmap(null); 99 bitmap.prepareToDraw(); 100 return bitmap; 101 } 102 103 @Override onCancelled()104 protected void onCancelled() { 105 if (mImageView.getTag() == this) { 106 mImageView.setTag(null); 107 } 108 } 109 110 @Override onPostExecute(Bitmap bitmap)111 protected void onPostExecute(Bitmap bitmap) { 112 if (mImageView.getTag() == this) { 113 mImageView.setTag(null); 114 sLruCache.put(mId, bitmap); 115 mImageView.setImageBitmap(bitmap); 116 } 117 } 118 } 119 loadBitmap(ImageView view, long id, int width, int height)120 public static void loadBitmap(ImageView view, long id, int width, int height) { 121 Context context = view.getContext(); 122 Bitmap bitmap = getLruCache(context).get(id); 123 if (bitmap != null) { 124 view.setImageBitmap(bitmap); 125 return; 126 } 127 new BitmapAsyncTask(view, id, width, height) 128 .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 129 } 130 cancel(ImageView view)131 public static void cancel(ImageView view) { 132 BitmapAsyncTask task = (BitmapAsyncTask) view.getTag(); 133 if (task != null && task.mImageView == view) { 134 task.mImageView.setTag(null); 135 task.cancel(false); 136 } 137 } 138 clear()139 public static void clear() { 140 if (sLruCache != null) { 141 sLruCache.evictAll(); 142 } 143 } 144 } 145