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