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 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 { 52 public Rect getPosition(int index); 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 63 public PhotoFallbackEffect() { 64 setDuration(ANIM_DURATION); 65 setInterpolator(ANIM_INTERPOLATE); 66 } 67 68 public void addEntry(Path path, Rect rect, RawTexture texture) { 69 mList.add(new Entry(path, rect, texture)); 70 } 71 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 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 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 157 protected void onCalculate(float progress) { 158 mProgress = progress; 159 } 160 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 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