PhotoView.java revision 3b4a8aeb0353fa18a2b5267b3952a80a6c6d4d13
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; 31b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Changimport com.android.gallery3d.data.MediaObject; 32b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Changimport com.android.gallery3d.util.RangeArray; 33b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 34b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Changimport java.util.Arrays; 352b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Lin 36f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpublic class PhotoView extends GLView { 37f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @SuppressWarnings("unused") 38f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final String TAG = "PhotoView"; 39c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang private static final int PLACEHOLDER_COLOR = 0xFF222222; 40f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 41f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static final int INVALID_SIZE = -1; 42b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public static final long INVALID_DATA_VERSION = 43b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang MediaObject.INVALID_DATA_VERSION; 44f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 45c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang public static class Size { 46c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang public int width; 47c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang public int height; 48c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang } 49c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang 50c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang public interface Model extends TileImageView.Model { 51bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public int getCurrentIndex(); 52bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public void moveTo(int index); 53c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang 54c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // Returns the size for the specified picture. If the size information is 55c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // not avaiable, width = height = 0. 56c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang public void getImageSize(int offset, Size size); 57c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang 58c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // Returns the rotation for the specified picture. 59c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang public int getImageRotation(int offset); 60f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 61b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // This amends the getScreenNail() method of TileImageView.Model to get 62b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // ScreenNail at previous (negative offset) or next (positive offset) 63b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // positions. Returns null if the specified ScreenNail is unavailable. 64b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public ScreenNail getScreenNail(int offset); 65c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang 66c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // Set this to true if we need the model to provide full images. 67b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang public void setNeedFullImage(boolean enabled); 68bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 69bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // Returns true if the item is the Camera preview. 70bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public boolean isCamera(int offset); 71d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang 72d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang // Returns true if the item is a Video. 73d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang public boolean isVideo(int offset); 74b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 75b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 76bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public interface Listener { 77b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void onSingleTapUp(int x, int y); 78bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public void lockOrientation(); 79bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public void unlockOrientation(); 80bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public void onFullScreenChanged(boolean full); 8161f94714c3702115d2f89bb5f8829697be0c3680Chih-Chung Chang public void onActionBarAllowed(boolean allowed); 82b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 83f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 84bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // Here is a graph showing the places we need to lock/unlock device 85bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // orientation: 86bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // 87bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // +------------+ A +------------+ 88bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // Page mode | Camera |<---| Photo | 89bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // | [locked] |--->| [unlocked] | 90bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // +------------+ B +------------+ 91bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // ^ ^ 92bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // | C | D 93bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // +------------+ +------------+ 94bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // | Camera | | Photo | 95bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // Film mode | [*] | | [*] | 96bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // +------------+ +------------+ 97bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // 98bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // In Page mode, we want to lock in Camera because we don't want the system 99bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // rotation animation. We also want to unlock in Photo because we want to 100bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // show the system action bar in the right place. 101bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // 102bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // We don't show action bar in Film mode, so it's fine for it to be locked 103bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // or unlocked in Film mode. 104bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // 105bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // There are four transitions we need to check if we need to 106bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // lock/unlock. Marked as A to D above and in the code. 107bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 108b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static final int MSG_SHOW_LOADING = 1; 109b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static final int MSG_CANCEL_EXTRA_SCALING = 2; 110b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static final int MSG_SWITCH_FOCUS = 3; 1112c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang private static final int MSG_CAPTURE_ANIMATION_DONE = 4; 112f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 113b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static final long DELAY_SHOW_LOADING = 250; // 250ms; 114f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 115f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int LOADING_INIT = 0; 116f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int LOADING_TIMEOUT = 1; 117f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int LOADING_COMPLETE = 2; 118f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int LOADING_FAIL = 3; 119f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 120b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static final int MOVE_THRESHOLD = 256; 121f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final float SWIPE_THRESHOLD = 300f; 122f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 123f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final float DEFAULT_TEXT_SIZE = 20; 124cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private static float TRANSITION_SCALE_FACTOR = 0.74f; 125d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang private static final int ICON_RATIO = 6; 1262c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang 1272c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // whether we want to apply card deck effect in page mode. 128b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static final boolean CARD_EFFECT = true; 129cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 130cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // Used to calculate the scaling factor for the fading animation. 131cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private ZInterpolator mScaleInterpolator = new ZInterpolator(0.5f); 132cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 133cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // Used to calculate the alpha factor for the fading animation. 134cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private AccelerateInterpolator mAlphaInterpolator = 135cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang new AccelerateInterpolator(0.9f); 136f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 137b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // We keep this many previous ScreenNails. (also this many next ScreenNails) 138b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public static final int SCREEN_NAIL_MAX = 3; 139b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 140b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // The picture entries, the valid index is from -SCREEN_NAIL_MAX to 141b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // SCREEN_NAIL_MAX. 142b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private final RangeArray<Picture> mPictures = 143b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang new RangeArray<Picture>(-SCREEN_NAIL_MAX, SCREEN_NAIL_MAX); 144f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 145b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private final long mDataVersion[] = new long[2 * SCREEN_NAIL_MAX + 1]; 146b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private final int mFromIndex[] = new int[2 * SCREEN_NAIL_MAX + 1]; 147f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1486575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang private final MyGestureListener mGestureListener; 1493a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang private final GestureRecognizer mGestureRecognizer; 150f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final PositionController mPositionController; 151f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 152bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private Listener mListener; 153f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private Model mModel; 154f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private StringTexture mLoadingText; 155f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private StringTexture mNoThumbnailText; 156b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private TileImageView mTileView; 157532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private EdgeView mEdgeView; 158f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private Texture mVideoPlayIcon; 159f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 160f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private ProgressSpinner mLoadingSpinner; 161f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 162f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private SynchronizedHandler mHandler; 163f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 164f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mLoadingState = LOADING_COMPLETE; 165f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 166cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private Point mImageCenter = new Point(); 167534b12fd804610dd67b8109bc08ba76f31afb33eChih-Chung Chang private boolean mCancelExtraScalingPending; 168b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private boolean mFilmMode = false; 169bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private int mDisplayRotation = 0; 170bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private int mCompensation = 0; 171bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private boolean mFullScreen = true; 1722ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang private Rect mCameraRelativeFrame = new Rect(); 173bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private Rect mCameraRect = new Rect(); 174f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 175c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // [mPrevBound, mNextBound] is the range of index for all pictures in the 176c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // model, if we assume the index of current focused picture is 0. So if 177c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // there are some previous pictures, mPrevBound < 0, and if there are some 178c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // next pictures, mNextBound > 0. 179c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang private int mPrevBound; 180c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang private int mNextBound; 181c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang 1822c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // This variable prevents us doing snapback until its values goes to 0. This 1832c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // happens if the user gesture is still in progress or we are in a capture 1842c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // animation. 1852c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang private int mHolding; 1862c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang private static final int HOLD_TOUCH_DOWN = 1; 18718958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang private static final int HOLD_CAPTURE_ANIMATION = 2; 1882c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang 189f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public PhotoView(GalleryActivity activity) { 190f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mTileView = new TileImageView(activity); 191f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin addComponent(mTileView); 192f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Context context = activity.getAndroidContext(); 193532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mEdgeView = new EdgeView(context); 194532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang addComponent(mEdgeView); 195f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mLoadingSpinner = new ProgressSpinner(context); 196f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mLoadingText = StringTexture.newInstance( 197f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin context.getString(R.string.loading), 198f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin DEFAULT_TEXT_SIZE, Color.WHITE); 199f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mNoThumbnailText = StringTexture.newInstance( 200f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin context.getString(R.string.no_thumbnail), 201f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin DEFAULT_TEXT_SIZE, Color.WHITE); 202f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 203b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mHandler = new MyHandler(activity.getGLRoot()); 204f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 2056575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang mGestureListener = new MyGestureListener(); 2066575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang mGestureRecognizer = new GestureRecognizer(context, mGestureListener); 207f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 208b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController = new PositionController(context, 209b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang new PositionController.Listener() { 210b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void invalidate() { 211b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang PhotoView.this.invalidate(); 212b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 2132c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang public boolean isHolding() { 21418958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang return mHolding != 0; 215b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 216b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void onPull(int offset, int direction) { 217b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mEdgeView.onPull(offset, direction); 218b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 219b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void onRelease() { 220b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mEdgeView.onRelease(); 221b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 222b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void onAbsorb(int velocity, int direction) { 223b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mEdgeView.onAbsorb(velocity, direction); 224b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 225b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang }); 226f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mVideoPlayIcon = new ResourceTexture(context, R.drawable.ic_control_play); 227b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Arrays.fill(mDataVersion, INVALID_DATA_VERSION); 228b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = -SCREEN_NAIL_MAX; i <= SCREEN_NAIL_MAX; i++) { 229b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (i == 0) { 230b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPictures.put(i, new FullPicture()); 231cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } else { 232b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPictures.put(i, new ScreenNailPicture(i)); 233cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 234f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 235f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 236f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 237b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void setModel(Model model) { 238b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mModel = model; 239b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mTileView.setModel(mModel); 240f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 241f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 242b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang class MyHandler extends SynchronizedHandler { 243b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public MyHandler(GLRoot root) { 244b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang super(root); 245f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 246f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 247b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 248b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void handleMessage(Message message) { 249b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang switch (message.what) { 250b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang case MSG_SHOW_LOADING: { 251b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mLoadingState == LOADING_INIT) { 252b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // We don't need the opening animation 253b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.setOpenAnimationRect(null); 254b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 255b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mLoadingSpinner.startAnimation(); 256b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mLoadingState = LOADING_TIMEOUT; 257b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang invalidate(); 258b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 259b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang break; 260f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 261b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang case MSG_CANCEL_EXTRA_SCALING: { 262b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mGestureRecognizer.cancelScale(); 263b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.setExtraScalingRange(false); 264b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mCancelExtraScalingPending = false; 265b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang break; 266b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 267b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang case MSG_SWITCH_FOCUS: { 268b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang switchFocus(); 269b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang break; 270b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 2712c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang case MSG_CAPTURE_ANIMATION_DONE: { 272bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // message.arg1 is the offset parameter passed to 273bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // switchWithCaptureAnimation(). 274bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang captureAnimationDone(message.arg1); 2752c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang break; 2762c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 277b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang default: throw new AssertionError(message.what); 278f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 279f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 280b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang }; 281f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 282f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void updateLoadingState() { 283f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Possible transitions of mLoadingState: 284f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // INIT --> TIMEOUT, COMPLETE, FAIL 285f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // TIMEOUT --> COMPLETE, FAIL, INIT 286f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // COMPLETE --> INIT 287f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // FAIL --> INIT 28815b351a22d02e89d882fc9fe32b3f4c512080e0aChih-Chung Chang if (mModel.getLevelCount() != 0 || mModel.getScreenNail() != null) { 289f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mHandler.removeMessages(MSG_SHOW_LOADING); 290f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mLoadingState = LOADING_COMPLETE; 291f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else if (mModel.isFailedToLoad()) { 292f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mHandler.removeMessages(MSG_SHOW_LOADING); 293f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mLoadingState = LOADING_FAIL; 294a7b78e224b1808895ea2c3d42ae385526dea12aaYuli Huang // We don't want the opening animation after loading failure 295b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.setOpenAnimationRect(null); 296f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else if (mLoadingState != LOADING_INIT) { 297f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mLoadingState = LOADING_INIT; 298f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mHandler.removeMessages(MSG_SHOW_LOADING); 299f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mHandler.sendEmptyMessageDelayed( 300f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin MSG_SHOW_LOADING, DELAY_SHOW_LOADING); 301f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 302f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 303f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 304b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 305b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Data/Image change notifications 306b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 307b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 308c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang public void notifyDataChange(long[] versions, int prevBound, int nextBound) { 309c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang mPrevBound = prevBound; 310c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang mNextBound = nextBound; 311c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang 312b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Check if the data version actually changed. 313b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang boolean changed = false; 314b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int N = 2 * SCREEN_NAIL_MAX + 1; 315b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = 0; i < N; i++) { 316b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (versions[i] != mDataVersion[i]) { 317b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang changed = true; 318b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang break; 319b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 320f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 321b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (!changed) return; 322f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 323b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Create the mFromIndex array, which records the index where the picture 324b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // come from. The value Integer.MAX_VALUE means it's a new picture. 325b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = 0; i < N; i++) { 326b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang long v = versions[i]; 327b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (v == INVALID_DATA_VERSION) { 328b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mFromIndex[i] = Integer.MAX_VALUE; 329b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang continue; 330b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 331f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 332b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Try to find the same version number in the old array 333b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int j; 334b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (j = 0; j < N; j++) { 335b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mDataVersion[j] == v) { 336b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang break; 337b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 338f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 339b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mFromIndex[i] = (j < N) ? j - SCREEN_NAIL_MAX : Integer.MAX_VALUE; 340f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 341b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 342b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Copy the new data version 343b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = 0; i < N; i++) { 344b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mDataVersion[i] = versions[i]; 345b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 346b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 347b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Move the boxes 348bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mPositionController.moveBox(mFromIndex, mPrevBound < 0, mNextBound > 0, 349bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mModel.isCamera(0)); 350b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 351b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang // Update the ScreenNails. 352b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = -SCREEN_NAIL_MAX; i <= SCREEN_NAIL_MAX; i++) { 353b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPictures.get(i).reload(); 354b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 355b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 356b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang invalidate(); 357f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 358f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 359b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void notifyImageChange(int index) { 360b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPictures.get(index).reload(); 361b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang invalidate(); 362f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 363f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 364bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang @Override 3652ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang protected void onLayout( 3662ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang boolean changeSize, int left, int top, int right, int bottom) { 3672ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang int w = right - left; 3682ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang int h = bottom - top; 3692ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang mTileView.layout(0, 0, w, h); 3702ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang mEdgeView.layout(0, 0, w, h); 3712ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang 3722ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang GLRoot root = getGLRoot(); 3732ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang int displayRotation = root.getDisplayRotation(); 3742ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang int compensation = root.getCompensation(); 3752ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang if (mDisplayRotation != displayRotation 3762ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang || mCompensation != compensation) { 3772ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang mDisplayRotation = displayRotation; 3782ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang mCompensation = compensation; 3792ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang 3803b4a8aeb0353fa18a2b5267b3952a80a6c6d4d13Chih-Chung Chang // We need to change the size and rotation of the Camera ScreenNail, 3813b4a8aeb0353fa18a2b5267b3952a80a6c6d4d13Chih-Chung Chang // but we don't want it to animate because the size doen't actually 3822ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang // change in the eye of the user. 3832ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang for (int i = -SCREEN_NAIL_MAX; i <= SCREEN_NAIL_MAX; i++) { 3842ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang Picture p = mPictures.get(i); 3852ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang if (p.isCamera()) { 3862ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang p.updateSize(true); 3872ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang } 388bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 389bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 390bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 391bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang updateConstrainedFrame(); 392bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (changeSize) { 393bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mPositionController.setViewSize(getWidth(), getHeight()); 394bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 395bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 396bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 397bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // Update the constrained frame due to layout change. 398bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private void updateConstrainedFrame() { 3992ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang // Get the width and height in framework orientation because the given 4002ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang // mCameraRelativeFrame is in that coordinates. 401bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang int w = getWidth(); 402bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang int h = getHeight(); 4032ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang if (mCompensation % 180 != 0) { 404bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang int tmp = w; 405bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang w = h; 406bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang h = tmp; 407bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 4082ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang int l = mCameraRelativeFrame.left; 4092ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang int t = mCameraRelativeFrame.top; 4102ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang int r = mCameraRelativeFrame.right; 4112ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang int b = mCameraRelativeFrame.bottom; 412bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 4132ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang // Now convert it to the coordinates we are using. 4142ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang switch (mCompensation) { 415bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang case 0: mCameraRect.set(l, t, r, b); break; 416bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang case 90: mCameraRect.set(h - b, l, h - t, r); break; 417bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang case 180: mCameraRect.set(w - r, h - b, w - l, h - t); break; 418bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang case 270: mCameraRect.set(t, w - r, b, w - l); break; 419bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 420bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 4212ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang Log.d(TAG, "compensation = " + mCompensation 4222ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang + ", CameraRelativeFrame = " + mCameraRelativeFrame 4232ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang + ", mCameraRect = " + mCameraRect); 424bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mPositionController.setConstrainedFrame(mCameraRect); 425bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 426bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 4272ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang public void setCameraRelativeFrame(Rect frame) { 4282ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang mCameraRelativeFrame.set(frame); 4292ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang updateConstrainedFrame(); 430bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 431bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 432bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // Returns the rotation we need to do to the camera texture before drawing 433bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // it to the canvas, assuming the camera texture is correct when the device 434bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // is in its natural orientation. 435bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private int getCameraRotation() { 436bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang return (mCompensation - mDisplayRotation + 360) % 360; 437bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 438bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 439b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 440b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Pictures 441b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 442b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 443b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private interface Picture { 444b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang void reload(); 445b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang void draw(GLCanvas canvas, Rect r); 446b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang void setScreenNail(ScreenNail s); 4472c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang boolean isCamera(); // whether the picture is a camera preview 448bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang void updateSize(boolean force); // called when mCompensation changes 449b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang }; 450f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 451b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang class FullPicture implements Picture { 452b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private int mRotation; 4532c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang private boolean mIsCamera; 454d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang private boolean mIsVideo; 455bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private boolean mWasCameraCenter; 456b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 457b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void FullPicture(TileImageView tileView) { 458b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mTileView = tileView; 459f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 460f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 461b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 462b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void reload() { 463b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // mImageWidth and mImageHeight will get updated 464b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mTileView.notifyModelInvalidated(); 465b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 466bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mIsCamera = mModel.isCamera(0); 467d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang mIsVideo = mModel.isVideo(0); 468bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang setScreenNail(mModel.getScreenNail(0)); 469bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang updateSize(false); 470bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang updateLoadingState(); 471bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 472bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 473bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang @Override 474bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public void updateSize(boolean force) { 475bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (mIsCamera) { 476bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mRotation = getCameraRotation(); 477bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } else { 478bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mRotation = mModel.getImageRotation(0); 479bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 480bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 481c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang int w = mTileView.mImageWidth; 482c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang int h = mTileView.mImageHeight; 483c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang mPositionController.setImageSize(0, 484c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang getRotated(mRotation, w, h), 485bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang getRotated(mRotation, h, w), 486bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang force); 487f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 488f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 489b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 490b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void draw(GLCanvas canvas, Rect r) { 491bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang boolean isCenter = mPositionController.isCenter(); 492bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 493b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mLoadingState == LOADING_COMPLETE) { 494d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang drawTileView(canvas, r); 495b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 496b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang renderMessage(canvas, r.centerX(), r.centerY()); 497cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 498aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang if (mIsCamera) { 499aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang boolean full = !mFilmMode && isCenter 500aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang && mPositionController.isAtMinimalScale(); 501aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang if (full != mFullScreen) { 502aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang mFullScreen = full; 503aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang mListener.onFullScreenChanged(full); 504aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang } 505aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang } 506aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang 507bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // We want to have the following transitions: 5082c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // (1) Move camera preview out of its place: switch to film mode 5092c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // (2) Move camera preview into its place: switch to page mode 5102c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // The extra mWasCenter check makes sure (1) does not apply if in 5112c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // page mode, we move _to_ the camera preview from another picture. 512bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 513bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // Holdings except touch-down prevent the transitions. 51418958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang if ((mHolding & ~HOLD_TOUCH_DOWN) != 0) return; 515bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 516bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang boolean isCameraCenter = mIsCamera && isCenter; 517bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 518bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (mWasCameraCenter && mIsCamera && !isCenter && !mFilmMode) { 51918958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang // Temporary disabled to de-emphasize filmstrip. 52018958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang // setFilmMode(true); 52118958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang } else if (!mWasCameraCenter && isCameraCenter && mFilmMode) { 522bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang setFilmMode(false); 523aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang } 524aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang 525aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang if (isCenter && !mFilmMode) { 526aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang if (mIsCamera) { 527aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang // move into camera, lock 528aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang mListener.lockOrientation(); // Transition A 529aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang } else { 530aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang // move out of camera, unlock 531aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang mListener.unlockOrientation(); // Transition B 532aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang } 533bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 534bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 535bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mWasCameraCenter = isCameraCenter; 536cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 537cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 538b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 539b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang public void setScreenNail(ScreenNail s) { 540b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang mTileView.setScreenNail(s); 541cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 542f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 543b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 5442c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang public boolean isCamera() { 5452c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang return mIsCamera; 546f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 547f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 548d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang private void drawTileView(GLCanvas canvas, Rect r) { 549ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang float imageScale = mPositionController.getImageScale(); 550b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int viewW = getWidth(); 551b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int viewH = getHeight(); 552d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang float cx = r.exactCenterX(); 553d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang float cy = r.exactCenterY(); 554ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang float scale = 1f; // the scaling factor due to card effect 555b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 556d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang canvas.save(GLCanvas.SAVE_FLAG_MATRIX | GLCanvas.SAVE_FLAG_ALPHA); 557ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang float filmRatio = mPositionController.getFilmRatio(); 558ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang boolean wantsCardEffect = CARD_EFFECT && !mIsCamera 559ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang && filmRatio != 1f && !mPictures.get(-1).isCamera(); 5602c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (wantsCardEffect) { 561b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Calculate the move-out progress value. 562b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int left = r.left; 563b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int right = r.right; 564b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang float progress = calculateMoveOutProgress(left, right, viewW); 565b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang progress = Utils.clamp(progress, -1f, 1f); 566b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 567b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // We only want to apply the fading animation if the scrolling 568b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // movement is to the right. 569bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (progress < 0) { 570ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang scale = getScrollScale(progress); 571ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang float alpha = getScrollAlpha(progress); 572ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang scale = interpolate(filmRatio, scale, 1f); 573ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang alpha = interpolate(filmRatio, alpha, 1f); 574d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang 575ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang imageScale *= scale; 576ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang canvas.multiplyAlpha(alpha); 577ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang 578ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang float cxPage; // the cx value in page mode 579d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang if (right - left <= viewW) { 580b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // If the picture is narrower than the view, keep it at 581b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // the center of the view. 582ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang cxPage = viewW / 2f; 583b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } else { 584b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // If the picture is wider than the view (it's 585b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // zoomed-in), keep the left edge of the object align 586b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // the the left edge of the view. 587ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang cxPage = (right - left) * scale / 2f; 588b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 589ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang cx = interpolate(filmRatio, cxPage, cx); 590b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 591b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 592f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 593d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang // Draw the tile view. 594ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang setTileViewPosition(cx, cy, viewW, viewH, imageScale); 595d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang PhotoView.super.render(canvas); 596d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang 597d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang // Draw the play video icon. 598d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang if (mIsVideo) { 599d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang canvas.translate((int) (cx + 0.5f), (int) (cy + 0.5f)); 600ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang int s = (int) (scale * Math.min(r.width(), r.height()) + 0.5f); 601d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang drawVideoPlayIcon(canvas, s); 602d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang } 603d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang 604d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang canvas.restore(); 605d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang } 606d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang 607d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang // Set the position of the tile view 608d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang private void setTileViewPosition(float cx, float cy, 609d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang int viewW, int viewH, float scale) { 610d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang // Find out the bitmap coordinates of the center of the view 611d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang int imageW = mPositionController.getImageWidth(); 612d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang int imageH = mPositionController.getImageHeight(); 613d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang int centerX = (int) (imageW / 2f + (viewW / 2f - cx) / scale + 0.5f); 614d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang int centerY = (int) (imageH / 2f + (viewH / 2f - cy) / scale + 0.5f); 615d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang 616b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int inverseX = imageW - centerX; 617b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int inverseY = imageH - centerY; 618d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang int x, y; 619d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang switch (mRotation) { 620d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang case 0: x = centerX; y = centerY; break; 621d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang case 90: x = centerY; y = inverseX; break; 622d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang case 180: x = inverseX; y = inverseY; break; 623d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang case 270: x = inverseY; y = centerX; break; 624b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang default: 625d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang throw new RuntimeException(String.valueOf(mRotation)); 626b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 627d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang mTileView.setPosition(x, y, scale, mRotation); 628f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 629f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 630b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void renderMessage(GLCanvas canvas, int x, int y) { 631b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Draw the progress spinner and the text below it 632b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // 633b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // (x, y) is where we put the center of the spinner. 634b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // s is the size of the video play icon, and we use s to layout text 635b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // because we want to keep the text at the same place when the video 636b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // play icon is shown instead of the spinner. 637b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int w = getWidth(); 638b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int h = getHeight(); 639d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang int s = Math.min(w, h) / ICON_RATIO; 640b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 641b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mLoadingState == LOADING_TIMEOUT) { 642b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang StringTexture m = mLoadingText; 643b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang ProgressSpinner p = mLoadingSpinner; 644b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang p.draw(canvas, x - p.getWidth() / 2, y - p.getHeight() / 2); 645b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang m.draw(canvas, x - m.getWidth() / 2, y + s / 2 + 5); 646b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang invalidate(); // we need to keep the spinner rotating 647b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } else if (mLoadingState == LOADING_FAIL) { 648b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang StringTexture m = mNoThumbnailText; 649b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang m.draw(canvas, x - m.getWidth() / 2, y + s / 2 + 5); 650b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 651f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 652b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Draw a debug indicator showing which picture has focus (index == 653b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // 0). 654b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // canvas.fillRect(x - 10, y - 10, 20, 20, 0x80FF00FF); 655f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 656f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 657f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 658b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private class ScreenNailPicture implements Picture { 659b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private int mIndex; 660b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private int mRotation; 661b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private ScreenNail mScreenNail; 662c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang private Size mSize = new Size(); 6632c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang private boolean mIsCamera; 664d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang private boolean mIsVideo; 665f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 666b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public ScreenNailPicture(int index) { 667b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mIndex = index; 668b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 669532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 670b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 671b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void reload() { 672bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mIsCamera = mModel.isCamera(mIndex); 673d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang mIsVideo = mModel.isVideo(mIndex); 674c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang setScreenNail(mModel.getScreenNail(mIndex)); 675b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 676b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 677b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 678b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void draw(GLCanvas canvas, Rect r) { 679b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mScreenNail == null) { 680c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // Draw a placeholder rectange if there will be a picture in 681c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // this position. 682c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang if (mIndex >= mPrevBound && mIndex <= mNextBound) { 683c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang canvas.fillRect(r.left, r.top, r.width(), r.height(), 684c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang PLACEHOLDER_COLOR); 685c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang } 686b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return; 687f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 688b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (r.left >= getWidth() || r.right <= 0 || 689b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang r.top >= getHeight() || r.bottom <= 0) { 690b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mScreenNail.noDraw(); 691b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return; 692f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 693f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 694bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (mIsCamera && mFullScreen != false) { 695bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mFullScreen = false; 696bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mListener.onFullScreenChanged(false); 697bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 698bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 699ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang float filmRatio = mPositionController.getFilmRatio(); 700ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang boolean wantsCardEffect = CARD_EFFECT && mIndex > 0 701ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang && filmRatio != 1f && !mPictures.get(0).isCamera(); 702b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int w = getWidth(); 703ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang int cx = wantsCardEffect 704ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang ? (int) (interpolate(filmRatio, w / 2, r.centerX()) + 0.5f) 705ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang : r.centerX(); 706b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int cy = r.centerY(); 707ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang canvas.save(GLCanvas.SAVE_FLAG_MATRIX | GLCanvas.SAVE_FLAG_ALPHA); 708b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang canvas.translate(cx, cy); 7092c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (wantsCardEffect) { 710b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang float progress = (float) (w / 2 - r.centerX()) / w; 711b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang progress = Utils.clamp(progress, -1, 1); 712b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang float alpha = getScrollAlpha(progress); 713b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang float scale = getScrollScale(progress); 714ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang alpha = interpolate(filmRatio, alpha, 1f); 715ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang scale = interpolate(filmRatio, scale, 1f); 716b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang canvas.multiplyAlpha(alpha); 717b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang canvas.scale(scale, scale, 1); 718b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 719b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mRotation != 0) { 720b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang canvas.rotate(mRotation, 0, 0, 1); 721b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 722ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang int drawW = getRotated(mRotation, r.width(), r.height()); 723ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang int drawH = getRotated(mRotation, r.height(), r.width()); 724b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mScreenNail.draw(canvas, -drawW / 2, -drawH / 2, drawW, drawH); 725d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang if (mIsVideo) drawVideoPlayIcon(canvas, Math.min(drawW, drawH)); 726b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang canvas.restore(); 727b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 728f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 729b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 730b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang public void setScreenNail(ScreenNail s) { 731b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mScreenNail == s) return; 732b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mScreenNail = s; 733bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang updateSize(false); 734bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 735bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 736bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang @Override 737bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public void updateSize(boolean force) { 738bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (mIsCamera) { 739bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mRotation = getCameraRotation(); 740bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } else { 741bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mRotation = mModel.getImageRotation(mIndex); 742bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 743c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang 744c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang int w = 0, h = 0; 745b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mScreenNail != null) { 746bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang w = mScreenNail.getWidth(); 747bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang h = mScreenNail.getHeight(); 748c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang } else if (mModel != null) { 749c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // If we don't have ScreenNail available, we can still try to 750c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // get the size information of it. 751c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang mModel.getImageSize(mIndex, mSize); 752c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang w = mSize.width; 753c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang h = mSize.height; 754b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 755c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang 756c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang if (w != 0 && h != 0) { 757b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.setImageSize(mIndex, 758b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang getRotated(mRotation, w, h), 759bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang getRotated(mRotation, h, w), 760bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang force); 761b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 762f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 763b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 764b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 7652c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang public boolean isCamera() { 7662c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang return mIsCamera; 767b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 768b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 769b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 770d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang // Draw the video play icon (in the place where the spinner was) 771d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang private void drawVideoPlayIcon(GLCanvas canvas, int side) { 772d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang int s = side / ICON_RATIO; 773d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang // Draw the video play icon at the center 774d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang mVideoPlayIcon.draw(canvas, -s / 2, -s / 2, s, s); 775d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang } 776d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang 777b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static int getRotated(int degree, int original, int theother) { 778b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return (degree % 180 == 0) ? original : theother; 779b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 780b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 781b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 782b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Gestures Handling 783b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 784b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 785b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 786b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang protected boolean onTouch(MotionEvent event) { 787b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mGestureRecognizer.onTouchEvent(event); 788b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return true; 789f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 790f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 7913a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang private class MyGestureListener implements GestureRecognizer.Listener { 7923a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang private boolean mIgnoreUpEvent = false; 793099989b310d84fe13eff0cdf2902bb3fb0bcbd14Chih-Chung Chang // If we can change mode for this scale gesture. 794099989b310d84fe13eff0cdf2902bb3fb0bcbd14Chih-Chung Chang private boolean mCanChangeMode; 79518958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang // If we have changed the film mode in this scaling gesture. 796b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private boolean mModeChanged; 79733f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang // If this scaling gesture should be ignored. 79833f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang private boolean mIgnoreScalingGesture; 79917ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang // whether the down action happened while the view is scrolling. 80017ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang private boolean mDownInScrolling; 8016575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang // If we should ignore all gestures other than onSingleTapUp. 8026575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang private boolean mIgnoreSwipingGesture; 803b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 8043a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang @Override 8053a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang public boolean onSingleTapUp(float x, float y) { 806ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang // We do this in addition to onUp() because we want the snapback of 807ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang // setFilmMode to happen. 808ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang mHolding &= ~HOLD_TOUCH_DOWN; 809ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang 81017ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang if (mFilmMode && !mDownInScrolling) { 81117ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang switchToHitPicture((int) (x + 0.5f), (int) (y + 0.5f)); 812b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang setFilmMode(false); 81317ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang mIgnoreUpEvent = true; 814b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return true; 815b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 816b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 817bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (mListener != null) { 8182ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang // Do the inverse transform of the touch coordinates. 8192ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang Matrix m = getGLRoot().getCompensationMatrix(); 8202ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang Matrix inv = new Matrix(); 8212ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang m.invert(inv); 8222ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang float[] pts = new float[] {x, y}; 8232ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang inv.mapPoints(pts); 8242ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang mListener.onSingleTapUp((int) (pts[0] + 0.5f), (int) (pts[1] + 0.5f)); 8253a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang } 8263a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang return true; 8273a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang } 8283a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang 8293a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang @Override 8303a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang public boolean onDoubleTap(float x, float y) { 8316575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang if (mIgnoreSwipingGesture) return true; 83261f94714c3702115d2f89bb5f8829697be0c3680Chih-Chung Chang if (mPictures.get(0).isCamera()) return false; 8333a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang PositionController controller = mPositionController; 834b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang float scale = controller.getImageScale(); 8353a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang // onDoubleTap happened on the second ACTION_DOWN. 8363a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang // We need to ignore the next UP event. 8373a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang mIgnoreUpEvent = true; 8383a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang if (scale <= 1.0f || controller.isAtMinimalScale()) { 8393a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang controller.zoomIn(x, y, Math.max(1.5f, scale * 1.5f)); 8403a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang } else { 8413a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang controller.resetToFullView(); 8423a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang } 8433a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang return true; 8443a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang } 845f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 846f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 8473a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang public boolean onScroll(float dx, float dy) { 8486575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang if (mIgnoreSwipingGesture) return true; 849b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.startScroll(-dx, -dy); 850f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return true; 851f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 852f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 853f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 8543a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang public boolean onFling(float velocityX, float velocityY) { 8556575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang if (mIgnoreSwipingGesture) return true; 8562ce3c3bfe08fff5aee58007cc8ba8f4a50861ae2Yuli Huang if (swipeImages(velocityX, velocityY)) { 857b3aab90bb37aa9cc60be32e05678ee55d6575ee8Chih-Chung Chang mIgnoreUpEvent = true; 858b3aab90bb37aa9cc60be32e05678ee55d6575ee8Chih-Chung Chang } else if (mPositionController.fling(velocityX, velocityY)) { 859b3aab90bb37aa9cc60be32e05678ee55d6575ee8Chih-Chung Chang mIgnoreUpEvent = true; 860f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 861f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return true; 862f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 863f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 864f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 8653a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang public boolean onScaleBegin(float focusX, float focusY) { 8666575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang if (mIgnoreSwipingGesture) return true; 86733f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang // We ignore the scaling gesture if it is a camera preview. 86833f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang mIgnoreScalingGesture = mPictures.get(0).isCamera(); 86933f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang if (mIgnoreScalingGesture) { 87033f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang return true; 87133f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang } 8723a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang mPositionController.beginScale(focusX, focusY); 873099989b310d84fe13eff0cdf2902bb3fb0bcbd14Chih-Chung Chang // We can change mode if we are in film mode, or we are in page 874099989b310d84fe13eff0cdf2902bb3fb0bcbd14Chih-Chung Chang // mode and at minimal scale. 875099989b310d84fe13eff0cdf2902bb3fb0bcbd14Chih-Chung Chang mCanChangeMode = mFilmMode 876099989b310d84fe13eff0cdf2902bb3fb0bcbd14Chih-Chung Chang || mPositionController.isAtMinimalScale(); 877b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mModeChanged = false; 878f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return true; 879f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 880f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 881f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 8823a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang public boolean onScale(float focusX, float focusY, float scale) { 8836575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang if (mIgnoreSwipingGesture) return true; 8846575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang if (mIgnoreScalingGesture) return true; 88518958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang if (mModeChanged) return true; 886b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (Float.isNaN(scale) || Float.isInfinite(scale)) return false; 88733f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang 88833f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang // We wait for the scale change accumulated to a large enough change 88933f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang // before reacting to it. Otherwise we may mistakenly treat a 89033f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang // zoom-in gesture as zoom-out or vice versa. 89118958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang if (scale > 0.99f && scale < 1.01f) return false; 89233f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang 893b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int outOfRange = mPositionController.scaleBy(scale, focusX, focusY); 894b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 89518958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang // If mode changes, we treat this scaling gesture has ended. 89618958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang if (mCanChangeMode) { 897b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if ((outOfRange < 0 && !mFilmMode) || 898b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang (outOfRange > 0 && mFilmMode)) { 89918958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang stopExtraScalingIfNeeded(); 90018958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang 90118958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang // Removing the touch down flag allows snapback to happen 90233f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang // for film mode change. 90318958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang mHolding &= ~HOLD_TOUCH_DOWN; 904b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang setFilmMode(!mFilmMode); 90518958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang 90618958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang // We need to call onScaleEnd() before setting mModeChanged 90718958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang // to true. 90818958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang onScaleEnd(); 909b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mModeChanged = true; 910b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return true; 911534b12fd804610dd67b8109bc08ba76f31afb33eChih-Chung Chang } 912b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 913b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 91418958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang if (outOfRange != 0) { 915b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang startExtraScalingIfNeeded(); 916534b12fd804610dd67b8109bc08ba76f31afb33eChih-Chung Chang } else { 917b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang stopExtraScalingIfNeeded(); 918534b12fd804610dd67b8109bc08ba76f31afb33eChih-Chung Chang } 919f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return true; 920f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 921f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 92233f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang @Override 92333f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang public void onScaleEnd() { 9246575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang if (mIgnoreSwipingGesture) return; 9256575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang if (mIgnoreScalingGesture) return; 92633f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang if (mModeChanged) return; 92733f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang mPositionController.endScale(); 92833f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang } 92933f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang 930b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void startExtraScalingIfNeeded() { 931b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (!mCancelExtraScalingPending) { 932b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mHandler.sendEmptyMessageDelayed( 933b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang MSG_CANCEL_EXTRA_SCALING, 700); 934b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.setExtraScalingRange(true); 935b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mCancelExtraScalingPending = true; 936b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 937b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 938b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 939b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void stopExtraScalingIfNeeded() { 940b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mCancelExtraScalingPending) { 941b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mHandler.removeMessages(MSG_CANCEL_EXTRA_SCALING); 942b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.setExtraScalingRange(false); 943b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mCancelExtraScalingPending = false; 944b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 945b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 946b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 947f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 9483a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang public void onDown() { 9496575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang if (mIgnoreSwipingGesture) return; 9506575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang 9512c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mHolding |= HOLD_TOUCH_DOWN; 95217ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang 95317ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang if (mFilmMode && mPositionController.isScrolling()) { 95417ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang mDownInScrolling = true; 95517ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang mPositionController.stopScrolling(); 95617ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang } else { 95717ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang mDownInScrolling = false; 95817ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang } 9593a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang } 9603a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang 9613a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang @Override 9623a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang public void onUp() { 9636575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang if (mIgnoreSwipingGesture) return; 9646575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang 96518958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang mHolding &= ~HOLD_TOUCH_DOWN; 9663a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang mEdgeView.onRelease(); 9673a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang 9683a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang if (mIgnoreUpEvent) { 9693a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang mIgnoreUpEvent = false; 9703a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang return; 9713a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang } 972b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 9732c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang snapback(); 974f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 9756575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang 9766575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang public void setSwipingEnabled(boolean enabled) { 9776575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang mIgnoreSwipingGesture = !enabled; 9786575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang } 9796575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang } 9806575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang 9816575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang public void setSwipingEnabled(boolean enabled) { 9826575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang mGestureListener.setSwipingEnabled(enabled); 983f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 984f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 985b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void setFilmMode(boolean enabled) { 986b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mFilmMode == enabled) return; 987b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mFilmMode = enabled; 988b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.setFilmMode(mFilmMode); 989b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang mModel.setNeedFullImage(!enabled); 99061f94714c3702115d2f89bb5f8829697be0c3680Chih-Chung Chang mListener.onActionBarAllowed(!enabled); 991bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 992bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // If we leave filmstrip mode, we should lock/unlock 993bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (!enabled) { 994bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (mPictures.get(0).isCamera()) { 995bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mListener.lockOrientation(); // Transition C 996bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } else { 997bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mListener.unlockOrientation(); // Transition D 998bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 999bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 1000bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 1001bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 1002bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public boolean getFilmMode() { 1003bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang return mFilmMode; 1004f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1005f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1006b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1007b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Framework events 1008b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1009b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1010b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void pause() { 1011b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.skipAnimation(); 1012b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mTileView.freeTextures(); 1013b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = -SCREEN_NAIL_MAX; i <= SCREEN_NAIL_MAX; i++) { 1014b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang mPictures.get(i).setScreenNail(null); 1015b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1016f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1017f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1018b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void resume() { 1019b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mTileView.prepareTextures(); 1020f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1021f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 102233f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang // move to the camera preview and show controls after resume 102333f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang public void resetToFirstPicture() { 102433f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang mModel.moveTo(0); 102533f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang setFilmMode(false); 102633f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang } 102733f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang 1028b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1029b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Rendering 1030b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1031b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1032b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 1033b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang protected void render(GLCanvas canvas) { 1034ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang float filmRatio = mPositionController.getFilmRatio(); 1035ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang 1036ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang // Draw next photos. In page mode, we draw only one next photo. 1037ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang int lastPhoto = (filmRatio == 0f) ? 1 : SCREEN_NAIL_MAX; 1038ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang for (int i = lastPhoto; i > 0; i--) { 1039b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Rect r = mPositionController.getPosition(i); 1040b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPictures.get(i).draw(canvas, r); 1041b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1042b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1043b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Draw current photo 1044b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPictures.get(0).draw(canvas, mPositionController.getPosition(0)); 1045b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1046ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang // Draw previous photos. In page mode, we draw only one previous photo. 1047ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang lastPhoto = (filmRatio == 0f) ? -1: -SCREEN_NAIL_MAX; 1048ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang for (int i = -1; i >= lastPhoto; i--) { 1049b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Rect r = mPositionController.getPosition(i); 1050b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPictures.get(i).draw(canvas, r); 1051b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1052b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1053b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.advanceAnimation(); 1054b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang checkFocusSwitching(); 1055ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang } 1056ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 1057b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1058b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Film mode focus switching 1059b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1060f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1061b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Runs in GL thread. 1062b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void checkFocusSwitching() { 1063b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (!mFilmMode) return; 1064b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mHandler.hasMessages(MSG_SWITCH_FOCUS)) return; 1065b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (switchPosition() != 0) { 1066b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mHandler.sendEmptyMessage(MSG_SWITCH_FOCUS); 1067f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1068f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1069f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1070b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Runs in main thread. 1071b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void switchFocus() { 10722c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (mHolding != 0) return; 1073b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang switch (switchPosition()) { 1074b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang case -1: 1075b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang switchToPrevImage(); 1076b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang break; 1077b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang case 1: 1078b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang switchToNextImage(); 1079b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang break; 1080b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1081f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1082f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1083b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Returns -1 if we should switch focus to the previous picture, +1 if we 1084b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // should switch to the next, 0 otherwise. 1085b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private int switchPosition() { 1086b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Rect curr = mPositionController.getPosition(0); 1087b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int center = getWidth() / 2; 1088f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 10892c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (curr.left > center && mPrevBound < 0) { 1090b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Rect prev = mPositionController.getPosition(-1); 1091b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int currDist = curr.left - center; 1092b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int prevDist = center - prev.right; 1093b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (prevDist < currDist) { 1094b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return -1; 1095b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 10962c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } else if (curr.right < center && mNextBound > 0) { 1097b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Rect next = mPositionController.getPosition(1); 1098b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int currDist = center - curr.right; 1099b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int nextDist = next.left - center; 1100b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (nextDist < currDist) { 1101b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return 1; 1102b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1103b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1104f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1105b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return 0; 1106f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1107f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 110817ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang // Switch to the previous or next picture if the hit position is inside 110917ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang // one of their boxes. This runs in main thread. 111017ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang private void switchToHitPicture(int x, int y) { 111117ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang if (mPrevBound < 0) { 111217ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang Rect r = mPositionController.getPosition(-1); 111317ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang if (r.right >= x) { 111417ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang slideToPrevPicture(); 111517ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang return; 111617ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang } 111717ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang } 111817ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang 111917ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang if (mNextBound > 0) { 112017ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang Rect r = mPositionController.getPosition(1); 112117ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang if (r.left <= x) { 112217ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang slideToNextPicture(); 112317ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang return; 112417ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang } 112517ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang } 112617ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang } 112717ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang 1128b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1129b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Page mode focus switching 1130b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // 1131b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // We slide image to the next one or the previous one in two cases: 1: If 1132b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // the user did a fling gesture with enough velocity. 2 If the user has 1133b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // moved the picture a lot. 1134b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1135f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1136b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private boolean swipeImages(float velocityX, float velocityY) { 1137b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mFilmMode) return false; 1138f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1139b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Avoid swiping images if we're possibly flinging to view the 1140b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // zoomed in picture vertically. 1141b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang PositionController controller = mPositionController; 1142b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang boolean isMinimal = controller.isAtMinimalScale(); 1143b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int edges = controller.getImageAtEdges(); 1144b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (!isMinimal && Math.abs(velocityY) > Math.abs(velocityX)) 1145b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if ((edges & PositionController.IMAGE_AT_TOP_EDGE) == 0 1146b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang || (edges & PositionController.IMAGE_AT_BOTTOM_EDGE) == 0) 1147b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return false; 1148f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1149b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // If we are at the edge of the current photo and the sweeping velocity 1150b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // exceeds the threshold, slide to the next / previous image. 1151b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (velocityX < -SWIPE_THRESHOLD && (isMinimal 1152b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang || (edges & PositionController.IMAGE_AT_RIGHT_EDGE) != 0)) { 1153b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return slideToNextPicture(); 1154b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } else if (velocityX > SWIPE_THRESHOLD && (isMinimal 1155b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang || (edges & PositionController.IMAGE_AT_LEFT_EDGE) != 0)) { 1156b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return slideToPrevPicture(); 1157f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1158f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1159b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return false; 1160b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1161b29a27f475a2c449abdda8d4e03d30914feed8c6Chih-Chung Chang 11622c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang private void snapback() { 11632c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (mHolding != 0) return; 11642c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (!snapToNeighborImage()) { 11652c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mPositionController.snapback(); 11662c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 11672c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 11682c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang 1169b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private boolean snapToNeighborImage() { 1170b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mFilmMode) return false; 1171f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1172b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Rect r = mPositionController.getPosition(0); 1173b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int viewW = getWidth(); 1174b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int threshold = MOVE_THRESHOLD + gapToSide(r.width(), viewW); 1175f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1176b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // If we have moved the picture a lot, switching. 1177b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (viewW - r.right > threshold) { 1178b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return slideToNextPicture(); 1179b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } else if (r.left > threshold) { 1180b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return slideToPrevPicture(); 1181f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1182f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1183b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return false; 1184b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1185f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1186b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private boolean slideToNextPicture() { 11872c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (mNextBound <= 0) return false; 1188b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang switchToNextImage(); 11892c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mPositionController.startHorizontalSlide(); 1190b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return true; 1191b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1192676170e619ad59ea97d04e0edcd62b1500304845Chih-Chung Chang 1193b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private boolean slideToPrevPicture() { 11942c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (mPrevBound >= 0) return false; 1195b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang switchToPrevImage(); 11962c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mPositionController.startHorizontalSlide(); 1197b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return true; 1198b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1199676170e619ad59ea97d04e0edcd62b1500304845Chih-Chung Chang 1200b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static int gapToSide(int imageWidth, int viewWidth) { 1201b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return Math.max(0, (viewWidth - imageWidth) / 2); 1202b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1203f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1204b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1205b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Focus switching 1206b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1207f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1208b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void switchToNextImage() { 1209bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mModel.moveTo(mModel.getCurrentIndex() + 1); 1210b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 121115b351a22d02e89d882fc9fe32b3f4c512080e0aChih-Chung Chang 1212b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void switchToPrevImage() { 1213bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mModel.moveTo(mModel.getCurrentIndex() - 1); 1214b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1215cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1216160e6d776daab93610b3d12413ad9ff2dd867d8bChih-Chung Chang private void switchToFirstImage() { 1217bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mModel.moveTo(0); 1218160e6d776daab93610b3d12413ad9ff2dd867d8bChih-Chung Chang } 1219160e6d776daab93610b3d12413ad9ff2dd867d8bChih-Chung Chang 1220b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1221b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Opening Animation 1222b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1223b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1224b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void setOpenAnimationRect(Rect rect) { 1225b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.setOpenAnimationRect(rect); 1226cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 122715b351a22d02e89d882fc9fe32b3f4c512080e0aChih-Chung Chang 1228b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 12292c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // Capture Animation 12302c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang //////////////////////////////////////////////////////////////////////////// 12312c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang 12322c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang public boolean switchWithCaptureAnimation(int offset) { 12332c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang GLRoot root = getGLRoot(); 12342c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang root.lockRenderThread(); 12352c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang try { 12362c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang return switchWithCaptureAnimationLocked(offset); 12372c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } finally { 12382c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang root.unlockRenderThread(); 12392c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 12402c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 12412c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang 12422c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang private boolean switchWithCaptureAnimationLocked(int offset) { 12432c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (mHolding != 0) return true; 12442c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (offset == 1) { 12452c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (mNextBound <= 0) return false; 124661f94714c3702115d2f89bb5f8829697be0c3680Chih-Chung Chang // Temporary disable action bar until the capture animation is done. 124761f94714c3702115d2f89bb5f8829697be0c3680Chih-Chung Chang if (!mFilmMode) mListener.onActionBarAllowed(false); 12482c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang switchToNextImage(); 12492c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mPositionController.startCaptureAnimationSlide(-1); 12502c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } else if (offset == -1) { 12512c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (mPrevBound >= 0) return false; 1252160e6d776daab93610b3d12413ad9ff2dd867d8bChih-Chung Chang switchToFirstImage(); 12532c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mPositionController.startCaptureAnimationSlide(1); 12542c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } else { 12552c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang return false; 12562c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 12572c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mHolding |= HOLD_CAPTURE_ANIMATION; 1258bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang Message m = mHandler.obtainMessage(MSG_CAPTURE_ANIMATION_DONE, offset, 0); 1259bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mHandler.sendMessageDelayed(m, 800); 12602c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang return true; 12612c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 12622c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang 1263bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private void captureAnimationDone(int offset) { 12642c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mHolding &= ~HOLD_CAPTURE_ANIMATION; 1265bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (offset == 1) { 1266bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // move out of camera, unlock 126761f94714c3702115d2f89bb5f8829697be0c3680Chih-Chung Chang if (!mFilmMode) { 126861f94714c3702115d2f89bb5f8829697be0c3680Chih-Chung Chang // Now the capture animation is done, enable the action bar. 126961f94714c3702115d2f89bb5f8829697be0c3680Chih-Chung Chang mListener.onActionBarAllowed(true); 127061f94714c3702115d2f89bb5f8829697be0c3680Chih-Chung Chang } 1271bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 12722c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang snapback(); 12732c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 12742c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang 12752c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1276b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Card deck effect calculation 1277b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1278b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1279cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // Returns the scrolling progress value for an object moving out of a 1280cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // view. The progress value measures how much the object has moving out of 1281cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // the view. The object currently displays in [left, right), and the view is 1282cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // at [0, viewWidth]. 1283cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // 1284cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // The returned value is negative when the object is moving right, and 1285cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // positive when the object is moving left. The value goes to -1 or 1 when 1286cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // the object just moves out of the view completely. The value is 0 if the 1287cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // object currently fills the view. 1288cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private static float calculateMoveOutProgress(int left, int right, 1289cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang int viewWidth) { 1290cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // w = object width 1291cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // viewWidth = view width 1292cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang int w = right - left; 1293cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1294cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // If the object width is smaller than the view width, 1295cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // |....view....| 1296cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // |<-->| progress = -1 when left = viewWidth 1297bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // |<-->| progress = 0 when left = viewWidth / 2 - w / 2 1298cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // |<-->| progress = 1 when left = -w 1299cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang if (w < viewWidth) { 1300bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang int zx = viewWidth / 2 - w / 2; 1301bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (left > zx) { 1302bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang return -(left - zx) / (float) (viewWidth - zx); // progress = (0, -1] 1303bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } else { 1304bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang return (left - zx) / (float) (-w - zx); // progress = [0, 1] 1305bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 1306cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 1307cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1308cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // If the object width is larger than the view width, 1309cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // |..view..| 1310cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // |<--------->| progress = -1 when left = viewWidth 1311cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // |<--------->| progress = 0 between left = 0 1312cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // |<--------->| and right = viewWidth 1313cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // |<--------->| progress = 1 when right = 0 1314cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang if (left > 0) { 1315cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang return -left / (float) viewWidth; 1316cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 1317cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1318cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang if (right < viewWidth) { 1319cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang return (viewWidth - right) / (float) viewWidth; 1320cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 1321cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1322cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang return 0; 1323cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 1324cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1325cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // Maps a scrolling progress value to the alpha factor in the fading 1326cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // animation. 1327cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private float getScrollAlpha(float scrollProgress) { 1328cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang return scrollProgress < 0 ? mAlphaInterpolator.getInterpolation( 1329cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1 - Math.abs(scrollProgress)) : 1.0f; 1330cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 1331cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1332cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // Maps a scrolling progress value to the scaling factor in the fading 1333cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // animation. 1334cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private float getScrollScale(float scrollProgress) { 1335cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang float interpolatedProgress = mScaleInterpolator.getInterpolation( 1336cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang Math.abs(scrollProgress)); 1337cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang float scale = (1 - interpolatedProgress) + 1338cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang interpolatedProgress * TRANSITION_SCALE_FACTOR; 1339cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang return scale; 1340cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 1341cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1342cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1343cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // This interpolator emulates the rate at which the perceived scale of an 1344cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // object changes as its distance from a camera increases. When this 1345cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // interpolator is applied to a scale animation on a view, it evokes the 1346cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // sense that the object is shrinking due to moving away from the camera. 1347cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private static class ZInterpolator { 1348cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private float focalLength; 1349cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1350cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang public ZInterpolator(float foc) { 1351cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang focalLength = foc; 1352cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 1353cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1354cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang public float getInterpolation(float input) { 1355cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang return (1.0f - focalLength / (focalLength + input)) / 1356cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang (1.0f - focalLength / (focalLength + 1.0f)); 1357f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1358f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1359f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1360ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang // Returns an interpolated value for the page/film transition. 1361ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang // When ratio = 0, the result is from. 1362ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang // When ratio = 1, the result is to. 1363ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang private static float interpolate(float ratio, float from, float to) { 1364ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang return from + (to - from) * ratio * ratio; 1365ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang } 1366ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang 1367b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1368b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Simple public utilities 1369b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1370f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1371bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public void setListener(Listener listener) { 1372bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mListener = listener; 1373f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1374f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin} 1375