1616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin/*
2616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin * Copyright (C) 2010 The Android Open Source Project
3616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin *
4616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin * Licensed under the Apache License, Version 2.0 (the "License");
5616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin * you may not use this file except in compliance with the License.
6616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin * You may obtain a copy of the License at
7616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin *
8616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin *      http://www.apache.org/licenses/LICENSE-2.0
9616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin *
10616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin * Unless required by applicable law or agreed to in writing, software
11616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin * distributed under the License is distributed on an "AS IS" BASIS,
12616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin * See the License for the specific language governing permissions and
14616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin * limitations under the License.
15616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin */
16616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin
17616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Linpackage com.android.gallery3d.ui;
18616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin
19616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Linimport android.graphics.Rect;
20616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Linimport android.graphics.RectF;
21616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Linimport android.view.animation.DecelerateInterpolator;
22616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Linimport android.view.animation.Interpolator;
23616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin
24616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Linimport com.android.gallery3d.anim.Animation;
25616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Linimport com.android.gallery3d.data.Path;
26a4eae1abb4f2547dfbda84301ee764ce35464881John Reckimport com.android.gallery3d.glrenderer.GLCanvas;
27a4eae1abb4f2547dfbda84301ee764ce35464881John Reckimport com.android.gallery3d.glrenderer.RawTexture;
28616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Linimport com.android.gallery3d.ui.AlbumSlotRenderer.SlotFilter;
29616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin
30616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Linimport java.util.ArrayList;
31616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin
32616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Linpublic class PhotoFallbackEffect extends Animation implements SlotFilter {
33616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin
34616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin    private static final int ANIM_DURATION = 300;
35616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin    private static final Interpolator ANIM_INTERPOLATE = new DecelerateInterpolator(1.5f);
36616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin
37616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin    public static class Entry {
38616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        public int index;
39616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        public Path path;
40616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        public Rect source;
41616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        public Rect dest;
42616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        public RawTexture texture;
43616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin
44616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        public Entry(Path path, Rect source, RawTexture texture) {
45616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin            this.path = path;
46616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin            this.source = source;
47616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin            this.texture = texture;
48616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        }
49616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin    }
50616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin
51616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin    public interface PositionProvider {
52616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        public Rect getPosition(int index);
53616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        public int getItemIndex(Path path);
54616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin    }
55616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin
56616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin    private RectF mSource = new RectF();
57616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin    private RectF mTarget = new RectF();
58616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin    private float mProgress;
59616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin    private PositionProvider mPositionProvider;
60616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin
61616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin    private ArrayList<Entry> mList = new ArrayList<Entry>();
62616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin
63616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin    public PhotoFallbackEffect() {
64616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        setDuration(ANIM_DURATION);
65616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        setInterpolator(ANIM_INTERPOLATE);
66616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin    }
67616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin
68616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin    public void addEntry(Path path, Rect rect, RawTexture texture) {
69616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        mList.add(new Entry(path, rect, texture));
70616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin    }
71616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin
72616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin    public Entry getEntry(Path path) {
73616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        for (int i = 0, n = mList.size(); i < n; ++i) {
74616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin            Entry entry = mList.get(i);
75616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin            if (entry.path == path) return entry;
76616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        }
77616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        return null;
78616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin    }
79616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin
80616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin    public boolean draw(GLCanvas canvas) {
81616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        boolean more = calculate(AnimationTime.get());
82616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        for (int i = 0, n = mList.size(); i < n; ++i) {
83616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin            Entry entry = mList.get(i);
84616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin            if (entry.index < 0) continue;
85616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin            entry.dest = mPositionProvider.getPosition(entry.index);
86616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin            drawEntry(canvas, entry);
87616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        }
88616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        return more;
89616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin    }
90616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin
91616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin    private void drawEntry(GLCanvas canvas, Entry entry) {
9237c605949219b8bf54c165c34d6405f5f2989f50Owen Lin        if (!entry.texture.isLoaded()) return;
93616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin
94616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        int w = entry.texture.getWidth();
95616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        int h = entry.texture.getHeight();
96616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin
97616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        Rect s = entry.source;
98616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        Rect d = entry.dest;
99616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin
100616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        // the following calculation is based on d.width() == d.height()
101616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin
102616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        float p = mProgress;
103616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin
104616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        float fullScale = (float) d.height() / Math.min(s.width(), s.height());
105616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        float scale = fullScale * p + 1 * (1 - p);
106616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin
107616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        float cx = d.centerX() * p + s.centerX() * (1 - p);
108616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        float cy = d.centerY() * p + s.centerY() * (1 - p);
109616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin
110616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        float ch = s.height() * scale;
111616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        float cw = s.width() * scale;
112616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin
113616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        if (w > h) {
114616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin            // draw the center part
115616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin            mTarget.set(cx - ch / 2, cy - ch / 2, cx + ch / 2, cy + ch / 2);
116616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin            mSource.set((w - h) / 2, 0, (w + h) / 2, h);
117616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin            canvas.drawTexture(entry.texture, mSource, mTarget);
118616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin
119616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin            canvas.save(GLCanvas.SAVE_FLAG_ALPHA);
120616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin            canvas.multiplyAlpha(1 - p);
121616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin
122616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin            // draw the left part
123616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin            mTarget.set(cx - cw / 2, cy - ch / 2, cx - ch / 2, cy + ch / 2);
124616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin            mSource.set(0, 0, (w - h) / 2, h);
125616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin            canvas.drawTexture(entry.texture, mSource, mTarget);
126616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin
127616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin            // draw the right part
128616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin            mTarget.set(cx + ch / 2, cy - ch / 2, cx + cw / 2, cy + ch / 2);
129616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin            mSource.set((w + h) / 2, 0, w, h);
130616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin            canvas.drawTexture(entry.texture, mSource, mTarget);
131616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin
132616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin            canvas.restore();
133616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        } else {
134616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin            // draw the center part
135616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin            mTarget.set(cx - cw / 2, cy - cw / 2, cx + cw / 2, cy + cw / 2);
136616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin            mSource.set(0, (h - w) / 2, w, (h + w) / 2);
137616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin            canvas.drawTexture(entry.texture, mSource, mTarget);
138616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin
139616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin            canvas.save(GLCanvas.SAVE_FLAG_ALPHA);
140616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin            canvas.multiplyAlpha(1 - p);
141616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin
142616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin            // draw the upper part
143616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin            mTarget.set(cx - cw / 2, cy - ch / 2, cx + cw / 2, cy - cw / 2);
144616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin            mSource.set(0, 0, w, (h - w) / 2);
145616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin            canvas.drawTexture(entry.texture, mSource, mTarget);
146616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin
147616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin            // draw the bottom part
148616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin            mTarget.set(cx - cw / 2, cy + cw / 2, cx + cw / 2, cy + ch / 2);
149616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin            mSource.set(0, (w + h) / 2, w, h);
150616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin            canvas.drawTexture(entry.texture, mSource, mTarget);
151616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin
152616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin            canvas.restore();
153616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        }
154616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin    }
155616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin
156616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin    @Override
157616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin    protected void onCalculate(float progress) {
158616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        mProgress = progress;
159616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin    }
160616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin
161616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin    public void setPositionProvider(PositionProvider provider) {
162616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        mPositionProvider = provider;
163616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        if (mPositionProvider != null) {
164616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin            for (int i = 0, n = mList.size(); i < n; ++i) {
165616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin                Entry entry = mList.get(i);
166616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin                entry.index = mPositionProvider.getItemIndex(entry.path);
167616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin            }
168616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        }
169616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin    }
170616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin
171616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin    @Override
172616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin    public boolean acceptSlot(int index) {
173616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        for (int i = 0, n = mList.size(); i < n; ++i) {
174616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin            Entry entry = mList.get(i);
175616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin            if (entry.index == index) return false;
176616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        }
177616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        return true;
178616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin    }
179616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin}
180