1030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin/*
2030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin * Copyright (C) 2012 The Android Open Source Project
3030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin *
4030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin * Licensed under the Apache License, Version 2.0 (the "License");
5030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin * you may not use this file except in compliance with the License.
6030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin * You may obtain a copy of the License at
7030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin *
8030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin *      http://www.apache.org/licenses/LICENSE-2.0
9030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin *
10030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin * Unless required by applicable law or agreed to in writing, software
11030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin * distributed under the License is distributed on an "AS IS" BASIS,
12030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin * See the License for the specific language governing permissions and
14030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin * limitations under the License.
15030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin */
16030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin
17030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Linpackage com.android.gallery3d.ui;
18030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin
19030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Linimport android.graphics.Bitmap;
20030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Linimport android.graphics.RectF;
21030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin
22030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Linimport com.android.gallery3d.common.Utils;
23f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescuimport com.android.photos.data.GalleryBitmapPool;
24a4eae1abb4f2547dfbda84301ee764ce35464881John Reckimport com.android.gallery3d.glrenderer.GLCanvas;
25a4eae1abb4f2547dfbda84301ee764ce35464881John Reckimport com.android.gallery3d.glrenderer.TiledTexture;
26030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin
27030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin// This is a ScreenNail wraps a Bitmap. There are some extra functions:
28030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin//
29030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin// - If we need to draw before the bitmap is available, we draw a rectange of
30030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin// placeholder color (gray).
31030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin//
32030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin// - When the the bitmap is available, and we have drawn the placeholder color
33030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin// before, we will do a fade-in animation.
34030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Linpublic class TiledScreenNail implements ScreenNail {
35030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    @SuppressWarnings("unused")
36030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    private static final String TAG = "TiledScreenNail";
37030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin
38030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    // The duration of the fading animation in milliseconds
39030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    private static final int DURATION = 180;
40030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin
41030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    private static int sMaxSide = 640;
42030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin
43030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    // These are special values for mAnimationStartTime
44030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    private static final long ANIMATION_NOT_NEEDED = -1;
45030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    private static final long ANIMATION_NEEDED = -2;
46030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    private static final long ANIMATION_DONE = -3;
47030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin
48030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    private int mWidth;
49030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    private int mHeight;
50030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    private long mAnimationStartTime = ANIMATION_NOT_NEEDED;
51030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin
52030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    private Bitmap mBitmap;
53030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    private TiledTexture mTexture;
54030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin
55030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    public TiledScreenNail(Bitmap bitmap) {
56030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        mWidth = bitmap.getWidth();
57030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        mHeight = bitmap.getHeight();
58030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        mBitmap = bitmap;
59030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        mTexture = new TiledTexture(bitmap);
60030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    }
61030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin
62030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    public TiledScreenNail(int width, int height) {
63030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        setSize(width, height);
64030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    }
65030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin
66030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    // This gets overridden by bitmap_screennail_placeholder
67030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    // in GalleryUtils.initialize
68030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    private static int mPlaceholderColor = 0xFF222222;
69030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    private static boolean mDrawPlaceholder = true;
70030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin
71030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    public static void setPlaceholderColor(int color) {
72030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        mPlaceholderColor = color;
73030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    }
74030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin
75030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    private void setSize(int width, int height) {
76030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        if (width == 0 || height == 0) {
77030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin            width = sMaxSide;
78030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin            height = sMaxSide * 3 / 4;
79030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        }
80030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        float scale = Math.min(1, (float) sMaxSide / Math.max(width, height));
81030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        mWidth = Math.round(scale * width);
82030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        mHeight = Math.round(scale * height);
83030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    }
84030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin
85030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    // Combines the two ScreenNails.
86030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    // Returns the used one and recycle the unused one.
87030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    public ScreenNail combine(ScreenNail other) {
88030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        if (other == null) {
89030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin            return this;
90030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        }
91030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin
92030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        if (!(other instanceof TiledScreenNail)) {
93030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin            recycle();
94030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin            return other;
95030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        }
96030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin
97030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        // Now both are TiledScreenNail. Move over the information about width,
98030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        // height, and Bitmap, then recycle the other.
99030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        TiledScreenNail newer = (TiledScreenNail) other;
100030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        mWidth = newer.mWidth;
101030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        mHeight = newer.mHeight;
102030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        if (newer.mTexture != null) {
103f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescu            if (mBitmap != null) GalleryBitmapPool.getInstance().put(mBitmap);
104030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin            if (mTexture != null) mTexture.recycle();
105030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin            mBitmap = newer.mBitmap;
106030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin            mTexture = newer.mTexture;
107030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin            newer.mBitmap = null;
108030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin            newer.mTexture = null;
109030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        }
110030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        newer.recycle();
111030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        return this;
112030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    }
113030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin
114030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    public void updatePlaceholderSize(int width, int height) {
115030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        if (mBitmap != null) return;
116030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        if (width == 0 || height == 0) return;
117030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        setSize(width, height);
118030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    }
119030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin
120030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    @Override
121030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    public int getWidth() {
122030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        return mWidth;
123030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    }
124030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin
125030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    @Override
126030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    public int getHeight() {
127030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        return mHeight;
128030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    }
129030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin
130030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    @Override
131030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    public void noDraw() {
132030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    }
133030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin
134030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    @Override
135030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    public void recycle() {
136030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        if (mTexture != null) {
137030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin            mTexture.recycle();
138030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin            mTexture = null;
139030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        }
140f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescu        if (mBitmap != null) {
141f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescu            GalleryBitmapPool.getInstance().put(mBitmap);
142f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescu            mBitmap = null;
143f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescu        }
144030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    }
145030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin
146030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    public static void disableDrawPlaceholder() {
147030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        mDrawPlaceholder = false;
148030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    }
149030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin
150030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    public static void enableDrawPlaceholder() {
151030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        mDrawPlaceholder = true;
152030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    }
153030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin
154030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    @Override
155030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    public void draw(GLCanvas canvas, int x, int y, int width, int height) {
156030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        if (mTexture == null || !mTexture.isReady()) {
157030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin            if (mAnimationStartTime == ANIMATION_NOT_NEEDED) {
158030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin                mAnimationStartTime = ANIMATION_NEEDED;
159030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin            }
160030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin            if(mDrawPlaceholder) {
161030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin                canvas.fillRect(x, y, width, height, mPlaceholderColor);
162030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin            }
163030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin            return;
164030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        }
165030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin
166030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        if (mAnimationStartTime == ANIMATION_NEEDED) {
167030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin            mAnimationStartTime = AnimationTime.get();
168030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        }
169030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin
170030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        if (isAnimating()) {
171030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin            mTexture.drawMixed(canvas, mPlaceholderColor, getRatio(), x, y,
172030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin                    width, height);
173030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        } else {
174030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin            mTexture.draw(canvas, x, y, width, height);
175030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        }
176030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    }
177030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin
178030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    @Override
179030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    public void draw(GLCanvas canvas, RectF source, RectF dest) {
180030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        if (mTexture == null || !mTexture.isReady()) {
181030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin            canvas.fillRect(dest.left, dest.top, dest.width(), dest.height(),
182030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin                    mPlaceholderColor);
183030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin            return;
184030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        }
185030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin
186030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        mTexture.draw(canvas, source, dest);
187030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    }
188030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin
189030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    public boolean isAnimating() {
190d71a718afe02282153d86b78f6a44c4783203d54Owen Lin        // The TiledTexture may not be uploaded completely yet.
191d71a718afe02282153d86b78f6a44c4783203d54Owen Lin        // In that case, we count it as animating state and we will draw
192d71a718afe02282153d86b78f6a44c4783203d54Owen Lin        // the placeholder in TileImageView.
193d71a718afe02282153d86b78f6a44c4783203d54Owen Lin        if (mTexture == null || !mTexture.isReady()) return true;
194030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        if (mAnimationStartTime < 0) return false;
195030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        if (AnimationTime.get() - mAnimationStartTime >= DURATION) {
196030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin            mAnimationStartTime = ANIMATION_DONE;
197030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin            return false;
198030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        }
199030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        return true;
200030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    }
201030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin
202030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    private float getRatio() {
203030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        float r = (float) (AnimationTime.get() - mAnimationStartTime) / DURATION;
204030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        return Utils.clamp(1.0f - r, 0.0f, 1.0f);
205030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    }
206030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin
207030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    public boolean isShowingPlaceholder() {
208030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        return (mBitmap == null) || isAnimating();
209030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    }
210030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin
211030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    public TiledTexture getTexture() {
212030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        return mTexture;
213030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    }
214030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin
215030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    public static void setMaxSide(int size) {
216030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin        sMaxSide = size;
217030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin    }
218030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin}
219