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