BitmapScreenNail.java revision e29fc4a51b99f12f7fae13fae272858df2e1af36
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 final int MAX_SIDE = 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 long mAnimationStartTime = ANIMATION_NOT_NEEDED;
50
51    private Bitmap mBitmap;
52    private TiledTexture mTexture;
53
54    public BitmapScreenNail(Bitmap bitmap) {
55        mWidth = bitmap.getWidth();
56        mHeight = bitmap.getHeight();
57        mBitmap = bitmap;
58        mTexture = new TiledTexture(bitmap);
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 = 640;
77            height = 480;
78        }
79        float scale = Math.min(1, (float) MAX_SIDE / 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.mTexture != null) {
107            recycleBitmap(MediaItem.getThumbPool(), mBitmap);
108            if (mTexture != null) mTexture.recycle();
109            mBitmap = newer.mBitmap;
110            mTexture = newer.mTexture;
111            newer.mBitmap = null;
112            newer.mTexture = null;
113        }
114        newer.recycle();
115        return this;
116    }
117
118    public void updatePlaceholderSize(int width, int height) {
119        if (mBitmap != null) return;
120        if (width == 0 || height == 0) return;
121        setSize(width, height);
122    }
123
124    @Override
125    public int getWidth() {
126        return mWidth;
127    }
128
129    @Override
130    public int getHeight() {
131        return mHeight;
132    }
133
134    @Override
135    public void noDraw() {
136    }
137
138    @Override
139    public void recycle() {
140        if (mTexture != null) {
141            mTexture.recycle();
142            mTexture = null;
143        }
144        recycleBitmap(MediaItem.getThumbPool(), mBitmap);
145        mBitmap = null;
146    }
147
148    public static void disableDrawPlaceholder() {
149        mDrawPlaceholder = false;
150    }
151
152    public static void enableDrawPlaceholder() {
153        mDrawPlaceholder = true;
154    }
155
156    @Override
157    public void draw(GLCanvas canvas, int x, int y, int width, int height) {
158        if (mTexture == null || !mTexture.isReady()) {
159            if (mAnimationStartTime == ANIMATION_NOT_NEEDED) {
160                mAnimationStartTime = ANIMATION_NEEDED;
161            }
162            if(mDrawPlaceholder) {
163                canvas.fillRect(x, y, width, height, mPlaceholderColor);
164            }
165            return;
166        }
167
168        if (mAnimationStartTime == ANIMATION_NEEDED) {
169            mAnimationStartTime = AnimationTime.get();
170        }
171
172        if (isAnimating()) {
173            mTexture.drawMixed(canvas, mPlaceholderColor, getRatio(), x, y,
174                    width, height);
175        } else {
176            mTexture.draw(canvas, x, y, width, height);
177        }
178    }
179
180    @Override
181    public void draw(GLCanvas canvas, RectF source, RectF dest) {
182        if (mTexture == null || !mTexture.isReady()) {
183            canvas.fillRect(dest.left, dest.top, dest.width(), dest.height(),
184                    mPlaceholderColor);
185            return;
186        }
187
188        mTexture.draw(canvas, source, dest);
189    }
190
191    public boolean isAnimating() {
192        if (mAnimationStartTime < 0) return false;
193        if (AnimationTime.get() - mAnimationStartTime >= DURATION) {
194            mAnimationStartTime = ANIMATION_DONE;
195            return false;
196        }
197        return true;
198    }
199
200    private float getRatio() {
201        float r = (float) (AnimationTime.get() - mAnimationStartTime) / DURATION;
202        return Utils.clamp(1.0f - r, 0.0f, 1.0f);
203    }
204
205    public boolean isShowingPlaceholder() {
206        return (mBitmap == null) || isAnimating();
207    }
208
209    public TiledTexture getTexture() {
210        return mTexture;
211    }
212}
213