1 /*
2  * Copyright (C) 2010 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.Rect;
20 import android.graphics.RectF;
21 import android.view.animation.DecelerateInterpolator;
22 import android.view.animation.Interpolator;
23 
24 import com.android.gallery3d.anim.Animation;
25 import com.android.gallery3d.data.Path;
26 import com.android.gallery3d.glrenderer.GLCanvas;
27 import com.android.gallery3d.glrenderer.RawTexture;
28 import com.android.gallery3d.ui.AlbumSlotRenderer.SlotFilter;
29 
30 import java.util.ArrayList;
31 
32 public class PhotoFallbackEffect extends Animation implements SlotFilter {
33 
34     private static final int ANIM_DURATION = 300;
35     private static final Interpolator ANIM_INTERPOLATE = new DecelerateInterpolator(1.5f);
36 
37     public static class Entry {
38         public int index;
39         public Path path;
40         public Rect source;
41         public Rect dest;
42         public RawTexture texture;
43 
Entry(Path path, Rect source, RawTexture texture)44         public Entry(Path path, Rect source, RawTexture texture) {
45             this.path = path;
46             this.source = source;
47             this.texture = texture;
48         }
49     }
50 
51     public interface PositionProvider {
getPosition(int index)52         public Rect getPosition(int index);
getItemIndex(Path path)53         public int getItemIndex(Path path);
54     }
55 
56     private RectF mSource = new RectF();
57     private RectF mTarget = new RectF();
58     private float mProgress;
59     private PositionProvider mPositionProvider;
60 
61     private ArrayList<Entry> mList = new ArrayList<Entry>();
62 
PhotoFallbackEffect()63     public PhotoFallbackEffect() {
64         setDuration(ANIM_DURATION);
65         setInterpolator(ANIM_INTERPOLATE);
66     }
67 
addEntry(Path path, Rect rect, RawTexture texture)68     public void addEntry(Path path, Rect rect, RawTexture texture) {
69         mList.add(new Entry(path, rect, texture));
70     }
71 
getEntry(Path path)72     public Entry getEntry(Path path) {
73         for (int i = 0, n = mList.size(); i < n; ++i) {
74             Entry entry = mList.get(i);
75             if (entry.path == path) return entry;
76         }
77         return null;
78     }
79 
draw(GLCanvas canvas)80     public boolean draw(GLCanvas canvas) {
81         boolean more = calculate(AnimationTime.get());
82         for (int i = 0, n = mList.size(); i < n; ++i) {
83             Entry entry = mList.get(i);
84             if (entry.index < 0) continue;
85             entry.dest = mPositionProvider.getPosition(entry.index);
86             drawEntry(canvas, entry);
87         }
88         return more;
89     }
90 
drawEntry(GLCanvas canvas, Entry entry)91     private void drawEntry(GLCanvas canvas, Entry entry) {
92         if (!entry.texture.isLoaded()) return;
93 
94         int w = entry.texture.getWidth();
95         int h = entry.texture.getHeight();
96 
97         Rect s = entry.source;
98         Rect d = entry.dest;
99 
100         // the following calculation is based on d.width() == d.height()
101 
102         float p = mProgress;
103 
104         float fullScale = (float) d.height() / Math.min(s.width(), s.height());
105         float scale = fullScale * p + 1 * (1 - p);
106 
107         float cx = d.centerX() * p + s.centerX() * (1 - p);
108         float cy = d.centerY() * p + s.centerY() * (1 - p);
109 
110         float ch = s.height() * scale;
111         float cw = s.width() * scale;
112 
113         if (w > h) {
114             // draw the center part
115             mTarget.set(cx - ch / 2, cy - ch / 2, cx + ch / 2, cy + ch / 2);
116             mSource.set((w - h) / 2, 0, (w + h) / 2, h);
117             canvas.drawTexture(entry.texture, mSource, mTarget);
118 
119             canvas.save(GLCanvas.SAVE_FLAG_ALPHA);
120             canvas.multiplyAlpha(1 - p);
121 
122             // draw the left part
123             mTarget.set(cx - cw / 2, cy - ch / 2, cx - ch / 2, cy + ch / 2);
124             mSource.set(0, 0, (w - h) / 2, h);
125             canvas.drawTexture(entry.texture, mSource, mTarget);
126 
127             // draw the right part
128             mTarget.set(cx + ch / 2, cy - ch / 2, cx + cw / 2, cy + ch / 2);
129             mSource.set((w + h) / 2, 0, w, h);
130             canvas.drawTexture(entry.texture, mSource, mTarget);
131 
132             canvas.restore();
133         } else {
134             // draw the center part
135             mTarget.set(cx - cw / 2, cy - cw / 2, cx + cw / 2, cy + cw / 2);
136             mSource.set(0, (h - w) / 2, w, (h + w) / 2);
137             canvas.drawTexture(entry.texture, mSource, mTarget);
138 
139             canvas.save(GLCanvas.SAVE_FLAG_ALPHA);
140             canvas.multiplyAlpha(1 - p);
141 
142             // draw the upper part
143             mTarget.set(cx - cw / 2, cy - ch / 2, cx + cw / 2, cy - cw / 2);
144             mSource.set(0, 0, w, (h - w) / 2);
145             canvas.drawTexture(entry.texture, mSource, mTarget);
146 
147             // draw the bottom part
148             mTarget.set(cx - cw / 2, cy + cw / 2, cx + cw / 2, cy + ch / 2);
149             mSource.set(0, (w + h) / 2, w, h);
150             canvas.drawTexture(entry.texture, mSource, mTarget);
151 
152             canvas.restore();
153         }
154     }
155 
156     @Override
onCalculate(float progress)157     protected void onCalculate(float progress) {
158         mProgress = progress;
159     }
160 
setPositionProvider(PositionProvider provider)161     public void setPositionProvider(PositionProvider provider) {
162         mPositionProvider = provider;
163         if (mPositionProvider != null) {
164             for (int i = 0, n = mList.size(); i < n; ++i) {
165                 Entry entry = mList.get(i);
166                 entry.index = mPositionProvider.getItemIndex(entry.path);
167             }
168         }
169     }
170 
171     @Override
acceptSlot(int index)172     public boolean acceptSlot(int index) {
173         for (int i = 0, n = mList.size(); i < n; ++i) {
174             Entry entry = mList.get(i);
175             if (entry.index == index) return false;
176         }
177         return true;
178     }
179 }
180