PhotoView.java revision 49affdc4e274098a34e4eb2dbe4a89a750f1ba7f
1f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin/* 2f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Copyright (C) 2010 The Android Open Source Project 3f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 4f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Licensed under the Apache License, Version 2.0 (the "License"); 5f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * you may not use this file except in compliance with the License. 6f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * You may obtain a copy of the License at 7f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 8f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * http://www.apache.org/licenses/LICENSE-2.0 9f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 10f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Unless required by applicable law or agreed to in writing, software 11f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * distributed under the License is distributed on an "AS IS" BASIS, 12f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * See the License for the specific language governing permissions and 14f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * limitations under the License. 15f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */ 16f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 17f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpackage com.android.gallery3d.ui; 18f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 19f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.content.Context; 20f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.graphics.Color; 212ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Changimport android.graphics.Matrix; 22cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Changimport android.graphics.Point; 2304ac045bf8da5082bbb0bdc9ea5f9c9b5b796ad0Yuli Huangimport android.graphics.Rect; 24f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.os.Message; 25f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.view.MotionEvent; 26cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Changimport android.view.animation.AccelerateInterpolator; 27f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 282b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Linimport com.android.gallery3d.R; 292b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Linimport com.android.gallery3d.app.GalleryActivity; 30cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Changimport com.android.gallery3d.common.Utils; 31616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Linimport com.android.gallery3d.data.MediaItem; 32b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Changimport com.android.gallery3d.data.MediaObject; 33b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Changimport com.android.gallery3d.util.RangeArray; 34b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 35f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpublic class PhotoView extends GLView { 36f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @SuppressWarnings("unused") 37f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final String TAG = "PhotoView"; 38c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang private static final int PLACEHOLDER_COLOR = 0xFF222222; 39f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 40f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static final int INVALID_SIZE = -1; 41b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public static final long INVALID_DATA_VERSION = 42b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang MediaObject.INVALID_DATA_VERSION; 43f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 44c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang public static class Size { 45c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang public int width; 46c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang public int height; 47c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang } 48c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang 49c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang public interface Model extends TileImageView.Model { 50bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public int getCurrentIndex(); 51bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public void moveTo(int index); 52c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang 53c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // Returns the size for the specified picture. If the size information is 54c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // not avaiable, width = height = 0. 55c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang public void getImageSize(int offset, Size size); 56c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang 57616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin // Returns the media item for the specified picture. 58616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin public MediaItem getMediaItem(int offset); 59616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin 60c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // Returns the rotation for the specified picture. 61c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang public int getImageRotation(int offset); 62f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 63b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // This amends the getScreenNail() method of TileImageView.Model to get 64b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // ScreenNail at previous (negative offset) or next (positive offset) 65b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // positions. Returns null if the specified ScreenNail is unavailable. 66b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public ScreenNail getScreenNail(int offset); 67c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang 68c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // Set this to true if we need the model to provide full images. 69b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang public void setNeedFullImage(boolean enabled); 70bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 71bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // Returns true if the item is the Camera preview. 72bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public boolean isCamera(int offset); 73d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang 7443a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong // Returns true if the item is the Panorama. 7543a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong public boolean isPanorama(int offset); 7643a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong 77d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang // Returns true if the item is a Video. 78d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang public boolean isVideo(int offset); 79f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang 80f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang public static final int LOADING_INIT = 0; 81f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang public static final int LOADING_COMPLETE = 1; 82f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang public static final int LOADING_FAIL = 2; 83f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang 84f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang public int getLoadingState(int offset); 85b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 86b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 87bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public interface Listener { 88b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void onSingleTapUp(int x, int y); 89bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public void lockOrientation(); 90bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public void unlockOrientation(); 91bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public void onFullScreenChanged(boolean full); 9261f94714c3702115d2f89bb5f8829697be0c3680Chih-Chung Chang public void onActionBarAllowed(boolean allowed); 93bd7c016d728853d38f98a3c6077b7bd9b08858b9Yuli Huang public void onCurrentImageUpdated(); 94b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 95f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 96bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // Here is a graph showing the places we need to lock/unlock device 97bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // orientation: 98bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // 99bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // +------------+ A +------------+ 100bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // Page mode | Camera |<---| Photo | 101bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // | [locked] |--->| [unlocked] | 102bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // +------------+ B +------------+ 103bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // ^ ^ 104bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // | C | D 105bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // +------------+ +------------+ 106bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // | Camera | | Photo | 107bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // Film mode | [*] | | [*] | 108bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // +------------+ +------------+ 109bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // 110bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // In Page mode, we want to lock in Camera because we don't want the system 111bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // rotation animation. We also want to unlock in Photo because we want to 112bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // show the system action bar in the right place. 113bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // 114bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // We don't show action bar in Film mode, so it's fine for it to be locked 115bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // or unlocked in Film mode. 116bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // 117bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // There are four transitions we need to check if we need to 118bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // lock/unlock. Marked as A to D above and in the code. 119bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 120b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static final int MSG_CANCEL_EXTRA_SCALING = 2; 121b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static final int MSG_SWITCH_FOCUS = 3; 1222c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang private static final int MSG_CAPTURE_ANIMATION_DONE = 4; 123f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 124b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static final int MOVE_THRESHOLD = 256; 125f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final float SWIPE_THRESHOLD = 300f; 126f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 127f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final float DEFAULT_TEXT_SIZE = 20; 128cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private static float TRANSITION_SCALE_FACTOR = 0.74f; 129d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang private static final int ICON_RATIO = 6; 1302c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang 1312c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // whether we want to apply card deck effect in page mode. 132b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static final boolean CARD_EFFECT = true; 133cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 134cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // Used to calculate the scaling factor for the fading animation. 135cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private ZInterpolator mScaleInterpolator = new ZInterpolator(0.5f); 136cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 137cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // Used to calculate the alpha factor for the fading animation. 138cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private AccelerateInterpolator mAlphaInterpolator = 139cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang new AccelerateInterpolator(0.9f); 140f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 141b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // We keep this many previous ScreenNails. (also this many next ScreenNails) 142b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public static final int SCREEN_NAIL_MAX = 3; 143b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 144b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // The picture entries, the valid index is from -SCREEN_NAIL_MAX to 145b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // SCREEN_NAIL_MAX. 146b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private final RangeArray<Picture> mPictures = 147b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang new RangeArray<Picture>(-SCREEN_NAIL_MAX, SCREEN_NAIL_MAX); 148f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1496575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang private final MyGestureListener mGestureListener; 1503a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang private final GestureRecognizer mGestureRecognizer; 151f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final PositionController mPositionController; 152f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 153bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private Listener mListener; 154f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private Model mModel; 155f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private StringTexture mLoadingText; 156f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private StringTexture mNoThumbnailText; 157b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private TileImageView mTileView; 158532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private EdgeView mEdgeView; 159f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private Texture mVideoPlayIcon; 160f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 161f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private SynchronizedHandler mHandler; 162f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 163cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private Point mImageCenter = new Point(); 164534b12fd804610dd67b8109bc08ba76f31afb33eChih-Chung Chang private boolean mCancelExtraScalingPending; 165b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private boolean mFilmMode = false; 166bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private int mDisplayRotation = 0; 167bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private int mCompensation = 0; 168bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private boolean mFullScreen = true; 1692ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang private Rect mCameraRelativeFrame = new Rect(); 170bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private Rect mCameraRect = new Rect(); 171f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 172c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // [mPrevBound, mNextBound] is the range of index for all pictures in the 173c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // model, if we assume the index of current focused picture is 0. So if 174c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // there are some previous pictures, mPrevBound < 0, and if there are some 175c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // next pictures, mNextBound > 0. 176c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang private int mPrevBound; 177c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang private int mNextBound; 178c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang 1792c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // This variable prevents us doing snapback until its values goes to 0. This 1802c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // happens if the user gesture is still in progress or we are in a capture 1812c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // animation. 1822c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang private int mHolding; 1832c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang private static final int HOLD_TOUCH_DOWN = 1; 18418958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang private static final int HOLD_CAPTURE_ANIMATION = 2; 1852c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang 186f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public PhotoView(GalleryActivity activity) { 187f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mTileView = new TileImageView(activity); 188f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin addComponent(mTileView); 189f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Context context = activity.getAndroidContext(); 190532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mEdgeView = new EdgeView(context); 191532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang addComponent(mEdgeView); 192f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mLoadingText = StringTexture.newInstance( 193f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin context.getString(R.string.loading), 194f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin DEFAULT_TEXT_SIZE, Color.WHITE); 195f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mNoThumbnailText = StringTexture.newInstance( 196f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin context.getString(R.string.no_thumbnail), 197f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin DEFAULT_TEXT_SIZE, Color.WHITE); 198f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 199b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mHandler = new MyHandler(activity.getGLRoot()); 200f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 2016575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang mGestureListener = new MyGestureListener(); 2026575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang mGestureRecognizer = new GestureRecognizer(context, mGestureListener); 203f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 204b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController = new PositionController(context, 205b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang new PositionController.Listener() { 206b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void invalidate() { 207b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang PhotoView.this.invalidate(); 208b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 2092c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang public boolean isHolding() { 21018958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang return mHolding != 0; 211b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 212b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void onPull(int offset, int direction) { 213b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mEdgeView.onPull(offset, direction); 214b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 215b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void onRelease() { 216b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mEdgeView.onRelease(); 217b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 218b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void onAbsorb(int velocity, int direction) { 219b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mEdgeView.onAbsorb(velocity, direction); 220b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 221b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang }); 222f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mVideoPlayIcon = new ResourceTexture(context, R.drawable.ic_control_play); 223b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = -SCREEN_NAIL_MAX; i <= SCREEN_NAIL_MAX; i++) { 224b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (i == 0) { 225b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPictures.put(i, new FullPicture()); 226cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } else { 227b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPictures.put(i, new ScreenNailPicture(i)); 228cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 229f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 230f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 231f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 232b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void setModel(Model model) { 233b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mModel = model; 234b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mTileView.setModel(mModel); 235f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 236f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 237b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang class MyHandler extends SynchronizedHandler { 238b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public MyHandler(GLRoot root) { 239b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang super(root); 240f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 241f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 242b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 243b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void handleMessage(Message message) { 244b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang switch (message.what) { 245b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang case MSG_CANCEL_EXTRA_SCALING: { 246b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mGestureRecognizer.cancelScale(); 247b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.setExtraScalingRange(false); 248b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mCancelExtraScalingPending = false; 249b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang break; 250b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 251b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang case MSG_SWITCH_FOCUS: { 252b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang switchFocus(); 253b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang break; 254b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 2552c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang case MSG_CAPTURE_ANIMATION_DONE: { 256bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // message.arg1 is the offset parameter passed to 257bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // switchWithCaptureAnimation(). 258bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang captureAnimationDone(message.arg1); 2592c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang break; 2602c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 261b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang default: throw new AssertionError(message.what); 262f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 263f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 264b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang }; 265f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 266b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 267b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Data/Image change notifications 268b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 269b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 270214993dc4abf87c386123af50e3c34184ba11cb6Chih-Chung Chang public void notifyDataChange(int[] fromIndex, int prevBound, int nextBound) { 271c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang mPrevBound = prevBound; 272c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang mNextBound = nextBound; 273c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang 274b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Move the boxes 275214993dc4abf87c386123af50e3c34184ba11cb6Chih-Chung Chang mPositionController.moveBox(fromIndex, mPrevBound < 0, mNextBound > 0, 276bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mModel.isCamera(0)); 277b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 278b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang // Update the ScreenNails. 279b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = -SCREEN_NAIL_MAX; i <= SCREEN_NAIL_MAX; i++) { 280b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPictures.get(i).reload(); 281b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 282b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 283b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang invalidate(); 284f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 285f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 286b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void notifyImageChange(int index) { 287bd7c016d728853d38f98a3c6077b7bd9b08858b9Yuli Huang if (index == 0) { 288bd7c016d728853d38f98a3c6077b7bd9b08858b9Yuli Huang mListener.onCurrentImageUpdated(); 289bd7c016d728853d38f98a3c6077b7bd9b08858b9Yuli Huang } 290b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPictures.get(index).reload(); 291b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang invalidate(); 292f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 293f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 294bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang @Override 2952ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang protected void onLayout( 2962ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang boolean changeSize, int left, int top, int right, int bottom) { 2972ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang int w = right - left; 2982ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang int h = bottom - top; 2992ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang mTileView.layout(0, 0, w, h); 3002ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang mEdgeView.layout(0, 0, w, h); 3012ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang 3022ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang GLRoot root = getGLRoot(); 3032ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang int displayRotation = root.getDisplayRotation(); 3042ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang int compensation = root.getCompensation(); 3052ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang if (mDisplayRotation != displayRotation 3062ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang || mCompensation != compensation) { 3072ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang mDisplayRotation = displayRotation; 3082ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang mCompensation = compensation; 3092ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang 3103b4a8aeb0353fa18a2b5267b3952a80a6c6d4d13Chih-Chung Chang // We need to change the size and rotation of the Camera ScreenNail, 3113b4a8aeb0353fa18a2b5267b3952a80a6c6d4d13Chih-Chung Chang // but we don't want it to animate because the size doen't actually 3122ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang // change in the eye of the user. 3132ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang for (int i = -SCREEN_NAIL_MAX; i <= SCREEN_NAIL_MAX; i++) { 3142ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang Picture p = mPictures.get(i); 3152ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang if (p.isCamera()) { 3162ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang p.updateSize(true); 3172ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang } 318bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 319bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 320bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 321bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang updateConstrainedFrame(); 322bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (changeSize) { 323bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mPositionController.setViewSize(getWidth(), getHeight()); 324bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 325bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 326bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 327bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // Update the constrained frame due to layout change. 328bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private void updateConstrainedFrame() { 3292ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang // Get the width and height in framework orientation because the given 3302ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang // mCameraRelativeFrame is in that coordinates. 331bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang int w = getWidth(); 332bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang int h = getHeight(); 3332ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang if (mCompensation % 180 != 0) { 334bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang int tmp = w; 335bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang w = h; 336bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang h = tmp; 337bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 3382ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang int l = mCameraRelativeFrame.left; 3392ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang int t = mCameraRelativeFrame.top; 3402ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang int r = mCameraRelativeFrame.right; 3412ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang int b = mCameraRelativeFrame.bottom; 342bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 3432ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang // Now convert it to the coordinates we are using. 3442ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang switch (mCompensation) { 345bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang case 0: mCameraRect.set(l, t, r, b); break; 346bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang case 90: mCameraRect.set(h - b, l, h - t, r); break; 347bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang case 180: mCameraRect.set(w - r, h - b, w - l, h - t); break; 348bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang case 270: mCameraRect.set(t, w - r, b, w - l); break; 349bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 350bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 3512ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang Log.d(TAG, "compensation = " + mCompensation 3522ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang + ", CameraRelativeFrame = " + mCameraRelativeFrame 3532ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang + ", mCameraRect = " + mCameraRect); 354bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mPositionController.setConstrainedFrame(mCameraRect); 355bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 356bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 3572ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang public void setCameraRelativeFrame(Rect frame) { 3582ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang mCameraRelativeFrame.set(frame); 3592ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang updateConstrainedFrame(); 360bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 361bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 362bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // Returns the rotation we need to do to the camera texture before drawing 363bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // it to the canvas, assuming the camera texture is correct when the device 364bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // is in its natural orientation. 365bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private int getCameraRotation() { 366bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang return (mCompensation - mDisplayRotation + 360) % 360; 367bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 368bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 36943a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong private int getPanoramaRotation() { 37043a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong return mCompensation; 37143a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong } 37243a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong 373b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 374b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Pictures 375b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 376b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 377b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private interface Picture { 378b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang void reload(); 379b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang void draw(GLCanvas canvas, Rect r); 380b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang void setScreenNail(ScreenNail s); 3812c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang boolean isCamera(); // whether the picture is a camera preview 382bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang void updateSize(boolean force); // called when mCompensation changes 383b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang }; 384f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 385b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang class FullPicture implements Picture { 386b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private int mRotation; 3872c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang private boolean mIsCamera; 38843a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong private boolean mIsPanorama; 389d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang private boolean mIsVideo; 390f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang private int mLoadingState = Model.LOADING_INIT; 391bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private boolean mWasCameraCenter; 392b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 393b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void FullPicture(TileImageView tileView) { 394b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mTileView = tileView; 395f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 396f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 397b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 398b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void reload() { 399b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // mImageWidth and mImageHeight will get updated 400b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mTileView.notifyModelInvalidated(); 401b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 402bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mIsCamera = mModel.isCamera(0); 40343a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong mIsPanorama = mModel.isPanorama(0); 404d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang mIsVideo = mModel.isVideo(0); 405f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang mLoadingState = mModel.getLoadingState(0); 406bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang setScreenNail(mModel.getScreenNail(0)); 407bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang updateSize(false); 408bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 409bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 410bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang @Override 411bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public void updateSize(boolean force) { 41243a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong if (mIsPanorama) { 41343a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong mRotation = getPanoramaRotation(); 41443a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong } else if (mIsCamera) { 415bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mRotation = getCameraRotation(); 416bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } else { 417bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mRotation = mModel.getImageRotation(0); 418bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 419bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 420c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang int w = mTileView.mImageWidth; 421c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang int h = mTileView.mImageHeight; 422c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang mPositionController.setImageSize(0, 423c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang getRotated(mRotation, w, h), 424bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang getRotated(mRotation, h, w), 425bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang force); 426f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 427f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 428b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 429b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void draw(GLCanvas canvas, Rect r) { 430f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang drawTileView(canvas, r); 431cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 432f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang boolean isCenter = mPositionController.isCenter(); 433aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang if (mIsCamera) { 434aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang boolean full = !mFilmMode && isCenter 435aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang && mPositionController.isAtMinimalScale(); 436aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang if (full != mFullScreen) { 437aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang mFullScreen = full; 438aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang mListener.onFullScreenChanged(full); 439aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang } 440aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang } 441aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang 442bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // We want to have the following transitions: 4432c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // (1) Move camera preview out of its place: switch to film mode 4442c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // (2) Move camera preview into its place: switch to page mode 4452c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // The extra mWasCenter check makes sure (1) does not apply if in 4462c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // page mode, we move _to_ the camera preview from another picture. 447bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 448bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // Holdings except touch-down prevent the transitions. 44918958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang if ((mHolding & ~HOLD_TOUCH_DOWN) != 0) return; 450bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 451bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang boolean isCameraCenter = mIsCamera && isCenter; 452bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 453bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (mWasCameraCenter && mIsCamera && !isCenter && !mFilmMode) { 45418958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang // Temporary disabled to de-emphasize filmstrip. 45518958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang // setFilmMode(true); 45618958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang } else if (!mWasCameraCenter && isCameraCenter && mFilmMode) { 457bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang setFilmMode(false); 458aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang } 459aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang 460aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang if (isCenter && !mFilmMode) { 461aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang if (mIsCamera) { 462aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang // move into camera, lock 463aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang mListener.lockOrientation(); // Transition A 464aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang } else { 465aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang // move out of camera, unlock 466aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang mListener.unlockOrientation(); // Transition B 467aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang } 468bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 469bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 470bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mWasCameraCenter = isCameraCenter; 471cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 472cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 473b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 474b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang public void setScreenNail(ScreenNail s) { 475b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang mTileView.setScreenNail(s); 476cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 477f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 478b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 4792c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang public boolean isCamera() { 4802c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang return mIsCamera; 481f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 482f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 483d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang private void drawTileView(GLCanvas canvas, Rect r) { 484ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang float imageScale = mPositionController.getImageScale(); 485b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int viewW = getWidth(); 486b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int viewH = getHeight(); 487d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang float cx = r.exactCenterX(); 488d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang float cy = r.exactCenterY(); 489ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang float scale = 1f; // the scaling factor due to card effect 490b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 491d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang canvas.save(GLCanvas.SAVE_FLAG_MATRIX | GLCanvas.SAVE_FLAG_ALPHA); 492ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang float filmRatio = mPositionController.getFilmRatio(); 493ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang boolean wantsCardEffect = CARD_EFFECT && !mIsCamera 494f320b8429dd5c68c117b8e9b1a36a435f4f4ff13Yuli Huang && filmRatio != 1f && !mPictures.get(-1).isCamera() 495f320b8429dd5c68c117b8e9b1a36a435f4f4ff13Yuli Huang && !mPositionController.inOpeningAnimation(); 4962c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (wantsCardEffect) { 497b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Calculate the move-out progress value. 498b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int left = r.left; 499b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int right = r.right; 500b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang float progress = calculateMoveOutProgress(left, right, viewW); 501b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang progress = Utils.clamp(progress, -1f, 1f); 502b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 503b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // We only want to apply the fading animation if the scrolling 504b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // movement is to the right. 505bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (progress < 0) { 506ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang scale = getScrollScale(progress); 507ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang float alpha = getScrollAlpha(progress); 508ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang scale = interpolate(filmRatio, scale, 1f); 509ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang alpha = interpolate(filmRatio, alpha, 1f); 510d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang 511ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang imageScale *= scale; 512ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang canvas.multiplyAlpha(alpha); 513ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang 514ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang float cxPage; // the cx value in page mode 515d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang if (right - left <= viewW) { 516b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // If the picture is narrower than the view, keep it at 517b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // the center of the view. 518ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang cxPage = viewW / 2f; 519b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } else { 520b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // If the picture is wider than the view (it's 521b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // zoomed-in), keep the left edge of the object align 522b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // the the left edge of the view. 523ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang cxPage = (right - left) * scale / 2f; 524b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 525ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang cx = interpolate(filmRatio, cxPage, cx); 526b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 527b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 528f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 529d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang // Draw the tile view. 530ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang setTileViewPosition(cx, cy, viewW, viewH, imageScale); 531d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang PhotoView.super.render(canvas); 532d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang 533f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang // Draw the play video icon and the message. 534f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang canvas.translate((int) (cx + 0.5f), (int) (cy + 0.5f)); 535f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang int s = (int) (scale * Math.min(r.width(), r.height()) + 0.5f); 536f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang if (mIsVideo) drawVideoPlayIcon(canvas, s); 537f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang if (mLoadingState == Model.LOADING_FAIL) { 538f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang drawLoadingFailMessage(canvas); 539d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang } 540d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang 541f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang // Draw a debug indicator showing which picture has focus (index == 542f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang // 0). 543f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang //canvas.fillRect(-10, -10, 20, 20, 0x80FF00FF); 544f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang 545d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang canvas.restore(); 546d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang } 547d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang 548d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang // Set the position of the tile view 549d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang private void setTileViewPosition(float cx, float cy, 550d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang int viewW, int viewH, float scale) { 551d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang // Find out the bitmap coordinates of the center of the view 552d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang int imageW = mPositionController.getImageWidth(); 553d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang int imageH = mPositionController.getImageHeight(); 554d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang int centerX = (int) (imageW / 2f + (viewW / 2f - cx) / scale + 0.5f); 555d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang int centerY = (int) (imageH / 2f + (viewH / 2f - cy) / scale + 0.5f); 556d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang 557b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int inverseX = imageW - centerX; 558b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int inverseY = imageH - centerY; 559d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang int x, y; 560d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang switch (mRotation) { 561d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang case 0: x = centerX; y = centerY; break; 562d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang case 90: x = centerY; y = inverseX; break; 563d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang case 180: x = inverseX; y = inverseY; break; 564d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang case 270: x = inverseY; y = centerX; break; 565b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang default: 566d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang throw new RuntimeException(String.valueOf(mRotation)); 567b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 568d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang mTileView.setPosition(x, y, scale, mRotation); 569f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 570f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 571f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 572b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private class ScreenNailPicture implements Picture { 573b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private int mIndex; 574b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private int mRotation; 575b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private ScreenNail mScreenNail; 576c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang private Size mSize = new Size(); 5772c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang private boolean mIsCamera; 57843a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong private boolean mIsPanorama; 579d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang private boolean mIsVideo; 580f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang private int mLoadingState = Model.LOADING_INIT; 581f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 582b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public ScreenNailPicture(int index) { 583b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mIndex = index; 584b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 585532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 586b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 587b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void reload() { 588bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mIsCamera = mModel.isCamera(mIndex); 58943a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong mIsPanorama = mModel.isPanorama(mIndex); 590d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang mIsVideo = mModel.isVideo(mIndex); 591f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang mLoadingState = mModel.getLoadingState(mIndex); 592c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang setScreenNail(mModel.getScreenNail(mIndex)); 593b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 594b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 595b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 596b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void draw(GLCanvas canvas, Rect r) { 597b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mScreenNail == null) { 598f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang // Draw a placeholder rectange if there should be a picture in 599f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang // this position (but somehow there isn't). 600c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang if (mIndex >= mPrevBound && mIndex <= mNextBound) { 601f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang drawPlaceHolder(canvas, r); 602c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang } 603b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return; 604f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 605b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (r.left >= getWidth() || r.right <= 0 || 606b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang r.top >= getHeight() || r.bottom <= 0) { 607b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mScreenNail.noDraw(); 608b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return; 609f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 610f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 611bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (mIsCamera && mFullScreen != false) { 612bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mFullScreen = false; 613bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mListener.onFullScreenChanged(false); 614bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 615bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 616ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang float filmRatio = mPositionController.getFilmRatio(); 617ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang boolean wantsCardEffect = CARD_EFFECT && mIndex > 0 618ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang && filmRatio != 1f && !mPictures.get(0).isCamera(); 619b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int w = getWidth(); 620ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang int cx = wantsCardEffect 621ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang ? (int) (interpolate(filmRatio, w / 2, r.centerX()) + 0.5f) 622ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang : r.centerX(); 623b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int cy = r.centerY(); 624ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang canvas.save(GLCanvas.SAVE_FLAG_MATRIX | GLCanvas.SAVE_FLAG_ALPHA); 625b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang canvas.translate(cx, cy); 6262c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (wantsCardEffect) { 627b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang float progress = (float) (w / 2 - r.centerX()) / w; 628b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang progress = Utils.clamp(progress, -1, 1); 629b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang float alpha = getScrollAlpha(progress); 630b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang float scale = getScrollScale(progress); 631ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang alpha = interpolate(filmRatio, alpha, 1f); 632ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang scale = interpolate(filmRatio, scale, 1f); 633b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang canvas.multiplyAlpha(alpha); 634b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang canvas.scale(scale, scale, 1); 635b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 636b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mRotation != 0) { 637b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang canvas.rotate(mRotation, 0, 0, 1); 638b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 639ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang int drawW = getRotated(mRotation, r.width(), r.height()); 640ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang int drawH = getRotated(mRotation, r.height(), r.width()); 641b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mScreenNail.draw(canvas, -drawW / 2, -drawH / 2, drawW, drawH); 642f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang if (isScreenNailAnimating()) { 643f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang invalidate(); 644f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang } 645f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang int s = Math.min(drawW, drawH); 646f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang if (mIsVideo) drawVideoPlayIcon(canvas, s); 647f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang if (mLoadingState == Model.LOADING_FAIL) { 648f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang drawLoadingFailMessage(canvas); 649f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang } 650b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang canvas.restore(); 651b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 652f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 653f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang private boolean isScreenNailAnimating() { 654f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang return (mScreenNail instanceof BitmapScreenNail) 655f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang && ((BitmapScreenNail) mScreenNail).isAnimating(); 656f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang } 657f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang 658b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 659b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang public void setScreenNail(ScreenNail s) { 660b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mScreenNail == s) return; 661b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mScreenNail = s; 662bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang updateSize(false); 663bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 664bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 665bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang @Override 666bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public void updateSize(boolean force) { 66743a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong if (mIsPanorama) { 66843a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong mRotation = getPanoramaRotation(); 66943a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong } else if (mIsCamera) { 670bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mRotation = getCameraRotation(); 671bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } else { 672bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mRotation = mModel.getImageRotation(mIndex); 673bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 674c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang 675c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang int w = 0, h = 0; 676b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mScreenNail != null) { 677bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang w = mScreenNail.getWidth(); 678bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang h = mScreenNail.getHeight(); 679c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang } else if (mModel != null) { 680c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // If we don't have ScreenNail available, we can still try to 681c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // get the size information of it. 682c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang mModel.getImageSize(mIndex, mSize); 683c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang w = mSize.width; 684c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang h = mSize.height; 685b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 686c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang 687c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang if (w != 0 && h != 0) { 688b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.setImageSize(mIndex, 689b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang getRotated(mRotation, w, h), 690bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang getRotated(mRotation, h, w), 691bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang force); 692b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 693f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 694b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 695b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 6962c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang public boolean isCamera() { 6972c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang return mIsCamera; 698b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 699b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 700b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 701f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang // Draw a gray placeholder in the specified rectangle. 702f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang private void drawPlaceHolder(GLCanvas canvas, Rect r) { 703f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang canvas.fillRect(r.left, r.top, r.width(), r.height(), PLACEHOLDER_COLOR); 704f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang } 705f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang 706d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang // Draw the video play icon (in the place where the spinner was) 707d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang private void drawVideoPlayIcon(GLCanvas canvas, int side) { 708d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang int s = side / ICON_RATIO; 709d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang // Draw the video play icon at the center 710d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang mVideoPlayIcon.draw(canvas, -s / 2, -s / 2, s, s); 711d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang } 712d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang 713f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang // Draw the "no thumbnail" message 714f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang private void drawLoadingFailMessage(GLCanvas canvas) { 715f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang StringTexture m = mNoThumbnailText; 716f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang m.draw(canvas, -m.getWidth() / 2, -m.getHeight() / 2); 717f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang } 718f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang 719b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static int getRotated(int degree, int original, int theother) { 720b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return (degree % 180 == 0) ? original : theother; 721b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 722b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 723b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 724b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Gestures Handling 725b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 726b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 727b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 728b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang protected boolean onTouch(MotionEvent event) { 729b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mGestureRecognizer.onTouchEvent(event); 730b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return true; 731f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 732f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 7333a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang private class MyGestureListener implements GestureRecognizer.Listener { 7343a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang private boolean mIgnoreUpEvent = false; 735099989b310d84fe13eff0cdf2902bb3fb0bcbd14Chih-Chung Chang // If we can change mode for this scale gesture. 736099989b310d84fe13eff0cdf2902bb3fb0bcbd14Chih-Chung Chang private boolean mCanChangeMode; 73718958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang // If we have changed the film mode in this scaling gesture. 738b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private boolean mModeChanged; 73933f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang // If this scaling gesture should be ignored. 74033f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang private boolean mIgnoreScalingGesture; 74117ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang // whether the down action happened while the view is scrolling. 74217ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang private boolean mDownInScrolling; 7436575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang // If we should ignore all gestures other than onSingleTapUp. 7446575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang private boolean mIgnoreSwipingGesture; 745b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 7463a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang @Override 7473a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang public boolean onSingleTapUp(float x, float y) { 748ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang // We do this in addition to onUp() because we want the snapback of 749ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang // setFilmMode to happen. 750ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang mHolding &= ~HOLD_TOUCH_DOWN; 751ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang 75217ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang if (mFilmMode && !mDownInScrolling) { 75317ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang switchToHitPicture((int) (x + 0.5f), (int) (y + 0.5f)); 754b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang setFilmMode(false); 75517ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang mIgnoreUpEvent = true; 756b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return true; 757b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 758b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 759bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (mListener != null) { 7602ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang // Do the inverse transform of the touch coordinates. 7612ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang Matrix m = getGLRoot().getCompensationMatrix(); 7622ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang Matrix inv = new Matrix(); 7632ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang m.invert(inv); 7642ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang float[] pts = new float[] {x, y}; 7652ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang inv.mapPoints(pts); 7662ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang mListener.onSingleTapUp((int) (pts[0] + 0.5f), (int) (pts[1] + 0.5f)); 7673a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang } 7683a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang return true; 7693a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang } 7703a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang 7713a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang @Override 7723a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang public boolean onDoubleTap(float x, float y) { 7736575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang if (mIgnoreSwipingGesture) return true; 77461f94714c3702115d2f89bb5f8829697be0c3680Chih-Chung Chang if (mPictures.get(0).isCamera()) return false; 7753a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang PositionController controller = mPositionController; 776b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang float scale = controller.getImageScale(); 7773a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang // onDoubleTap happened on the second ACTION_DOWN. 7783a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang // We need to ignore the next UP event. 7793a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang mIgnoreUpEvent = true; 7803a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang if (scale <= 1.0f || controller.isAtMinimalScale()) { 7813a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang controller.zoomIn(x, y, Math.max(1.5f, scale * 1.5f)); 7823a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang } else { 7833a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang controller.resetToFullView(); 7843a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang } 7853a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang return true; 7863a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang } 787f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 788f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 7893a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang public boolean onScroll(float dx, float dy) { 7906575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang if (mIgnoreSwipingGesture) return true; 791b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.startScroll(-dx, -dy); 792f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return true; 793f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 794f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 795f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 7963a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang public boolean onFling(float velocityX, float velocityY) { 7976575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang if (mIgnoreSwipingGesture) return true; 7982ce3c3bfe08fff5aee58007cc8ba8f4a50861ae2Yuli Huang if (swipeImages(velocityX, velocityY)) { 799b3aab90bb37aa9cc60be32e05678ee55d6575ee8Chih-Chung Chang mIgnoreUpEvent = true; 800b3aab90bb37aa9cc60be32e05678ee55d6575ee8Chih-Chung Chang } else if (mPositionController.fling(velocityX, velocityY)) { 801b3aab90bb37aa9cc60be32e05678ee55d6575ee8Chih-Chung Chang mIgnoreUpEvent = true; 802f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 803f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return true; 804f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 805f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 806f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 8073a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang public boolean onScaleBegin(float focusX, float focusY) { 8086575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang if (mIgnoreSwipingGesture) return true; 80933f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang // We ignore the scaling gesture if it is a camera preview. 81033f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang mIgnoreScalingGesture = mPictures.get(0).isCamera(); 81133f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang if (mIgnoreScalingGesture) { 81233f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang return true; 81333f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang } 8143a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang mPositionController.beginScale(focusX, focusY); 815099989b310d84fe13eff0cdf2902bb3fb0bcbd14Chih-Chung Chang // We can change mode if we are in film mode, or we are in page 816099989b310d84fe13eff0cdf2902bb3fb0bcbd14Chih-Chung Chang // mode and at minimal scale. 817099989b310d84fe13eff0cdf2902bb3fb0bcbd14Chih-Chung Chang mCanChangeMode = mFilmMode 818099989b310d84fe13eff0cdf2902bb3fb0bcbd14Chih-Chung Chang || mPositionController.isAtMinimalScale(); 819b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mModeChanged = false; 820f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return true; 821f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 822f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 823f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 8243a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang public boolean onScale(float focusX, float focusY, float scale) { 8256575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang if (mIgnoreSwipingGesture) return true; 8266575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang if (mIgnoreScalingGesture) return true; 82718958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang if (mModeChanged) return true; 828b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (Float.isNaN(scale) || Float.isInfinite(scale)) return false; 82933f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang 83033f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang // We wait for the scale change accumulated to a large enough change 83133f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang // before reacting to it. Otherwise we may mistakenly treat a 83233f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang // zoom-in gesture as zoom-out or vice versa. 83318958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang if (scale > 0.99f && scale < 1.01f) return false; 83433f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang 835b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int outOfRange = mPositionController.scaleBy(scale, focusX, focusY); 836b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 83718958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang // If mode changes, we treat this scaling gesture has ended. 83818958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang if (mCanChangeMode) { 839b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if ((outOfRange < 0 && !mFilmMode) || 840b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang (outOfRange > 0 && mFilmMode)) { 84118958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang stopExtraScalingIfNeeded(); 84218958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang 84318958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang // Removing the touch down flag allows snapback to happen 84433f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang // for film mode change. 84518958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang mHolding &= ~HOLD_TOUCH_DOWN; 846b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang setFilmMode(!mFilmMode); 84718958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang 84818958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang // We need to call onScaleEnd() before setting mModeChanged 84918958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang // to true. 85018958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang onScaleEnd(); 851b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mModeChanged = true; 852b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return true; 853534b12fd804610dd67b8109bc08ba76f31afb33eChih-Chung Chang } 854b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 855b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 85618958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang if (outOfRange != 0) { 857b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang startExtraScalingIfNeeded(); 858534b12fd804610dd67b8109bc08ba76f31afb33eChih-Chung Chang } else { 859b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang stopExtraScalingIfNeeded(); 860534b12fd804610dd67b8109bc08ba76f31afb33eChih-Chung Chang } 861f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return true; 862f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 863f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 86433f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang @Override 86533f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang public void onScaleEnd() { 8666575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang if (mIgnoreSwipingGesture) return; 8676575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang if (mIgnoreScalingGesture) return; 86833f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang if (mModeChanged) return; 86933f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang mPositionController.endScale(); 87033f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang } 87133f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang 872b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void startExtraScalingIfNeeded() { 873b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (!mCancelExtraScalingPending) { 874b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mHandler.sendEmptyMessageDelayed( 875b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang MSG_CANCEL_EXTRA_SCALING, 700); 876b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.setExtraScalingRange(true); 877b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mCancelExtraScalingPending = true; 878b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 879b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 880b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 881b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void stopExtraScalingIfNeeded() { 882b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mCancelExtraScalingPending) { 883b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mHandler.removeMessages(MSG_CANCEL_EXTRA_SCALING); 884b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.setExtraScalingRange(false); 885b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mCancelExtraScalingPending = false; 886b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 887b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 888b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 889f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 8903a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang public void onDown() { 8916575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang if (mIgnoreSwipingGesture) return; 8926575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang 8932c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mHolding |= HOLD_TOUCH_DOWN; 89417ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang 89517ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang if (mFilmMode && mPositionController.isScrolling()) { 89617ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang mDownInScrolling = true; 89717ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang mPositionController.stopScrolling(); 89817ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang } else { 89917ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang mDownInScrolling = false; 90017ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang } 9013a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang } 9023a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang 9033a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang @Override 9043a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang public void onUp() { 9056575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang if (mIgnoreSwipingGesture) return; 9066575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang 90718958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang mHolding &= ~HOLD_TOUCH_DOWN; 9083a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang mEdgeView.onRelease(); 9093a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang 9103a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang if (mIgnoreUpEvent) { 9113a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang mIgnoreUpEvent = false; 9123a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang return; 9133a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang } 914b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 9152c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang snapback(); 916f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 9176575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang 9186575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang public void setSwipingEnabled(boolean enabled) { 9196575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang mIgnoreSwipingGesture = !enabled; 9206575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang } 9216575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang } 9226575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang 9236575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang public void setSwipingEnabled(boolean enabled) { 9246575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang mGestureListener.setSwipingEnabled(enabled); 925f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 926f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 927b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void setFilmMode(boolean enabled) { 928b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mFilmMode == enabled) return; 929b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mFilmMode = enabled; 930b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.setFilmMode(mFilmMode); 931b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang mModel.setNeedFullImage(!enabled); 93261f94714c3702115d2f89bb5f8829697be0c3680Chih-Chung Chang mListener.onActionBarAllowed(!enabled); 933bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 934bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // If we leave filmstrip mode, we should lock/unlock 935bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (!enabled) { 936bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (mPictures.get(0).isCamera()) { 937bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mListener.lockOrientation(); // Transition C 938bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } else { 939bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mListener.unlockOrientation(); // Transition D 940bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 941bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 942bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 943bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 944bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public boolean getFilmMode() { 945bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang return mFilmMode; 946f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 947f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 948b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 949b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Framework events 950b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 951b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 952b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void pause() { 953b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.skipAnimation(); 954b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mTileView.freeTextures(); 955b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = -SCREEN_NAIL_MAX; i <= SCREEN_NAIL_MAX; i++) { 956b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang mPictures.get(i).setScreenNail(null); 957b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 958f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 959f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 960b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void resume() { 961b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mTileView.prepareTextures(); 962f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 963f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 96433f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang // move to the camera preview and show controls after resume 96533f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang public void resetToFirstPicture() { 96633f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang mModel.moveTo(0); 96733f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang setFilmMode(false); 96833f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang } 96933f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang 970b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 971b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Rendering 972b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 973b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 974b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 975b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang protected void render(GLCanvas canvas) { 976c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang // In page mode, we draw only one previous/next photo. But if we are 977c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang // doing capture animation, we want to draw all photos. 978c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang boolean inPageMode = (mPositionController.getFilmRatio() == 0f); 979c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang boolean inCaptureAnimation = ((mHolding & HOLD_CAPTURE_ANIMATION) != 0); 980c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang boolean drawOneNeighborOnly = inPageMode && !inCaptureAnimation; 981c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang int neighbors = drawOneNeighborOnly ? 1 : SCREEN_NAIL_MAX; 982c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang 983c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang // Draw photos from back to front 984c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang for (int i = neighbors; i >= -neighbors; i--) { 985b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Rect r = mPositionController.getPosition(i); 986b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPictures.get(i).draw(canvas, r); 987b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 988b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 989b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.advanceAnimation(); 990b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang checkFocusSwitching(); 991ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang } 992ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 993b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 994b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Film mode focus switching 995b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 996f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 997b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Runs in GL thread. 998b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void checkFocusSwitching() { 999b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (!mFilmMode) return; 1000b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mHandler.hasMessages(MSG_SWITCH_FOCUS)) return; 1001b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (switchPosition() != 0) { 1002b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mHandler.sendEmptyMessage(MSG_SWITCH_FOCUS); 1003f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1004f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1005f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1006b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Runs in main thread. 1007b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void switchFocus() { 10082c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (mHolding != 0) return; 1009b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang switch (switchPosition()) { 1010b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang case -1: 1011b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang switchToPrevImage(); 1012b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang break; 1013b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang case 1: 1014b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang switchToNextImage(); 1015b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang break; 1016b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1017f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1018f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1019b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Returns -1 if we should switch focus to the previous picture, +1 if we 1020b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // should switch to the next, 0 otherwise. 1021b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private int switchPosition() { 1022b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Rect curr = mPositionController.getPosition(0); 1023b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int center = getWidth() / 2; 1024f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 10252c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (curr.left > center && mPrevBound < 0) { 1026b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Rect prev = mPositionController.getPosition(-1); 1027b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int currDist = curr.left - center; 1028b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int prevDist = center - prev.right; 1029b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (prevDist < currDist) { 1030b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return -1; 1031b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 10322c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } else if (curr.right < center && mNextBound > 0) { 1033b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Rect next = mPositionController.getPosition(1); 1034b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int currDist = center - curr.right; 1035b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int nextDist = next.left - center; 1036b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (nextDist < currDist) { 1037b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return 1; 1038b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1039b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1040f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1041b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return 0; 1042f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1043f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 104417ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang // Switch to the previous or next picture if the hit position is inside 104517ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang // one of their boxes. This runs in main thread. 104617ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang private void switchToHitPicture(int x, int y) { 104717ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang if (mPrevBound < 0) { 104817ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang Rect r = mPositionController.getPosition(-1); 104917ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang if (r.right >= x) { 105017ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang slideToPrevPicture(); 105117ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang return; 105217ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang } 105317ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang } 105417ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang 105517ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang if (mNextBound > 0) { 105617ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang Rect r = mPositionController.getPosition(1); 105717ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang if (r.left <= x) { 105817ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang slideToNextPicture(); 105917ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang return; 106017ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang } 106117ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang } 106217ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang } 106317ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang 1064b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1065b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Page mode focus switching 1066b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // 1067b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // We slide image to the next one or the previous one in two cases: 1: If 1068b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // the user did a fling gesture with enough velocity. 2 If the user has 1069b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // moved the picture a lot. 1070b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1071f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1072b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private boolean swipeImages(float velocityX, float velocityY) { 1073b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mFilmMode) return false; 1074f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1075b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Avoid swiping images if we're possibly flinging to view the 1076b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // zoomed in picture vertically. 1077b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang PositionController controller = mPositionController; 1078b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang boolean isMinimal = controller.isAtMinimalScale(); 1079b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int edges = controller.getImageAtEdges(); 1080b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (!isMinimal && Math.abs(velocityY) > Math.abs(velocityX)) 1081b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if ((edges & PositionController.IMAGE_AT_TOP_EDGE) == 0 1082b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang || (edges & PositionController.IMAGE_AT_BOTTOM_EDGE) == 0) 1083b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return false; 1084f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1085b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // If we are at the edge of the current photo and the sweeping velocity 1086b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // exceeds the threshold, slide to the next / previous image. 1087b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (velocityX < -SWIPE_THRESHOLD && (isMinimal 1088b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang || (edges & PositionController.IMAGE_AT_RIGHT_EDGE) != 0)) { 1089b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return slideToNextPicture(); 1090b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } else if (velocityX > SWIPE_THRESHOLD && (isMinimal 1091b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang || (edges & PositionController.IMAGE_AT_LEFT_EDGE) != 0)) { 1092b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return slideToPrevPicture(); 1093f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1094f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1095b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return false; 1096b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1097b29a27f475a2c449abdda8d4e03d30914feed8c6Chih-Chung Chang 10982c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang private void snapback() { 10992c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (mHolding != 0) return; 11002c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (!snapToNeighborImage()) { 11012c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mPositionController.snapback(); 11022c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 11032c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 11042c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang 1105b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private boolean snapToNeighborImage() { 1106b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mFilmMode) return false; 1107f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1108b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Rect r = mPositionController.getPosition(0); 1109b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int viewW = getWidth(); 1110b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int threshold = MOVE_THRESHOLD + gapToSide(r.width(), viewW); 1111f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1112b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // If we have moved the picture a lot, switching. 1113b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (viewW - r.right > threshold) { 1114b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return slideToNextPicture(); 1115b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } else if (r.left > threshold) { 1116b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return slideToPrevPicture(); 1117f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1118f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1119b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return false; 1120b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1121f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1122b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private boolean slideToNextPicture() { 11232c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (mNextBound <= 0) return false; 1124b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang switchToNextImage(); 11252c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mPositionController.startHorizontalSlide(); 1126b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return true; 1127b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1128676170e619ad59ea97d04e0edcd62b1500304845Chih-Chung Chang 1129b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private boolean slideToPrevPicture() { 11302c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (mPrevBound >= 0) return false; 1131b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang switchToPrevImage(); 11322c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mPositionController.startHorizontalSlide(); 1133b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return true; 1134b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1135676170e619ad59ea97d04e0edcd62b1500304845Chih-Chung Chang 1136b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static int gapToSide(int imageWidth, int viewWidth) { 1137b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return Math.max(0, (viewWidth - imageWidth) / 2); 1138b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1139f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1140b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1141b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Focus switching 1142b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1143f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1144b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void switchToNextImage() { 1145bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mModel.moveTo(mModel.getCurrentIndex() + 1); 1146b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 114715b351a22d02e89d882fc9fe32b3f4c512080e0aChih-Chung Chang 1148b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void switchToPrevImage() { 1149bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mModel.moveTo(mModel.getCurrentIndex() - 1); 1150b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1151cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1152160e6d776daab93610b3d12413ad9ff2dd867d8bChih-Chung Chang private void switchToFirstImage() { 1153bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mModel.moveTo(0); 1154160e6d776daab93610b3d12413ad9ff2dd867d8bChih-Chung Chang } 1155160e6d776daab93610b3d12413ad9ff2dd867d8bChih-Chung Chang 1156b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1157b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Opening Animation 1158b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1159b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1160b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void setOpenAnimationRect(Rect rect) { 1161b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.setOpenAnimationRect(rect); 1162cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 116315b351a22d02e89d882fc9fe32b3f4c512080e0aChih-Chung Chang 1164b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 11652c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // Capture Animation 11662c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang //////////////////////////////////////////////////////////////////////////// 11672c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang 11682c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang public boolean switchWithCaptureAnimation(int offset) { 11692c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang GLRoot root = getGLRoot(); 11702c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang root.lockRenderThread(); 11712c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang try { 11722c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang return switchWithCaptureAnimationLocked(offset); 11732c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } finally { 11742c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang root.unlockRenderThread(); 11752c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 11762c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 11772c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang 11782c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang private boolean switchWithCaptureAnimationLocked(int offset) { 11792c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (mHolding != 0) return true; 11802c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (offset == 1) { 11812c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (mNextBound <= 0) return false; 118261f94714c3702115d2f89bb5f8829697be0c3680Chih-Chung Chang // Temporary disable action bar until the capture animation is done. 118361f94714c3702115d2f89bb5f8829697be0c3680Chih-Chung Chang if (!mFilmMode) mListener.onActionBarAllowed(false); 11842c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang switchToNextImage(); 11852c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mPositionController.startCaptureAnimationSlide(-1); 11862c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } else if (offset == -1) { 11872c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (mPrevBound >= 0) return false; 1188c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang if (mFilmMode) setFilmMode(false); 1189c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang 1190c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang // If we are too far away from the first image (so that we don't 1191c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang // have all the ScreenNails in-between), we go directly without 1192c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang // animation. 1193c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang if (mModel.getCurrentIndex() > SCREEN_NAIL_MAX) { 1194c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang switchToFirstImage(); 1195c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang mPositionController.skipAnimation(); 1196c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang return true; 1197c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang } 1198c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang 1199160e6d776daab93610b3d12413ad9ff2dd867d8bChih-Chung Chang switchToFirstImage(); 12002c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mPositionController.startCaptureAnimationSlide(1); 12012c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } else { 12022c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang return false; 12032c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 12042c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mHolding |= HOLD_CAPTURE_ANIMATION; 1205bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang Message m = mHandler.obtainMessage(MSG_CAPTURE_ANIMATION_DONE, offset, 0); 1206f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang mHandler.sendMessageDelayed(m, PositionController.CAPTURE_ANIMATION_TIME); 12072c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang return true; 12082c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 12092c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang 1210bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private void captureAnimationDone(int offset) { 12112c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mHolding &= ~HOLD_CAPTURE_ANIMATION; 1212bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (offset == 1) { 1213bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // move out of camera, unlock 121461f94714c3702115d2f89bb5f8829697be0c3680Chih-Chung Chang if (!mFilmMode) { 121561f94714c3702115d2f89bb5f8829697be0c3680Chih-Chung Chang // Now the capture animation is done, enable the action bar. 121661f94714c3702115d2f89bb5f8829697be0c3680Chih-Chung Chang mListener.onActionBarAllowed(true); 121761f94714c3702115d2f89bb5f8829697be0c3680Chih-Chung Chang } 1218bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 12192c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang snapback(); 12202c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 12212c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang 12222c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1223b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Card deck effect calculation 1224b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1225b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1226cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // Returns the scrolling progress value for an object moving out of a 1227cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // view. The progress value measures how much the object has moving out of 1228cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // the view. The object currently displays in [left, right), and the view is 1229cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // at [0, viewWidth]. 1230cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // 1231cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // The returned value is negative when the object is moving right, and 1232cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // positive when the object is moving left. The value goes to -1 or 1 when 1233cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // the object just moves out of the view completely. The value is 0 if the 1234cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // object currently fills the view. 1235cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private static float calculateMoveOutProgress(int left, int right, 1236cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang int viewWidth) { 1237cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // w = object width 1238cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // viewWidth = view width 1239cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang int w = right - left; 1240cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1241cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // If the object width is smaller than the view width, 1242cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // |....view....| 1243cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // |<-->| progress = -1 when left = viewWidth 1244bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // |<-->| progress = 0 when left = viewWidth / 2 - w / 2 1245cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // |<-->| progress = 1 when left = -w 1246cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang if (w < viewWidth) { 1247bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang int zx = viewWidth / 2 - w / 2; 1248bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (left > zx) { 1249bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang return -(left - zx) / (float) (viewWidth - zx); // progress = (0, -1] 1250bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } else { 1251bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang return (left - zx) / (float) (-w - zx); // progress = [0, 1] 1252bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 1253cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 1254cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1255cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // If the object width is larger than the view width, 1256cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // |..view..| 1257cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // |<--------->| progress = -1 when left = viewWidth 1258cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // |<--------->| progress = 0 between left = 0 1259cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // |<--------->| and right = viewWidth 1260cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // |<--------->| progress = 1 when right = 0 1261cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang if (left > 0) { 1262cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang return -left / (float) viewWidth; 1263cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 1264cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1265cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang if (right < viewWidth) { 1266cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang return (viewWidth - right) / (float) viewWidth; 1267cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 1268cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1269cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang return 0; 1270cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 1271cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1272cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // Maps a scrolling progress value to the alpha factor in the fading 1273cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // animation. 1274cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private float getScrollAlpha(float scrollProgress) { 1275cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang return scrollProgress < 0 ? mAlphaInterpolator.getInterpolation( 1276cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1 - Math.abs(scrollProgress)) : 1.0f; 1277cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 1278cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1279cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // Maps a scrolling progress value to the scaling factor in the fading 1280cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // animation. 1281cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private float getScrollScale(float scrollProgress) { 1282cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang float interpolatedProgress = mScaleInterpolator.getInterpolation( 1283cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang Math.abs(scrollProgress)); 1284cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang float scale = (1 - interpolatedProgress) + 1285cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang interpolatedProgress * TRANSITION_SCALE_FACTOR; 1286cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang return scale; 1287cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 1288cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1289cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1290cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // This interpolator emulates the rate at which the perceived scale of an 1291cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // object changes as its distance from a camera increases. When this 1292cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // interpolator is applied to a scale animation on a view, it evokes the 1293cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // sense that the object is shrinking due to moving away from the camera. 1294cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private static class ZInterpolator { 1295cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private float focalLength; 1296cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1297cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang public ZInterpolator(float foc) { 1298cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang focalLength = foc; 1299cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 1300cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1301cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang public float getInterpolation(float input) { 1302cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang return (1.0f - focalLength / (focalLength + input)) / 1303cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang (1.0f - focalLength / (focalLength + 1.0f)); 1304f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1305f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1306f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1307ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang // Returns an interpolated value for the page/film transition. 1308ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang // When ratio = 0, the result is from. 1309ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang // When ratio = 1, the result is to. 1310ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang private static float interpolate(float ratio, float from, float to) { 1311ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang return from + (to - from) * ratio * ratio; 1312ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang } 1313ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang 1314b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1315b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Simple public utilities 1316b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1317f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1318bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public void setListener(Listener listener) { 1319bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mListener = listener; 1320f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1321616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin 1322616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin public Rect getPhotoRect(int index) { 1323616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin return mPositionController.getPosition(index); 1324616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin } 1325616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin 1326616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin 1327616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin public PhotoFallbackEffect buildFallbackEffect(GLView root, GLCanvas canvas) { 1328616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin Rect location = new Rect(); 1329616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin Utils.assertTrue(root.getBoundsOf(this, location)); 1330616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin 1331616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin Rect fullRect = bounds(); 1332616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin PhotoFallbackEffect effect = new PhotoFallbackEffect(); 1333616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin for (int i = -SCREEN_NAIL_MAX; i <= SCREEN_NAIL_MAX; ++i) { 1334616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin MediaItem item = mModel.getMediaItem(i); 1335616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin if (item == null) continue; 1336616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin ScreenNail sc = mModel.getScreenNail(i); 133749affdc4e274098a34e4eb2dbe4a89a750f1ba7fOwen Lin if (!(sc instanceof BitmapScreenNail) 133849affdc4e274098a34e4eb2dbe4a89a750f1ba7fOwen Lin || ((BitmapScreenNail) sc).isShowingPlaceholder()) continue; 133949affdc4e274098a34e4eb2dbe4a89a750f1ba7fOwen Lin 134049affdc4e274098a34e4eb2dbe4a89a750f1ba7fOwen Lin // Now, sc is BitmapScreenNail and is not showing placeholder 1341616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin Rect rect = new Rect(getPhotoRect(i)); 1342616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin if (!Rect.intersects(fullRect, rect)) continue; 1343616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin rect.offset(location.left, location.top); 1344616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin 1345616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin RawTexture texture = new RawTexture(sc.getWidth(), sc.getHeight(), true); 1346616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin canvas.beginRenderTarget(texture); 1347616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin sc.draw(canvas, 0, 0, sc.getWidth(), sc.getHeight()); 1348616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin canvas.endRenderTarget(); 1349616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin effect.addEntry(item.getPath(), rect, texture); 1350616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin } 1351616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin return effect; 1352616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin } 1353f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin} 1354