BitmapScreenNail.java revision ad7cf187bf0c11b05aa3eab7085148e0353f2af5
1/* 2 * Copyright (C) 2012 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 17package com.android.gallery3d.ui; 18 19import android.graphics.Bitmap; 20import android.graphics.RectF; 21 22import com.android.gallery3d.common.Utils; 23import com.android.gallery3d.data.BitmapPool; 24import com.android.gallery3d.data.MediaItem; 25 26// This is a ScreenNail wraps a Bitmap. There are some extra functions: 27// 28// - If we need to draw before the bitmap is available, we draw a rectange of 29// placeholder color (gray). 30// 31// - When the the bitmap is available, and we have drawn the placeholder color 32// before, we will do a fade-in animation. 33public class BitmapScreenNail implements ScreenNail { 34 @SuppressWarnings("unused") 35 private static final String TAG = "BitmapScreenNail"; 36 37 // The duration of the fading animation in milliseconds 38 private static final int DURATION = 180; 39 40 private static int sMaxSide = 640; 41 42 // These are special values for mAnimationStartTime 43 private static final long ANIMATION_NOT_NEEDED = -1; 44 private static final long ANIMATION_NEEDED = -2; 45 private static final long ANIMATION_DONE = -3; 46 47 private int mWidth; 48 private int mHeight; 49 private Bitmap mBitmap; 50 private BitmapTexture mTexture; 51 private long mAnimationStartTime = ANIMATION_NOT_NEEDED; 52 53 public BitmapScreenNail(Bitmap bitmap) { 54 mWidth = bitmap.getWidth(); 55 mHeight = bitmap.getHeight(); 56 mBitmap = bitmap; 57 // We create mTexture lazily, so we don't incur the cost if we don't 58 // actually need it. 59 } 60 61 public BitmapScreenNail(int width, int height) { 62 setSize(width, height); 63 } 64 65 // This gets overridden by bitmap_screennail_placeholder 66 // in GalleryUtils.initialize 67 private static int mPlaceholderColor = 0xFF222222; 68 private static boolean mDrawPlaceholder = true; 69 70 public static void setPlaceholderColor(int color) { 71 mPlaceholderColor = color; 72 } 73 74 private void setSize(int width, int height) { 75 if (width == 0 || height == 0) { 76 width = sMaxSide; 77 height = sMaxSide * 3 / 4; 78 } 79 float scale = Math.min(1, (float) sMaxSide / Math.max(width, height)); 80 mWidth = Math.round(scale * width); 81 mHeight = Math.round(scale * height); 82 } 83 84 private static void recycleBitmap(BitmapPool pool, Bitmap bitmap) { 85 if (pool == null || bitmap == null) return; 86 pool.recycle(bitmap); 87 } 88 89 // Combines the two ScreenNails. 90 // Returns the used one and recycle the unused one. 91 public ScreenNail combine(ScreenNail other) { 92 if (other == null) { 93 return this; 94 } 95 96 if (!(other instanceof BitmapScreenNail)) { 97 recycle(); 98 return other; 99 } 100 101 // Now both are BitmapScreenNail. Move over the information about width, 102 // height, and Bitmap, then recycle the other. 103 BitmapScreenNail newer = (BitmapScreenNail) other; 104 mWidth = newer.mWidth; 105 mHeight = newer.mHeight; 106 if (newer.mBitmap != null) { 107 recycleBitmap(MediaItem.getThumbPool(), mBitmap); 108 mBitmap = newer.mBitmap; 109 newer.mBitmap = null; 110 111 if (mTexture != null) { 112 mTexture.recycle(); 113 mTexture = null; 114 } 115 } 116 117 newer.recycle(); 118 return this; 119 } 120 121 public void updatePlaceholderSize(int width, int height) { 122 if (mBitmap != null) return; 123 if (width == 0 || height == 0) return; 124 setSize(width, height); 125 } 126 127 @Override 128 public int getWidth() { 129 return mWidth; 130 } 131 132 @Override 133 public int getHeight() { 134 return mHeight; 135 } 136 137 @Override 138 public void noDraw() { 139 } 140 141 @Override 142 public void recycle() { 143 if (mTexture != null) { 144 mTexture.recycle(); 145 mTexture = null; 146 } 147 recycleBitmap(MediaItem.getThumbPool(), mBitmap); 148 mBitmap = null; 149 } 150 151 public static void disableDrawPlaceholder() { 152 mDrawPlaceholder = false; 153 } 154 155 public static void enableDrawPlaceholder() { 156 mDrawPlaceholder = true; 157 } 158 159 @Override 160 public void draw(GLCanvas canvas, int x, int y, int width, int height) { 161 if (mBitmap == null) { 162 if (mAnimationStartTime == ANIMATION_NOT_NEEDED) { 163 mAnimationStartTime = ANIMATION_NEEDED; 164 } 165 if(mDrawPlaceholder) { 166 canvas.fillRect(x, y, width, height, mPlaceholderColor); 167 } 168 return; 169 } 170 171 if (mTexture == null) { 172 mTexture = new BitmapTexture(mBitmap); 173 } 174 175 if (mAnimationStartTime == ANIMATION_NEEDED) { 176 mAnimationStartTime = now(); 177 } 178 179 if (isAnimating()) { 180 canvas.drawMixed(mTexture, mPlaceholderColor, getRatio(), x, y, 181 width, height); 182 } else { 183 mTexture.draw(canvas, x, y, width, height); 184 } 185 } 186 187 @Override 188 public void draw(GLCanvas canvas, RectF source, RectF dest) { 189 if (mBitmap == null) { 190 canvas.fillRect(dest.left, dest.top, dest.width(), dest.height(), 191 mPlaceholderColor); 192 return; 193 } 194 195 if (mTexture == null) { 196 mTexture = new BitmapTexture(mBitmap); 197 } 198 199 canvas.drawTexture(mTexture, source, dest); 200 } 201 202 public boolean isAnimating() { 203 if (mAnimationStartTime < 0) return false; 204 if (now() - mAnimationStartTime >= DURATION) { 205 mAnimationStartTime = ANIMATION_DONE; 206 return false; 207 } 208 return true; 209 } 210 211 private static long now() { 212 return AnimationTime.get(); 213 } 214 215 private float getRatio() { 216 float r = (float)(now() - mAnimationStartTime) / DURATION; 217 return Utils.clamp(1.0f - r, 0.0f, 1.0f); 218 } 219 220 public boolean isShowingPlaceholder() { 221 return (mBitmap == null) || isAnimating(); 222 } 223 224 public static void setMaxSide(int size) { 225 sMaxSide = size; 226 } 227} 228