/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.gallery3d.ui; import android.graphics.Rect; import android.graphics.RectF; import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; import com.android.gallery3d.anim.Animation; import com.android.gallery3d.data.Path; import com.android.gallery3d.glrenderer.GLCanvas; import com.android.gallery3d.glrenderer.RawTexture; import com.android.gallery3d.ui.AlbumSlotRenderer.SlotFilter; import java.util.ArrayList; public class PhotoFallbackEffect extends Animation implements SlotFilter { private static final int ANIM_DURATION = 300; private static final Interpolator ANIM_INTERPOLATE = new DecelerateInterpolator(1.5f); public static class Entry { public int index; public Path path; public Rect source; public Rect dest; public RawTexture texture; public Entry(Path path, Rect source, RawTexture texture) { this.path = path; this.source = source; this.texture = texture; } } public interface PositionProvider { public Rect getPosition(int index); public int getItemIndex(Path path); } private RectF mSource = new RectF(); private RectF mTarget = new RectF(); private float mProgress; private PositionProvider mPositionProvider; private ArrayList mList = new ArrayList(); public PhotoFallbackEffect() { setDuration(ANIM_DURATION); setInterpolator(ANIM_INTERPOLATE); } public void addEntry(Path path, Rect rect, RawTexture texture) { mList.add(new Entry(path, rect, texture)); } public Entry getEntry(Path path) { for (int i = 0, n = mList.size(); i < n; ++i) { Entry entry = mList.get(i); if (entry.path == path) return entry; } return null; } public boolean draw(GLCanvas canvas) { boolean more = calculate(AnimationTime.get()); for (int i = 0, n = mList.size(); i < n; ++i) { Entry entry = mList.get(i); if (entry.index < 0) continue; entry.dest = mPositionProvider.getPosition(entry.index); drawEntry(canvas, entry); } return more; } private void drawEntry(GLCanvas canvas, Entry entry) { if (!entry.texture.isLoaded()) return; int w = entry.texture.getWidth(); int h = entry.texture.getHeight(); Rect s = entry.source; Rect d = entry.dest; // the following calculation is based on d.width() == d.height() float p = mProgress; float fullScale = (float) d.height() / Math.min(s.width(), s.height()); float scale = fullScale * p + 1 * (1 - p); float cx = d.centerX() * p + s.centerX() * (1 - p); float cy = d.centerY() * p + s.centerY() * (1 - p); float ch = s.height() * scale; float cw = s.width() * scale; if (w > h) { // draw the center part mTarget.set(cx - ch / 2, cy - ch / 2, cx + ch / 2, cy + ch / 2); mSource.set((w - h) / 2, 0, (w + h) / 2, h); canvas.drawTexture(entry.texture, mSource, mTarget); canvas.save(GLCanvas.SAVE_FLAG_ALPHA); canvas.multiplyAlpha(1 - p); // draw the left part mTarget.set(cx - cw / 2, cy - ch / 2, cx - ch / 2, cy + ch / 2); mSource.set(0, 0, (w - h) / 2, h); canvas.drawTexture(entry.texture, mSource, mTarget); // draw the right part mTarget.set(cx + ch / 2, cy - ch / 2, cx + cw / 2, cy + ch / 2); mSource.set((w + h) / 2, 0, w, h); canvas.drawTexture(entry.texture, mSource, mTarget); canvas.restore(); } else { // draw the center part mTarget.set(cx - cw / 2, cy - cw / 2, cx + cw / 2, cy + cw / 2); mSource.set(0, (h - w) / 2, w, (h + w) / 2); canvas.drawTexture(entry.texture, mSource, mTarget); canvas.save(GLCanvas.SAVE_FLAG_ALPHA); canvas.multiplyAlpha(1 - p); // draw the upper part mTarget.set(cx - cw / 2, cy - ch / 2, cx + cw / 2, cy - cw / 2); mSource.set(0, 0, w, (h - w) / 2); canvas.drawTexture(entry.texture, mSource, mTarget); // draw the bottom part mTarget.set(cx - cw / 2, cy + cw / 2, cx + cw / 2, cy + ch / 2); mSource.set(0, (w + h) / 2, w, h); canvas.drawTexture(entry.texture, mSource, mTarget); canvas.restore(); } } @Override protected void onCalculate(float progress) { mProgress = progress; } public void setPositionProvider(PositionProvider provider) { mPositionProvider = provider; if (mPositionProvider != null) { for (int i = 0, n = mList.size(); i < n; ++i) { Entry entry = mList.get(i); entry.index = mPositionProvider.getItemIndex(entry.path); } } } @Override public boolean acceptSlot(int index) { for (int i = 0, n = mList.size(); i < n; ++i) { Entry entry = mList.get(i); if (entry.index == index) return false; } return true; } }