1 /* 2 * Copyright (C) 2013 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 17 package com.android.photos.shims; 18 19 import android.graphics.Bitmap; 20 import android.graphics.Canvas; 21 import android.graphics.ColorFilter; 22 import android.graphics.Matrix; 23 import android.graphics.Paint; 24 import android.graphics.PixelFormat; 25 import android.graphics.Rect; 26 import android.graphics.drawable.Drawable; 27 28 import com.android.gallery3d.data.MediaItem; 29 import com.android.gallery3d.ui.BitmapLoader; 30 import com.android.gallery3d.util.Future; 31 import com.android.gallery3d.util.FutureListener; 32 import com.android.gallery3d.util.ThreadPool; 33 import com.android.photos.data.GalleryBitmapPool; 34 35 36 public class BitmapJobDrawable extends Drawable implements Runnable { 37 38 private ThumbnailLoader mLoader; 39 private MediaItem mItem; 40 private Bitmap mBitmap; 41 private Paint mPaint = new Paint(); 42 private Matrix mDrawMatrix = new Matrix(); 43 private int mRotation = 0; 44 BitmapJobDrawable()45 public BitmapJobDrawable() { 46 } 47 setMediaItem(MediaItem item)48 public void setMediaItem(MediaItem item) { 49 if (mItem == item) return; 50 51 if (mLoader != null) { 52 mLoader.cancelLoad(); 53 } 54 mItem = item; 55 if (mBitmap != null) { 56 GalleryBitmapPool.getInstance().put(mBitmap); 57 mBitmap = null; 58 } 59 if (mItem != null) { 60 // TODO: Figure out why ThumbnailLoader doesn't like to be re-used 61 mLoader = new ThumbnailLoader(this); 62 mLoader.startLoad(); 63 mRotation = mItem.getRotation(); 64 } 65 invalidateSelf(); 66 } 67 68 @Override run()69 public void run() { 70 Bitmap bitmap = mLoader.getBitmap(); 71 if (bitmap != null) { 72 mBitmap = bitmap; 73 updateDrawMatrix(); 74 } 75 } 76 77 @Override onBoundsChange(Rect bounds)78 protected void onBoundsChange(Rect bounds) { 79 super.onBoundsChange(bounds); 80 updateDrawMatrix(); 81 } 82 83 @Override draw(Canvas canvas)84 public void draw(Canvas canvas) { 85 Rect bounds = getBounds(); 86 if (mBitmap != null) { 87 canvas.save(); 88 canvas.clipRect(bounds); 89 canvas.concat(mDrawMatrix); 90 canvas.rotate(mRotation, bounds.centerX(), bounds.centerY()); 91 canvas.drawBitmap(mBitmap, 0, 0, mPaint); 92 canvas.restore(); 93 } else { 94 mPaint.setColor(0xFFCCCCCC); 95 canvas.drawRect(bounds, mPaint); 96 } 97 } 98 updateDrawMatrix()99 private void updateDrawMatrix() { 100 Rect bounds = getBounds(); 101 if (mBitmap == null || bounds.isEmpty()) { 102 mDrawMatrix.reset(); 103 return; 104 } 105 106 float scale; 107 float dx = 0, dy = 0; 108 109 int dwidth = mBitmap.getWidth(); 110 int dheight = mBitmap.getHeight(); 111 int vwidth = bounds.width(); 112 int vheight = bounds.height(); 113 114 // Calculates a matrix similar to ScaleType.CENTER_CROP 115 if (dwidth * vheight > vwidth * dheight) { 116 scale = (float) vheight / (float) dheight; 117 dx = (vwidth - dwidth * scale) * 0.5f; 118 } else { 119 scale = (float) vwidth / (float) dwidth; 120 dy = (vheight - dheight * scale) * 0.5f; 121 } 122 123 mDrawMatrix.setScale(scale, scale); 124 mDrawMatrix.postTranslate((int) (dx + 0.5f), (int) (dy + 0.5f)); 125 invalidateSelf(); 126 } 127 128 @Override getIntrinsicWidth()129 public int getIntrinsicWidth() { 130 return MediaItem.getTargetSize(MediaItem.TYPE_MICROTHUMBNAIL); 131 } 132 133 @Override getIntrinsicHeight()134 public int getIntrinsicHeight() { 135 return MediaItem.getTargetSize(MediaItem.TYPE_MICROTHUMBNAIL); 136 } 137 138 @Override getOpacity()139 public int getOpacity() { 140 Bitmap bm = mBitmap; 141 return (bm == null || bm.hasAlpha() || mPaint.getAlpha() < 255) ? 142 PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE; 143 } 144 145 @Override setAlpha(int alpha)146 public void setAlpha(int alpha) { 147 int oldAlpha = mPaint.getAlpha(); 148 if (alpha != oldAlpha) { 149 mPaint.setAlpha(alpha); 150 invalidateSelf(); 151 } 152 } 153 154 @Override setColorFilter(ColorFilter cf)155 public void setColorFilter(ColorFilter cf) { 156 mPaint.setColorFilter(cf); 157 invalidateSelf(); 158 } 159 160 private static class ThumbnailLoader extends BitmapLoader { 161 private static final ThreadPool sThreadPool = new ThreadPool(0, 2); 162 private BitmapJobDrawable mParent; 163 ThumbnailLoader(BitmapJobDrawable parent)164 public ThumbnailLoader(BitmapJobDrawable parent) { 165 mParent = parent; 166 } 167 168 @Override submitBitmapTask(FutureListener<Bitmap> l)169 protected Future<Bitmap> submitBitmapTask(FutureListener<Bitmap> l) { 170 return sThreadPool.submit( 171 mParent.mItem.requestImage(MediaItem.TYPE_MICROTHUMBNAIL), this); 172 } 173 174 @Override onLoadComplete(Bitmap bitmap)175 protected void onLoadComplete(Bitmap bitmap) { 176 mParent.scheduleSelf(mParent, 0); 177 } 178 } 179 180 } 181