1fb6132b0b3079153fd1d15acf1dc3c6100aa2e00Bobby Georgescu/* 2fb6132b0b3079153fd1d15acf1dc3c6100aa2e00Bobby Georgescu * Copyright (C) 2013 The Android Open Source Project 3fb6132b0b3079153fd1d15acf1dc3c6100aa2e00Bobby Georgescu * 4fb6132b0b3079153fd1d15acf1dc3c6100aa2e00Bobby Georgescu * Licensed under the Apache License, Version 2.0 (the "License"); 5fb6132b0b3079153fd1d15acf1dc3c6100aa2e00Bobby Georgescu * you may not use this file except in compliance with the License. 6fb6132b0b3079153fd1d15acf1dc3c6100aa2e00Bobby Georgescu * You may obtain a copy of the License at 7fb6132b0b3079153fd1d15acf1dc3c6100aa2e00Bobby Georgescu * 8fb6132b0b3079153fd1d15acf1dc3c6100aa2e00Bobby Georgescu * http://www.apache.org/licenses/LICENSE-2.0 9fb6132b0b3079153fd1d15acf1dc3c6100aa2e00Bobby Georgescu * 10fb6132b0b3079153fd1d15acf1dc3c6100aa2e00Bobby Georgescu * Unless required by applicable law or agreed to in writing, software 11fb6132b0b3079153fd1d15acf1dc3c6100aa2e00Bobby Georgescu * distributed under the License is distributed on an "AS IS" BASIS, 12fb6132b0b3079153fd1d15acf1dc3c6100aa2e00Bobby Georgescu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13fb6132b0b3079153fd1d15acf1dc3c6100aa2e00Bobby Georgescu * See the License for the specific language governing permissions and 14fb6132b0b3079153fd1d15acf1dc3c6100aa2e00Bobby Georgescu * limitations under the License. 15fb6132b0b3079153fd1d15acf1dc3c6100aa2e00Bobby Georgescu */ 16fb6132b0b3079153fd1d15acf1dc3c6100aa2e00Bobby Georgescu 17d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reckpackage com.android.photos.shims; 18d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck 19d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reckimport android.graphics.Bitmap; 20d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reckimport android.graphics.Canvas; 21d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reckimport android.graphics.ColorFilter; 22d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reckimport android.graphics.Matrix; 23d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reckimport android.graphics.Paint; 24d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reckimport android.graphics.PixelFormat; 25d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reckimport android.graphics.Rect; 26d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reckimport android.graphics.drawable.Drawable; 27d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck 28d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reckimport com.android.gallery3d.data.MediaItem; 29d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reckimport com.android.gallery3d.ui.BitmapLoader; 30d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reckimport com.android.gallery3d.util.Future; 31d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reckimport com.android.gallery3d.util.FutureListener; 32d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reckimport com.android.gallery3d.util.ThreadPool; 332ff8d80018c27abdd475a7610ab3d684c4b33acbJohn Reckimport com.android.photos.data.GalleryBitmapPool; 34d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck 35d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck 36d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reckpublic class BitmapJobDrawable extends Drawable implements Runnable { 37d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck 38d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck private ThumbnailLoader mLoader; 39d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck private MediaItem mItem; 40d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck private Bitmap mBitmap; 41d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck private Paint mPaint = new Paint(); 42d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck private Matrix mDrawMatrix = new Matrix(); 43d3d2e2763bb4187a2dd3ac350d3a3c51d092890aJohn Reck private int mRotation = 0; 44d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck 45d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck public BitmapJobDrawable() { 46d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck } 47d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck 48d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck public void setMediaItem(MediaItem item) { 49638d9ec56c26d9f3cff55145ccbd20b35bb964f5John Reck if (mItem == item) return; 50638d9ec56c26d9f3cff55145ccbd20b35bb964f5John Reck 51d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck if (mLoader != null) { 52d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck mLoader.cancelLoad(); 53d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck } 54d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck mItem = item; 552ff8d80018c27abdd475a7610ab3d684c4b33acbJohn Reck if (mBitmap != null) { 562ff8d80018c27abdd475a7610ab3d684c4b33acbJohn Reck GalleryBitmapPool.getInstance().put(mBitmap); 572ff8d80018c27abdd475a7610ab3d684c4b33acbJohn Reck mBitmap = null; 582ff8d80018c27abdd475a7610ab3d684c4b33acbJohn Reck } 59638d9ec56c26d9f3cff55145ccbd20b35bb964f5John Reck if (mItem != null) { 60638d9ec56c26d9f3cff55145ccbd20b35bb964f5John Reck // TODO: Figure out why ThumbnailLoader doesn't like to be re-used 61638d9ec56c26d9f3cff55145ccbd20b35bb964f5John Reck mLoader = new ThumbnailLoader(this); 62638d9ec56c26d9f3cff55145ccbd20b35bb964f5John Reck mLoader.startLoad(); 63d3d2e2763bb4187a2dd3ac350d3a3c51d092890aJohn Reck mRotation = mItem.getRotation(); 64638d9ec56c26d9f3cff55145ccbd20b35bb964f5John Reck } 65d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck invalidateSelf(); 66d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck } 67d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck 68d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck @Override 69d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck public void run() { 70d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck Bitmap bitmap = mLoader.getBitmap(); 71d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck if (bitmap != null) { 72d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck mBitmap = bitmap; 73d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck updateDrawMatrix(); 74d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck } 75d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck } 76d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck 77d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck @Override 78d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck protected void onBoundsChange(Rect bounds) { 79d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck super.onBoundsChange(bounds); 80d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck updateDrawMatrix(); 81d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck } 82d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck 83d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck @Override 84d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck public void draw(Canvas canvas) { 85d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck Rect bounds = getBounds(); 86d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck if (mBitmap != null) { 87d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck canvas.save(); 88d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck canvas.clipRect(bounds); 89d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck canvas.concat(mDrawMatrix); 90d3d2e2763bb4187a2dd3ac350d3a3c51d092890aJohn Reck canvas.rotate(mRotation, bounds.centerX(), bounds.centerY()); 91d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck canvas.drawBitmap(mBitmap, 0, 0, mPaint); 92d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck canvas.restore(); 93d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck } else { 94d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck mPaint.setColor(0xFFCCCCCC); 95d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck canvas.drawRect(bounds, mPaint); 96d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck } 97d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck } 98d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck 99d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck private void updateDrawMatrix() { 100d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck Rect bounds = getBounds(); 101d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck if (mBitmap == null || bounds.isEmpty()) { 102d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck mDrawMatrix.reset(); 103d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck return; 104d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck } 105d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck 106d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck float scale; 107d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck float dx = 0, dy = 0; 108d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck 109d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck int dwidth = mBitmap.getWidth(); 110d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck int dheight = mBitmap.getHeight(); 111d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck int vwidth = bounds.width(); 112d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck int vheight = bounds.height(); 113d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck 114d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck // Calculates a matrix similar to ScaleType.CENTER_CROP 115d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck if (dwidth * vheight > vwidth * dheight) { 116d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck scale = (float) vheight / (float) dheight; 117d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck dx = (vwidth - dwidth * scale) * 0.5f; 118d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck } else { 119d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck scale = (float) vwidth / (float) dwidth; 120d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck dy = (vheight - dheight * scale) * 0.5f; 121d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck } 122d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck 123d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck mDrawMatrix.setScale(scale, scale); 124d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck mDrawMatrix.postTranslate((int) (dx + 0.5f), (int) (dy + 0.5f)); 125d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck invalidateSelf(); 126d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck } 127d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck 128d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck @Override 129d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck public int getIntrinsicWidth() { 130d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck return MediaItem.getTargetSize(MediaItem.TYPE_MICROTHUMBNAIL); 131d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck } 132d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck 133d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck @Override 134d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck public int getIntrinsicHeight() { 135d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck return MediaItem.getTargetSize(MediaItem.TYPE_MICROTHUMBNAIL); 136d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck } 137d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck 138d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck @Override 139d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck public int getOpacity() { 140d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck Bitmap bm = mBitmap; 141d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck return (bm == null || bm.hasAlpha() || mPaint.getAlpha() < 255) ? 142d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE; 143d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck } 144d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck 145d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck @Override 146d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck public void setAlpha(int alpha) { 147d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck int oldAlpha = mPaint.getAlpha(); 148d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck if (alpha != oldAlpha) { 149d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck mPaint.setAlpha(alpha); 150d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck invalidateSelf(); 151d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck } 152d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck } 153d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck 154d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck @Override 155d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck public void setColorFilter(ColorFilter cf) { 156d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck mPaint.setColorFilter(cf); 157d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck invalidateSelf(); 158d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck } 159d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck 160d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck private static class ThumbnailLoader extends BitmapLoader { 161d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck private static final ThreadPool sThreadPool = new ThreadPool(0, 2); 162d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck private BitmapJobDrawable mParent; 163d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck 164d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck public ThumbnailLoader(BitmapJobDrawable parent) { 165d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck mParent = parent; 166d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck } 167d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck 168d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck @Override 169d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck protected Future<Bitmap> submitBitmapTask(FutureListener<Bitmap> l) { 170d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck return sThreadPool.submit( 171d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck mParent.mItem.requestImage(MediaItem.TYPE_MICROTHUMBNAIL), this); 172d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck } 173d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck 174d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck @Override 175d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck protected void onLoadComplete(Bitmap bitmap) { 176d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck mParent.scheduleSelf(mParent, 0); 177d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck } 178d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck } 179d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck 180d228222e5efca7df8c7f2fe49e5ec76696cbbc05John Reck} 181