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