PhotoView.java revision dbb6acc204ba6f095eb0e49e1298e9ceda2c3096
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; 256b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Changimport android.util.FloatMath; 26f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.view.MotionEvent; 276b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Changimport android.view.View.MeasureSpec; 28cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Changimport android.view.animation.AccelerateInterpolator; 29f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 302b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Linimport com.android.gallery3d.R; 312b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Linimport com.android.gallery3d.app.GalleryActivity; 32cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Changimport com.android.gallery3d.common.Utils; 33616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Linimport com.android.gallery3d.data.MediaItem; 34b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Changimport com.android.gallery3d.data.MediaObject; 356b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Changimport com.android.gallery3d.data.Path; 366b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Changimport com.android.gallery3d.util.GalleryUtils; 37b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Changimport com.android.gallery3d.util.RangeArray; 38b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 39f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpublic class PhotoView extends GLView { 40f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @SuppressWarnings("unused") 41f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final String TAG = "PhotoView"; 42c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang private static final int PLACEHOLDER_COLOR = 0xFF222222; 43f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 44f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static final int INVALID_SIZE = -1; 45b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public static final long INVALID_DATA_VERSION = 46b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang MediaObject.INVALID_DATA_VERSION; 47f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 48c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang public static class Size { 49c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang public int width; 50c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang public int height; 51c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang } 52c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang 53c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang public interface Model extends TileImageView.Model { 54bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public int getCurrentIndex(); 55bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public void moveTo(int index); 56c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang 57c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // Returns the size for the specified picture. If the size information is 58c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // not avaiable, width = height = 0. 59c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang public void getImageSize(int offset, Size size); 60c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang 61616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin // Returns the media item for the specified picture. 62616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin public MediaItem getMediaItem(int offset); 63616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin 64c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // Returns the rotation for the specified picture. 65c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang public int getImageRotation(int offset); 66f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 67b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // This amends the getScreenNail() method of TileImageView.Model to get 68b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // ScreenNail at previous (negative offset) or next (positive offset) 69b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // positions. Returns null if the specified ScreenNail is unavailable. 70b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public ScreenNail getScreenNail(int offset); 71c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang 72c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // Set this to true if we need the model to provide full images. 73b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang public void setNeedFullImage(boolean enabled); 74bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 75bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // Returns true if the item is the Camera preview. 76bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public boolean isCamera(int offset); 77d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang 7843a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong // Returns true if the item is the Panorama. 7943a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong public boolean isPanorama(int offset); 8043a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong 81dbb6acc204ba6f095eb0e49e1298e9ceda2c3096Wu-cheng Li // Returns true if the item is a static image that represents camera 82dbb6acc204ba6f095eb0e49e1298e9ceda2c3096Wu-cheng Li // preview. 83dbb6acc204ba6f095eb0e49e1298e9ceda2c3096Wu-cheng Li public boolean isStaticCamera(int offset); 84dbb6acc204ba6f095eb0e49e1298e9ceda2c3096Wu-cheng Li 85d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang // Returns true if the item is a Video. 86d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang public boolean isVideo(int offset); 87f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang 886b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // Returns true if the item can be deleted. 896b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public boolean isDeletable(int offset); 906b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 91f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang public static final int LOADING_INIT = 0; 92f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang public static final int LOADING_COMPLETE = 1; 93f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang public static final int LOADING_FAIL = 2; 94f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang 95f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang public int getLoadingState(int offset); 966b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 976b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // When data change happens, we need to decide which MediaItem to focus 986b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // on. 996b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // 1006b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // 1. If focus hint path != null, we try to focus on it if we can find 1016b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // it. This is used for undo a deletion, so we can focus on the 1026b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // undeleted item. 1036b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // 1046b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // 2. Otherwise try to focus on the MediaItem that is currently focused, 1056b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // if we can find it. 1066b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // 1076b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // 3. Otherwise try to focus on the previous MediaItem or the next 1086b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // MediaItem, depending on the value of focus hint direction. 1096b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public static final int FOCUS_HINT_NEXT = 0; 1106b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public static final int FOCUS_HINT_PREVIOUS = 1; 1116b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public void setFocusHintDirection(int direction); 1126b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public void setFocusHintPath(Path path); 113b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 114b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 115bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public interface Listener { 116b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void onSingleTapUp(int x, int y); 117bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public void lockOrientation(); 118bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public void unlockOrientation(); 119bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public void onFullScreenChanged(boolean full); 12061f94714c3702115d2f89bb5f8829697be0c3680Chih-Chung Chang public void onActionBarAllowed(boolean allowed); 121e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang public void onActionBarWanted(); 122bd7c016d728853d38f98a3c6077b7bd9b08858b9Yuli Huang public void onCurrentImageUpdated(); 1236b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public void onDeleteImage(Path path, int offset); 1246b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public void onUndoDeleteImage(); 1256b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public void onCommitDeleteImage(); 126b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 127f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 128e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang // The rules about orientation locking: 129bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // 130e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang // (1) We need to lock the orientation if we are in page mode camera 131e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang // preview, so there is no (unwanted) rotation animation when the user 132e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang // rotates the device. 133bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // 134e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang // (2) We need to unlock the orientation if we want to show the action bar 135e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang // because the action bar follows the system orientation. 136bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // 137e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang // The rules about action bar: 138bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // 139e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang // (1) If we are in film mode, we don't show action bar. 140e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang // 141e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang // (2) If we go from camera to gallery with capture animation, we show 142e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang // action bar. 143b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static final int MSG_CANCEL_EXTRA_SCALING = 2; 144b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static final int MSG_SWITCH_FOCUS = 3; 1452c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang private static final int MSG_CAPTURE_ANIMATION_DONE = 4; 1466b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private static final int MSG_DELETE_ANIMATION_DONE = 5; 1476b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private static final int MSG_DELETE_DONE = 6; 1486118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang private static final int MSG_UNDO_BAR_TIMEOUT = 7; 1496118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang private static final int MSG_UNDO_BAR_FULL_CAMERA = 8; 150f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 151b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static final int MOVE_THRESHOLD = 256; 152f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final float SWIPE_THRESHOLD = 300f; 153f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 154f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final float DEFAULT_TEXT_SIZE = 20; 155cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private static float TRANSITION_SCALE_FACTOR = 0.74f; 156d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang private static final int ICON_RATIO = 6; 1572c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang 1582c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // whether we want to apply card deck effect in page mode. 159b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static final boolean CARD_EFFECT = true; 160cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1616b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // whether we want to apply offset effect in film mode. 1626b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private static final boolean OFFSET_EFFECT = true; 1636b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 1646b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // Used to calculate the scaling factor for the card deck effect. 165cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private ZInterpolator mScaleInterpolator = new ZInterpolator(0.5f); 166cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 167cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // Used to calculate the alpha factor for the fading animation. 168cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private AccelerateInterpolator mAlphaInterpolator = 169cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang new AccelerateInterpolator(0.9f); 170f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 171b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // We keep this many previous ScreenNails. (also this many next ScreenNails) 172b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public static final int SCREEN_NAIL_MAX = 3; 173b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1746b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // These are constants for the delete gesture. 1756b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private static final int SWIPE_ESCAPE_VELOCITY = 500; // dp/sec 1766b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private static final int MAX_DISMISS_VELOCITY = 2000; // dp/sec 1776b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 178b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // The picture entries, the valid index is from -SCREEN_NAIL_MAX to 179b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // SCREEN_NAIL_MAX. 180b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private final RangeArray<Picture> mPictures = 181b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang new RangeArray<Picture>(-SCREEN_NAIL_MAX, SCREEN_NAIL_MAX); 1826b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private Size[] mSizes = new Size[2 * SCREEN_NAIL_MAX + 1]; 183f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1846575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang private final MyGestureListener mGestureListener; 1853a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang private final GestureRecognizer mGestureRecognizer; 186f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final PositionController mPositionController; 187f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 188bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private Listener mListener; 189f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private Model mModel; 190f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private StringTexture mLoadingText; 191f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private StringTexture mNoThumbnailText; 192b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private TileImageView mTileView; 193532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private EdgeView mEdgeView; 1946b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private UndoBarView mUndoBar; 195f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private Texture mVideoPlayIcon; 196f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 197f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private SynchronizedHandler mHandler; 198f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 199cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private Point mImageCenter = new Point(); 200534b12fd804610dd67b8109bc08ba76f31afb33eChih-Chung Chang private boolean mCancelExtraScalingPending; 201b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private boolean mFilmMode = false; 202bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private int mDisplayRotation = 0; 203bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private int mCompensation = 0; 2049f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang private boolean mFullScreenCamera; 2052ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang private Rect mCameraRelativeFrame = new Rect(); 206bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private Rect mCameraRect = new Rect(); 207f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 208c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // [mPrevBound, mNextBound] is the range of index for all pictures in the 209c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // model, if we assume the index of current focused picture is 0. So if 210c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // there are some previous pictures, mPrevBound < 0, and if there are some 211c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // next pictures, mNextBound > 0. 212c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang private int mPrevBound; 213c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang private int mNextBound; 214c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang 2152c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // This variable prevents us doing snapback until its values goes to 0. This 2162c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // happens if the user gesture is still in progress or we are in a capture 2172c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // animation. 2182c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang private int mHolding; 2192c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang private static final int HOLD_TOUCH_DOWN = 1; 22018958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang private static final int HOLD_CAPTURE_ANIMATION = 2; 2216b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private static final int HOLD_DELETE = 4; 2226b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 2236b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // mTouchBoxIndex is the index of the box that is touched by the down 2246b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // gesture in film mode. The value Integer.MAX_VALUE means no box was 2256b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // touched. 2266b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private int mTouchBoxIndex = Integer.MAX_VALUE; 2276b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // Whether the box indicated by mTouchBoxIndex is deletable. Only meaningful 2286b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // if mTouchBoxIndex is not Integer.MAX_VALUE. 2296b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private boolean mTouchBoxDeletable; 230517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang // This is the index of the last deleted item. This is only used as a hint 231517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang // to hide the undo button when we are too far away from the deleted 232517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang // item. The value Integer.MAX_VALUE means there is no such hint. 233517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang private int mUndoIndexHint = Integer.MAX_VALUE; 2342c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang 235f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public PhotoView(GalleryActivity activity) { 236f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mTileView = new TileImageView(activity); 237f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin addComponent(mTileView); 238f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Context context = activity.getAndroidContext(); 239532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mEdgeView = new EdgeView(context); 240532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang addComponent(mEdgeView); 2416b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mUndoBar = new UndoBarView(context); 2426b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang addComponent(mUndoBar); 2436b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mUndoBar.setVisibility(GLView.INVISIBLE); 2446b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mUndoBar.setOnClickListener(new OnClickListener() { 2456b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang @Override 2466b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public void onClick(GLView v) { 2476b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mListener.onUndoDeleteImage(); 2486118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang hideUndoBar(); 2496b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 2506b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang }); 251f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mLoadingText = StringTexture.newInstance( 252f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin context.getString(R.string.loading), 253f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin DEFAULT_TEXT_SIZE, Color.WHITE); 254f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mNoThumbnailText = StringTexture.newInstance( 255f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin context.getString(R.string.no_thumbnail), 256f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin DEFAULT_TEXT_SIZE, Color.WHITE); 257f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 258b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mHandler = new MyHandler(activity.getGLRoot()); 259f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 2606575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang mGestureListener = new MyGestureListener(); 2616575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang mGestureRecognizer = new GestureRecognizer(context, mGestureListener); 262f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 263b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController = new PositionController(context, 264b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang new PositionController.Listener() { 265b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void invalidate() { 266b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang PhotoView.this.invalidate(); 267b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 2686b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public boolean isHoldingDown() { 2696b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang return (mHolding & HOLD_TOUCH_DOWN) != 0; 2706b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 2716b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public boolean isHoldingDelete() { 2726b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang return (mHolding & HOLD_DELETE) != 0; 273b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 274b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void onPull(int offset, int direction) { 275b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mEdgeView.onPull(offset, direction); 276b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 277b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void onRelease() { 278b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mEdgeView.onRelease(); 279b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 280b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void onAbsorb(int velocity, int direction) { 281b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mEdgeView.onAbsorb(velocity, direction); 282b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 283b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang }); 284f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mVideoPlayIcon = new ResourceTexture(context, R.drawable.ic_control_play); 285b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = -SCREEN_NAIL_MAX; i <= SCREEN_NAIL_MAX; i++) { 286b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (i == 0) { 287b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPictures.put(i, new FullPicture()); 288cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } else { 289b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPictures.put(i, new ScreenNailPicture(i)); 290cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 291f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 292f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 293f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 294b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void setModel(Model model) { 295b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mModel = model; 296b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mTileView.setModel(mModel); 297f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 298f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 299b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang class MyHandler extends SynchronizedHandler { 300b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public MyHandler(GLRoot root) { 301b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang super(root); 302f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 303f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 304b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 305b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void handleMessage(Message message) { 306b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang switch (message.what) { 307b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang case MSG_CANCEL_EXTRA_SCALING: { 308b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mGestureRecognizer.cancelScale(); 309b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.setExtraScalingRange(false); 310b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mCancelExtraScalingPending = false; 311b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang break; 312b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 313b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang case MSG_SWITCH_FOCUS: { 314b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang switchFocus(); 315b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang break; 316b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 3172c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang case MSG_CAPTURE_ANIMATION_DONE: { 318bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // message.arg1 is the offset parameter passed to 319bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // switchWithCaptureAnimation(). 320bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang captureAnimationDone(message.arg1); 3212c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang break; 3222c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 3236b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang case MSG_DELETE_ANIMATION_DONE: { 3246b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // message.obj is the Path of the MediaItem which should be 3256b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // deleted. message.arg1 is the offset of the image. 3266b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mListener.onDeleteImage((Path) message.obj, message.arg1); 3276b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // Normally a box which finishes delete animation will hold 3286b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // position until the underlying MediaItem is actually 3296b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // deleted, and HOLD_DELETE will be cancelled that time. In 3306b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // case the MediaItem didn't actually get deleted in 2 3316b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // seconds, we will cancel HOLD_DELETE and make it bounce 3326b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // back. 3336b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 3346b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // We make sure there is at most one MSG_DELETE_DONE 3356b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // in the handler. 3366b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mHandler.removeMessages(MSG_DELETE_DONE); 3376b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang Message m = mHandler.obtainMessage(MSG_DELETE_DONE); 3386b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mHandler.sendMessageDelayed(m, 2000); 3396118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang 3406118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang int numberOfPictures = mNextBound - mPrevBound + 1; 3416118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang if (numberOfPictures == 2) { 3426118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang if (mModel.isCamera(mNextBound) 3436118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang || mModel.isCamera(mPrevBound)) { 3446118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang numberOfPictures--; 3456118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang } 3466118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang } 3476118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang showUndoBar(numberOfPictures <= 1); 3486b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang break; 3496b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 3506b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang case MSG_DELETE_DONE: { 3516b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (!mHandler.hasMessages(MSG_DELETE_ANIMATION_DONE)) { 3526b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mHolding &= ~HOLD_DELETE; 3536b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang snapback(); 3546b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 3556b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang break; 3566b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 3576118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang case MSG_UNDO_BAR_TIMEOUT: { 358517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang checkHideUndoBar(UNDO_BAR_TIMEOUT); 359517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang break; 360517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang } 3616118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang case MSG_UNDO_BAR_FULL_CAMERA: { 3626118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang checkHideUndoBar(UNDO_BAR_FULL_CAMERA); 3636118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang break; 3646118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang } 365b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang default: throw new AssertionError(message.what); 366f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 367f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 368b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang }; 369f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 370b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 371b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Data/Image change notifications 372b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 373b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 374214993dc4abf87c386123af50e3c34184ba11cb6Chih-Chung Chang public void notifyDataChange(int[] fromIndex, int prevBound, int nextBound) { 375c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang mPrevBound = prevBound; 376c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang mNextBound = nextBound; 377c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang 3786b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // Update mTouchBoxIndex 3796b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (mTouchBoxIndex != Integer.MAX_VALUE) { 3806b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int k = mTouchBoxIndex; 3816b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mTouchBoxIndex = Integer.MAX_VALUE; 3826b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang for (int i = 0; i < 2 * SCREEN_NAIL_MAX + 1; i++) { 3836b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (fromIndex[i] == k) { 3846b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mTouchBoxIndex = i - SCREEN_NAIL_MAX; 3856b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang break; 3866b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 3876b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 3886b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 3896b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 390517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang // Hide undo button if we are too far away 391517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang if (mUndoIndexHint != Integer.MAX_VALUE) { 392517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang if (Math.abs(mUndoIndexHint - mModel.getCurrentIndex()) >= 3) { 393517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang hideUndoBar(); 394517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang } 395517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang } 396517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang 3976b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // Update the ScreenNails. 3986b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang for (int i = -SCREEN_NAIL_MAX; i <= SCREEN_NAIL_MAX; i++) { 3996b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang Picture p = mPictures.get(i); 4006b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang p.reload(); 4016b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mSizes[i + SCREEN_NAIL_MAX] = p.getSize(); 4026b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 4036b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 4046b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang boolean wasDeleting = mPositionController.hasDeletingBox(); 4056b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 406b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Move the boxes 407214993dc4abf87c386123af50e3c34184ba11cb6Chih-Chung Chang mPositionController.moveBox(fromIndex, mPrevBound < 0, mNextBound > 0, 4086b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mModel.isCamera(0), mSizes); 409b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 410b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = -SCREEN_NAIL_MAX; i <= SCREEN_NAIL_MAX; i++) { 4116b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang setPictureSize(i); 4126b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 4136b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 4146b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang boolean isDeleting = mPositionController.hasDeletingBox(); 4156b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 4166b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // If the deletion is done, make HOLD_DELETE persist for only the time 4176b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // needed for a snapback animation. 4186b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (wasDeleting && !isDeleting) { 4196b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mHandler.removeMessages(MSG_DELETE_DONE); 4206b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang Message m = mHandler.obtainMessage(MSG_DELETE_DONE); 4216b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mHandler.sendMessageDelayed( 4226b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang m, PositionController.SNAPBACK_ANIMATION_TIME); 423b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 424b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 425b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang invalidate(); 426f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 427f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 4286b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public boolean isDeleting() { 4296b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang return (mHolding & HOLD_DELETE) != 0 4306b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang && mPositionController.hasDeletingBox(); 4316b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 4326b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 433b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void notifyImageChange(int index) { 434bd7c016d728853d38f98a3c6077b7bd9b08858b9Yuli Huang if (index == 0) { 435bd7c016d728853d38f98a3c6077b7bd9b08858b9Yuli Huang mListener.onCurrentImageUpdated(); 436bd7c016d728853d38f98a3c6077b7bd9b08858b9Yuli Huang } 437b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPictures.get(index).reload(); 4386b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang setPictureSize(index); 439b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang invalidate(); 440f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 441f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 4426b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private void setPictureSize(int index) { 4436b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang Picture p = mPictures.get(index); 4446b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mPositionController.setImageSize(index, p.getSize(), 4456b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang index == 0 && p.isCamera() ? mCameraRect : null); 4466b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 4476b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 448bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang @Override 4492ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang protected void onLayout( 4502ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang boolean changeSize, int left, int top, int right, int bottom) { 4512ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang int w = right - left; 4522ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang int h = bottom - top; 4532ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang mTileView.layout(0, 0, w, h); 4542ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang mEdgeView.layout(0, 0, w, h); 4556b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mUndoBar.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); 4566b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mUndoBar.layout(0, h - mUndoBar.getMeasuredHeight(), w, h); 4572ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang 4582ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang GLRoot root = getGLRoot(); 4592ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang int displayRotation = root.getDisplayRotation(); 4602ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang int compensation = root.getCompensation(); 4612ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang if (mDisplayRotation != displayRotation 4622ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang || mCompensation != compensation) { 4632ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang mDisplayRotation = displayRotation; 4642ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang mCompensation = compensation; 4652ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang 4663b4a8aeb0353fa18a2b5267b3952a80a6c6d4d13Chih-Chung Chang // We need to change the size and rotation of the Camera ScreenNail, 4673b4a8aeb0353fa18a2b5267b3952a80a6c6d4d13Chih-Chung Chang // but we don't want it to animate because the size doen't actually 4682ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang // change in the eye of the user. 4692ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang for (int i = -SCREEN_NAIL_MAX; i <= SCREEN_NAIL_MAX; i++) { 4702ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang Picture p = mPictures.get(i); 4712ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang if (p.isCamera()) { 4729f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang p.forceSize(); 4732ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang } 474bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 475bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 476bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 4779f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang updateCameraRect(); 4789f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang mPositionController.setConstrainedFrame(mCameraRect); 479bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (changeSize) { 480bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mPositionController.setViewSize(getWidth(), getHeight()); 481bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 482bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 483bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 4849f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang // Update the camera rectangle due to layout change or camera relative frame 4859f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang // change. 4869f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang private void updateCameraRect() { 4872ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang // Get the width and height in framework orientation because the given 4882ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang // mCameraRelativeFrame is in that coordinates. 489bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang int w = getWidth(); 490bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang int h = getHeight(); 4912ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang if (mCompensation % 180 != 0) { 492bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang int tmp = w; 493bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang w = h; 494bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang h = tmp; 495bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 4962ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang int l = mCameraRelativeFrame.left; 4972ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang int t = mCameraRelativeFrame.top; 4982ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang int r = mCameraRelativeFrame.right; 4992ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang int b = mCameraRelativeFrame.bottom; 500bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 5012ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang // Now convert it to the coordinates we are using. 5022ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang switch (mCompensation) { 503bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang case 0: mCameraRect.set(l, t, r, b); break; 504bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang case 90: mCameraRect.set(h - b, l, h - t, r); break; 505bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang case 180: mCameraRect.set(w - r, h - b, w - l, h - t); break; 506bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang case 270: mCameraRect.set(t, w - r, b, w - l); break; 507bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 508bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 5092ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang Log.d(TAG, "compensation = " + mCompensation 5102ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang + ", CameraRelativeFrame = " + mCameraRelativeFrame 5112ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang + ", mCameraRect = " + mCameraRect); 512bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 513bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 5142ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang public void setCameraRelativeFrame(Rect frame) { 5152ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang mCameraRelativeFrame.set(frame); 5169f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang updateCameraRect(); 5179f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang // Originally we do 5189f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang // mPositionController.setConstrainedFrame(mCameraRect); 5199f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang // here, but it is moved to a parameter of the setImageSize() call, so 5209f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang // it can be updated atomically with the CameraScreenNail's size change. 521bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 522bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 523bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // Returns the rotation we need to do to the camera texture before drawing 524bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // it to the canvas, assuming the camera texture is correct when the device 525bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // is in its natural orientation. 526bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private int getCameraRotation() { 527bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang return (mCompensation - mDisplayRotation + 360) % 360; 528bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 529bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 53043a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong private int getPanoramaRotation() { 53143a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong return mCompensation; 53243a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong } 53343a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong 534b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 535b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Pictures 536b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 537b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 538b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private interface Picture { 539b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang void reload(); 540b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang void draw(GLCanvas canvas, Rect r); 541b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang void setScreenNail(ScreenNail s); 5422c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang boolean isCamera(); // whether the picture is a camera preview 5436b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang boolean isDeletable(); // whether the picture can be deleted 5449f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang void forceSize(); // called when mCompensation changes 5456b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang Size getSize(); 5467817979db0c52ffeacb951625b1e821eba303285Ahbong Chang } 547f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 548b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang class FullPicture implements Picture { 549b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private int mRotation; 5502c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang private boolean mIsCamera; 55143a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong private boolean mIsPanorama; 552dbb6acc204ba6f095eb0e49e1298e9ceda2c3096Wu-cheng Li private boolean mIsStaticCamera; 553d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang private boolean mIsVideo; 5546b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private boolean mIsDeletable; 555f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang private int mLoadingState = Model.LOADING_INIT; 5566b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private Size mSize = new Size(); 557bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private boolean mWasCameraCenter; 558b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void FullPicture(TileImageView tileView) { 559b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mTileView = tileView; 560f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 561f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 562b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 563b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void reload() { 564b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // mImageWidth and mImageHeight will get updated 565b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mTileView.notifyModelInvalidated(); 566b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 567bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mIsCamera = mModel.isCamera(0); 56843a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong mIsPanorama = mModel.isPanorama(0); 569dbb6acc204ba6f095eb0e49e1298e9ceda2c3096Wu-cheng Li mIsStaticCamera = mModel.isStaticCamera(0); 570d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang mIsVideo = mModel.isVideo(0); 5716b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mIsDeletable = mModel.isDeletable(0); 572f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang mLoadingState = mModel.getLoadingState(0); 573bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang setScreenNail(mModel.getScreenNail(0)); 5746b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang updateSize(); 5759f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang } 5769f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang 5776b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang @Override 5786b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public Size getSize() { 5796b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang return mSize; 580bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 581bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 582bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang @Override 5839f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang public void forceSize() { 5849f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang updateSize(); 5856b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mPositionController.forceImageSize(0, mSize); 5869f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang } 5879f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang 5889f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang private void updateSize() { 58943a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong if (mIsPanorama) { 59043a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong mRotation = getPanoramaRotation(); 591dbb6acc204ba6f095eb0e49e1298e9ceda2c3096Wu-cheng Li } else if (mIsCamera && !mIsStaticCamera) { 592bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mRotation = getCameraRotation(); 593bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } else { 594bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mRotation = mModel.getImageRotation(0); 595bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 596bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 597c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang int w = mTileView.mImageWidth; 598c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang int h = mTileView.mImageHeight; 5996b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mSize.width = getRotated(mRotation, w, h); 6006b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mSize.height = getRotated(mRotation, h, w); 601f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 602f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 603b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 604b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void draw(GLCanvas canvas, Rect r) { 605f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang drawTileView(canvas, r); 606cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 607bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // We want to have the following transitions: 6082c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // (1) Move camera preview out of its place: switch to film mode 6092c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // (2) Move camera preview into its place: switch to page mode 6102c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // The extra mWasCenter check makes sure (1) does not apply if in 6112c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // page mode, we move _to_ the camera preview from another picture. 612bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 613bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // Holdings except touch-down prevent the transitions. 61418958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang if ((mHolding & ~HOLD_TOUCH_DOWN) != 0) return; 615bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 6169f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang boolean isCenter = mPositionController.isCenter(); 6176118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang boolean isCameraCenter = mIsCamera && isCenter && !canUndoLastPicture(); 618bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 619bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (mWasCameraCenter && mIsCamera && !isCenter && !mFilmMode) { 62018958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang // Temporary disabled to de-emphasize filmstrip. 62118958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang // setFilmMode(true); 62218958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang } else if (!mWasCameraCenter && isCameraCenter && mFilmMode) { 623bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang setFilmMode(false); 624aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang } 625aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang 6269f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang if (isCameraCenter && !mFilmMode) { 627e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang // Move into camera in page mode, lock 628e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang mListener.lockOrientation(); 629bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 630bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 631bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mWasCameraCenter = isCameraCenter; 632cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 633cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 634b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 635b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang public void setScreenNail(ScreenNail s) { 636b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang mTileView.setScreenNail(s); 637cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 638f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 639b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 6402c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang public boolean isCamera() { 6412c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang return mIsCamera; 642f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 643f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 6446b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang @Override 6456b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public boolean isDeletable() { 6466b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang return mIsDeletable; 6476b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 6486b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 649d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang private void drawTileView(GLCanvas canvas, Rect r) { 650ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang float imageScale = mPositionController.getImageScale(); 651b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int viewW = getWidth(); 652b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int viewH = getHeight(); 653d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang float cx = r.exactCenterX(); 654d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang float cy = r.exactCenterY(); 655ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang float scale = 1f; // the scaling factor due to card effect 656b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 657d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang canvas.save(GLCanvas.SAVE_FLAG_MATRIX | GLCanvas.SAVE_FLAG_ALPHA); 658ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang float filmRatio = mPositionController.getFilmRatio(); 659ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang boolean wantsCardEffect = CARD_EFFECT && !mIsCamera 660f320b8429dd5c68c117b8e9b1a36a435f4f4ff13Yuli Huang && filmRatio != 1f && !mPictures.get(-1).isCamera() 661f320b8429dd5c68c117b8e9b1a36a435f4f4ff13Yuli Huang && !mPositionController.inOpeningAnimation(); 6626b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang boolean wantsOffsetEffect = OFFSET_EFFECT && mIsDeletable 6636b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang && filmRatio == 1f && r.centerY() != viewH / 2; 6642c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (wantsCardEffect) { 665b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Calculate the move-out progress value. 666b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int left = r.left; 667b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int right = r.right; 668b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang float progress = calculateMoveOutProgress(left, right, viewW); 669b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang progress = Utils.clamp(progress, -1f, 1f); 670b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 671b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // We only want to apply the fading animation if the scrolling 672b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // movement is to the right. 673bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (progress < 0) { 674ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang scale = getScrollScale(progress); 675ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang float alpha = getScrollAlpha(progress); 676ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang scale = interpolate(filmRatio, scale, 1f); 677ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang alpha = interpolate(filmRatio, alpha, 1f); 678d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang 679ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang imageScale *= scale; 680ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang canvas.multiplyAlpha(alpha); 681ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang 682ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang float cxPage; // the cx value in page mode 683d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang if (right - left <= viewW) { 684b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // If the picture is narrower than the view, keep it at 685b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // the center of the view. 686ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang cxPage = viewW / 2f; 687b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } else { 688b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // If the picture is wider than the view (it's 689b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // zoomed-in), keep the left edge of the object align 690b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // the the left edge of the view. 691ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang cxPage = (right - left) * scale / 2f; 692b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 693ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang cx = interpolate(filmRatio, cxPage, cx); 694b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 6956b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } else if (wantsOffsetEffect) { 6966b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang float offset = (float) (r.centerY() - viewH / 2) / viewH; 6976b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang float alpha = getOffsetAlpha(offset); 6986b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang canvas.multiplyAlpha(alpha); 699b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 700f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 701d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang // Draw the tile view. 702ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang setTileViewPosition(cx, cy, viewW, viewH, imageScale); 7036b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang renderChild(canvas, mTileView); 704d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang 705f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang // Draw the play video icon and the message. 706f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang canvas.translate((int) (cx + 0.5f), (int) (cy + 0.5f)); 707f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang int s = (int) (scale * Math.min(r.width(), r.height()) + 0.5f); 708f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang if (mIsVideo) drawVideoPlayIcon(canvas, s); 709f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang if (mLoadingState == Model.LOADING_FAIL) { 710f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang drawLoadingFailMessage(canvas); 711d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang } 712d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang 713f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang // Draw a debug indicator showing which picture has focus (index == 714f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang // 0). 715f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang //canvas.fillRect(-10, -10, 20, 20, 0x80FF00FF); 716f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang 717d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang canvas.restore(); 718d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang } 719d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang 720d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang // Set the position of the tile view 721d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang private void setTileViewPosition(float cx, float cy, 722d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang int viewW, int viewH, float scale) { 723d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang // Find out the bitmap coordinates of the center of the view 724d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang int imageW = mPositionController.getImageWidth(); 725d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang int imageH = mPositionController.getImageHeight(); 726d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang int centerX = (int) (imageW / 2f + (viewW / 2f - cx) / scale + 0.5f); 727d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang int centerY = (int) (imageH / 2f + (viewH / 2f - cy) / scale + 0.5f); 728d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang 729b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int inverseX = imageW - centerX; 730b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int inverseY = imageH - centerY; 731d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang int x, y; 732d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang switch (mRotation) { 733d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang case 0: x = centerX; y = centerY; break; 734d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang case 90: x = centerY; y = inverseX; break; 735d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang case 180: x = inverseX; y = inverseY; break; 736d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang case 270: x = inverseY; y = centerX; break; 737b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang default: 738d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang throw new RuntimeException(String.valueOf(mRotation)); 739b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 740d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang mTileView.setPosition(x, y, scale, mRotation); 741f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 742f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 743f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 744b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private class ScreenNailPicture implements Picture { 745b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private int mIndex; 746b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private int mRotation; 747b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private ScreenNail mScreenNail; 7482c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang private boolean mIsCamera; 74943a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong private boolean mIsPanorama; 750dbb6acc204ba6f095eb0e49e1298e9ceda2c3096Wu-cheng Li private boolean mIsStaticCamera; 751d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang private boolean mIsVideo; 7526b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private boolean mIsDeletable; 753f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang private int mLoadingState = Model.LOADING_INIT; 7546b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private Size mSize = new Size(); 755f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 756b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public ScreenNailPicture(int index) { 757b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mIndex = index; 758b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 759532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 760b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 761b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void reload() { 762bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mIsCamera = mModel.isCamera(mIndex); 76343a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong mIsPanorama = mModel.isPanorama(mIndex); 764dbb6acc204ba6f095eb0e49e1298e9ceda2c3096Wu-cheng Li mIsStaticCamera = mModel.isStaticCamera(mIndex); 765d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang mIsVideo = mModel.isVideo(mIndex); 7666b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mIsDeletable = mModel.isDeletable(mIndex); 767f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang mLoadingState = mModel.getLoadingState(mIndex); 768c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang setScreenNail(mModel.getScreenNail(mIndex)); 7696b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang updateSize(); 7706b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 7716b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 7726b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang @Override 7736b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public Size getSize() { 7746b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang return mSize; 775b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 776b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 777b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 778b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void draw(GLCanvas canvas, Rect r) { 779b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mScreenNail == null) { 780f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang // Draw a placeholder rectange if there should be a picture in 781f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang // this position (but somehow there isn't). 782c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang if (mIndex >= mPrevBound && mIndex <= mNextBound) { 783f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang drawPlaceHolder(canvas, r); 784c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang } 785b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return; 786f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 7876b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int w = getWidth(); 7886b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int h = getHeight(); 7896b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (r.left >= w || r.right <= 0 || r.top >= h || r.bottom <= 0) { 790b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mScreenNail.noDraw(); 791b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return; 792f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 793f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 794ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang float filmRatio = mPositionController.getFilmRatio(); 795ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang boolean wantsCardEffect = CARD_EFFECT && mIndex > 0 796ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang && filmRatio != 1f && !mPictures.get(0).isCamera(); 7976b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang boolean wantsOffsetEffect = OFFSET_EFFECT && mIsDeletable 7986b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang && filmRatio == 1f && r.centerY() != h / 2; 799ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang int cx = wantsCardEffect 800ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang ? (int) (interpolate(filmRatio, w / 2, r.centerX()) + 0.5f) 801ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang : r.centerX(); 802b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int cy = r.centerY(); 803ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang canvas.save(GLCanvas.SAVE_FLAG_MATRIX | GLCanvas.SAVE_FLAG_ALPHA); 804b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang canvas.translate(cx, cy); 8052c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (wantsCardEffect) { 806b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang float progress = (float) (w / 2 - r.centerX()) / w; 807b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang progress = Utils.clamp(progress, -1, 1); 808b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang float alpha = getScrollAlpha(progress); 809b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang float scale = getScrollScale(progress); 810ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang alpha = interpolate(filmRatio, alpha, 1f); 811ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang scale = interpolate(filmRatio, scale, 1f); 812b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang canvas.multiplyAlpha(alpha); 813b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang canvas.scale(scale, scale, 1); 8146b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } else if (wantsOffsetEffect) { 8156b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang float offset = (float) (r.centerY() - h / 2) / h; 8166b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang float alpha = getOffsetAlpha(offset); 8176b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang canvas.multiplyAlpha(alpha); 818b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 819b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mRotation != 0) { 820b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang canvas.rotate(mRotation, 0, 0, 1); 821b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 822ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang int drawW = getRotated(mRotation, r.width(), r.height()); 823ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang int drawH = getRotated(mRotation, r.height(), r.width()); 824b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mScreenNail.draw(canvas, -drawW / 2, -drawH / 2, drawW, drawH); 825f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang if (isScreenNailAnimating()) { 826f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang invalidate(); 827f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang } 828f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang int s = Math.min(drawW, drawH); 829f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang if (mIsVideo) drawVideoPlayIcon(canvas, s); 830f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang if (mLoadingState == Model.LOADING_FAIL) { 831f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang drawLoadingFailMessage(canvas); 832f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang } 833b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang canvas.restore(); 834b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 835f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 836f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang private boolean isScreenNailAnimating() { 837f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang return (mScreenNail instanceof BitmapScreenNail) 838f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang && ((BitmapScreenNail) mScreenNail).isAnimating(); 839f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang } 840f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang 841b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 842b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang public void setScreenNail(ScreenNail s) { 843b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mScreenNail = s; 8449f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang } 8459f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang 846bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang @Override 8479f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang public void forceSize() { 8489f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang updateSize(); 8496b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mPositionController.forceImageSize(mIndex, mSize); 8509f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang } 8519f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang 8529f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang private void updateSize() { 85343a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong if (mIsPanorama) { 85443a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong mRotation = getPanoramaRotation(); 855dbb6acc204ba6f095eb0e49e1298e9ceda2c3096Wu-cheng Li } else if (mIsCamera && !mIsStaticCamera) { 856bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mRotation = getCameraRotation(); 857bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } else { 858bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mRotation = mModel.getImageRotation(mIndex); 859bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 860c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang 861b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mScreenNail != null) { 8626b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mSize.width = mScreenNail.getWidth(); 8636b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mSize.height = mScreenNail.getHeight(); 8646b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } else { 865c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // If we don't have ScreenNail available, we can still try to 866c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // get the size information of it. 867c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang mModel.getImageSize(mIndex, mSize); 868b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 869c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang 8706b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int w = mSize.width; 8716b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int h = mSize.height; 8726b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mSize.width = getRotated(mRotation, w, h); 8736b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mSize.height = getRotated(mRotation, h, w); 874f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 875b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 876b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 8772c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang public boolean isCamera() { 8782c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang return mIsCamera; 879b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 8806b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 8816b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang @Override 8826b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public boolean isDeletable() { 8836b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang return mIsDeletable; 8846b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 885b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 886b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 887f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang // Draw a gray placeholder in the specified rectangle. 888f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang private void drawPlaceHolder(GLCanvas canvas, Rect r) { 889f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang canvas.fillRect(r.left, r.top, r.width(), r.height(), PLACEHOLDER_COLOR); 890f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang } 891f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang 892d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang // Draw the video play icon (in the place where the spinner was) 893d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang private void drawVideoPlayIcon(GLCanvas canvas, int side) { 894d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang int s = side / ICON_RATIO; 895d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang // Draw the video play icon at the center 896d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang mVideoPlayIcon.draw(canvas, -s / 2, -s / 2, s, s); 897d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang } 898d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang 899f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang // Draw the "no thumbnail" message 900f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang private void drawLoadingFailMessage(GLCanvas canvas) { 901f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang StringTexture m = mNoThumbnailText; 902f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang m.draw(canvas, -m.getWidth() / 2, -m.getHeight() / 2); 903f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang } 904f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang 905b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static int getRotated(int degree, int original, int theother) { 906b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return (degree % 180 == 0) ? original : theother; 907b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 908b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 909b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 910b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Gestures Handling 911b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 912b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 913b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 914b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang protected boolean onTouch(MotionEvent event) { 915b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mGestureRecognizer.onTouchEvent(event); 916b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return true; 917f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 918f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 9193a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang private class MyGestureListener implements GestureRecognizer.Listener { 9203a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang private boolean mIgnoreUpEvent = false; 921099989b310d84fe13eff0cdf2902bb3fb0bcbd14Chih-Chung Chang // If we can change mode for this scale gesture. 922099989b310d84fe13eff0cdf2902bb3fb0bcbd14Chih-Chung Chang private boolean mCanChangeMode; 92318958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang // If we have changed the film mode in this scaling gesture. 924b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private boolean mModeChanged; 92533f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang // If this scaling gesture should be ignored. 92633f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang private boolean mIgnoreScalingGesture; 9272ce59cbd4368eaf0f30cfea28891bd47155182cbChih-Chung Chang // If we have seen a scaling gesture. 9282ce59cbd4368eaf0f30cfea28891bd47155182cbChih-Chung Chang private boolean mSeenScaling; 92917ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang // whether the down action happened while the view is scrolling. 93017ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang private boolean mDownInScrolling; 9316575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang // If we should ignore all gestures other than onSingleTapUp. 9326575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang private boolean mIgnoreSwipingGesture; 9336b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // If a scrolling has happened after a down gesture. 9346b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private boolean mScrolledAfterDown; 9356b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // If the first scrolling move is in X direction. In the film mode, X 9366b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // direction scrolling is normal scrolling. but Y direction scrolling is 9376b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // a delete gesture. 9386b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private boolean mFirstScrollX; 9396b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // The accumulated Y delta that has been sent to mPositionController. 9406b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private int mDeltaY; 9412ce59cbd4368eaf0f30cfea28891bd47155182cbChih-Chung Chang // The accumulated scaling change from a scaling gesture. 9422ce59cbd4368eaf0f30cfea28891bd47155182cbChih-Chung Chang private float mAccScale; 943b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 9443a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang @Override 9453a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang public boolean onSingleTapUp(float x, float y) { 946ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang // We do this in addition to onUp() because we want the snapback of 947ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang // setFilmMode to happen. 948ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang mHolding &= ~HOLD_TOUCH_DOWN; 949ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang 95017ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang if (mFilmMode && !mDownInScrolling) { 95117ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang switchToHitPicture((int) (x + 0.5f), (int) (y + 0.5f)); 952b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang setFilmMode(false); 95317ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang mIgnoreUpEvent = true; 954b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return true; 955b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 956b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 957bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (mListener != null) { 9582ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang // Do the inverse transform of the touch coordinates. 9592ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang Matrix m = getGLRoot().getCompensationMatrix(); 9602ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang Matrix inv = new Matrix(); 9612ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang m.invert(inv); 9622ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang float[] pts = new float[] {x, y}; 9632ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang inv.mapPoints(pts); 9642ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang mListener.onSingleTapUp((int) (pts[0] + 0.5f), (int) (pts[1] + 0.5f)); 9653a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang } 9663a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang return true; 9673a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang } 9683a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang 9693a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang @Override 9703a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang public boolean onDoubleTap(float x, float y) { 9716575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang if (mIgnoreSwipingGesture) return true; 97261f94714c3702115d2f89bb5f8829697be0c3680Chih-Chung Chang if (mPictures.get(0).isCamera()) return false; 9733a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang PositionController controller = mPositionController; 974b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang float scale = controller.getImageScale(); 9753a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang // onDoubleTap happened on the second ACTION_DOWN. 9763a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang // We need to ignore the next UP event. 9773a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang mIgnoreUpEvent = true; 9783a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang if (scale <= 1.0f || controller.isAtMinimalScale()) { 9793a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang controller.zoomIn(x, y, Math.max(1.5f, scale * 1.5f)); 9803a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang } else { 9813a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang controller.resetToFullView(); 9823a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang } 9833a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang return true; 9843a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang } 985f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 986f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 9876b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public boolean onScroll(float dx, float dy, float totalX, float totalY) { 9886575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang if (mIgnoreSwipingGesture) return true; 9896b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (!mScrolledAfterDown) { 9906b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mScrolledAfterDown = true; 9916b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mFirstScrollX = (Math.abs(dx) > Math.abs(dy)); 9926b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 9936b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 9946b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int dxi = (int) (-dx + 0.5f); 9956b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int dyi = (int) (-dy + 0.5f); 9966b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (mFilmMode) { 9976b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (mFirstScrollX) { 9986b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mPositionController.scrollFilmX(dxi); 9996b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } else { 10006b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (mTouchBoxIndex == Integer.MAX_VALUE) return true; 10016b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int newDeltaY = calculateDeltaY(totalY); 10026b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int d = newDeltaY - mDeltaY; 10036b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (d != 0) { 10046b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mPositionController.scrollFilmY(mTouchBoxIndex, d); 10056b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mDeltaY = newDeltaY; 10066b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 10076b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 10086b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } else { 10096b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mPositionController.scrollPage(dxi, dyi); 10106b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 1011f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return true; 1012f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1013f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 10146b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private int calculateDeltaY(float delta) { 10156b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (mTouchBoxDeletable) return (int) (delta + 0.5f); 10166b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 10176b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // don't let items that can't be deleted be dragged more than 10186b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // maxScrollDistance, and make it harder and harder to drag. 10196b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int size = getHeight(); 10206b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang float maxScrollDistance = 0.15f * size; 10216b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (Math.abs(delta) >= size) { 10226b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang delta = delta > 0 ? maxScrollDistance : -maxScrollDistance; 10236b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } else { 10246b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang delta = maxScrollDistance * 10256b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang FloatMath.sin((delta / size) * (float) (Math.PI / 2)); 10266b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 10276b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang return (int) (delta + 0.5f); 10286b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 10296b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 1030f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 10313a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang public boolean onFling(float velocityX, float velocityY) { 10326575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang if (mIgnoreSwipingGesture) return true; 10332ce59cbd4368eaf0f30cfea28891bd47155182cbChih-Chung Chang if (mSeenScaling) return true; 10342ce3c3bfe08fff5aee58007cc8ba8f4a50861ae2Yuli Huang if (swipeImages(velocityX, velocityY)) { 1035b3aab90bb37aa9cc60be32e05678ee55d6575ee8Chih-Chung Chang mIgnoreUpEvent = true; 10366b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } else { 10376b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang flingImages(velocityX, velocityY); 1038f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1039f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return true; 1040f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1041f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 10426b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private boolean flingImages(float velocityX, float velocityY) { 10436b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int vx = (int) (velocityX + 0.5f); 10446b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int vy = (int) (velocityY + 0.5f); 10456b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (!mFilmMode) { 10466b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang return mPositionController.flingPage(vx, vy); 10476b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 10486b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (Math.abs(velocityX) > Math.abs(velocityY)) { 10496b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang return mPositionController.flingFilmX(vx); 10506b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 10516b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // If we scrolled in Y direction fast enough, treat it as a delete 10526b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // gesture. 10536b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (!mFilmMode || mTouchBoxIndex == Integer.MAX_VALUE 10546b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang || !mTouchBoxDeletable) { 10556b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang return false; 10566b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 10577817979db0c52ffeacb951625b1e821eba303285Ahbong Chang int maxVelocity = GalleryUtils.dpToPixel(MAX_DISMISS_VELOCITY); 10587817979db0c52ffeacb951625b1e821eba303285Ahbong Chang int escapeVelocity = GalleryUtils.dpToPixel(SWIPE_ESCAPE_VELOCITY); 10596b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int centerY = mPositionController.getPosition(mTouchBoxIndex) 10606b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang .centerY(); 10616b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang boolean fastEnough = (Math.abs(vy) > escapeVelocity) 10626b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang && (Math.abs(vy) > Math.abs(vx)) 10636b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang && ((vy > 0) == (centerY > getHeight() / 2)); 10646b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (fastEnough) { 10656b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang vy = Math.min(vy, maxVelocity); 10666b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int duration = mPositionController.flingFilmY(mTouchBoxIndex, vy); 10676b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (duration >= 0) { 10686b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mPositionController.setPopFromTop(vy < 0); 10696b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang deleteAfterAnimation(duration); 10706b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // We reset mTouchBoxIndex, so up() won't check if Y 10716b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // scrolled far enough to be a delete gesture. 10726b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mTouchBoxIndex = Integer.MAX_VALUE; 10736b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang return true; 10746b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 10756b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 10766b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang return false; 10776b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 10786b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 10796b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private void deleteAfterAnimation(int duration) { 10806b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang MediaItem item = mModel.getMediaItem(mTouchBoxIndex); 10816b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (item == null) return; 1082517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang mListener.onCommitDeleteImage(); 1083517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang mUndoIndexHint = mModel.getCurrentIndex() + mTouchBoxIndex; 10846b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mHolding |= HOLD_DELETE; 10856b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang Message m = mHandler.obtainMessage(MSG_DELETE_ANIMATION_DONE); 10866b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang m.obj = item.getPath(); 10876b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang m.arg1 = mTouchBoxIndex; 10886b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mHandler.sendMessageDelayed(m, duration); 10896b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 10906b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 1091f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 10923a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang public boolean onScaleBegin(float focusX, float focusY) { 10936575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang if (mIgnoreSwipingGesture) return true; 109433f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang // We ignore the scaling gesture if it is a camera preview. 109533f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang mIgnoreScalingGesture = mPictures.get(0).isCamera(); 109633f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang if (mIgnoreScalingGesture) { 109733f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang return true; 109833f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang } 10993a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang mPositionController.beginScale(focusX, focusY); 1100099989b310d84fe13eff0cdf2902bb3fb0bcbd14Chih-Chung Chang // We can change mode if we are in film mode, or we are in page 1101099989b310d84fe13eff0cdf2902bb3fb0bcbd14Chih-Chung Chang // mode and at minimal scale. 1102099989b310d84fe13eff0cdf2902bb3fb0bcbd14Chih-Chung Chang mCanChangeMode = mFilmMode 1103099989b310d84fe13eff0cdf2902bb3fb0bcbd14Chih-Chung Chang || mPositionController.isAtMinimalScale(); 1104b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mModeChanged = false; 11052ce59cbd4368eaf0f30cfea28891bd47155182cbChih-Chung Chang mSeenScaling = true; 11062ce59cbd4368eaf0f30cfea28891bd47155182cbChih-Chung Chang mAccScale = 1f; 1107f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return true; 1108f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1109f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1110f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 11113a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang public boolean onScale(float focusX, float focusY, float scale) { 11126575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang if (mIgnoreSwipingGesture) return true; 11136575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang if (mIgnoreScalingGesture) return true; 111418958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang if (mModeChanged) return true; 1115b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (Float.isNaN(scale) || Float.isInfinite(scale)) return false; 111633f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang 1117b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int outOfRange = mPositionController.scaleBy(scale, focusX, focusY); 1118b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 11192ce59cbd4368eaf0f30cfea28891bd47155182cbChih-Chung Chang // We wait for a large enough scale change before changing mode. 11202ce59cbd4368eaf0f30cfea28891bd47155182cbChih-Chung Chang // Otherwise we may mistakenly treat a zoom-in gesture as zoom-out 11212ce59cbd4368eaf0f30cfea28891bd47155182cbChih-Chung Chang // or vice versa. 11222ce59cbd4368eaf0f30cfea28891bd47155182cbChih-Chung Chang mAccScale *= scale; 11232ce59cbd4368eaf0f30cfea28891bd47155182cbChih-Chung Chang boolean largeEnough = (mAccScale < 0.97f || mAccScale > 1.03f); 11242ce59cbd4368eaf0f30cfea28891bd47155182cbChih-Chung Chang 112518958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang // If mode changes, we treat this scaling gesture has ended. 11262ce59cbd4368eaf0f30cfea28891bd47155182cbChih-Chung Chang if (mCanChangeMode && largeEnough) { 1127b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if ((outOfRange < 0 && !mFilmMode) || 1128b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang (outOfRange > 0 && mFilmMode)) { 112918958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang stopExtraScalingIfNeeded(); 113018958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang 113118958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang // Removing the touch down flag allows snapback to happen 113233f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang // for film mode change. 113318958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang mHolding &= ~HOLD_TOUCH_DOWN; 1134b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang setFilmMode(!mFilmMode); 113518958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang 113618958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang // We need to call onScaleEnd() before setting mModeChanged 113718958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang // to true. 113818958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang onScaleEnd(); 1139b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mModeChanged = true; 1140b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return true; 1141534b12fd804610dd67b8109bc08ba76f31afb33eChih-Chung Chang } 1142b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1143b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 114418958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang if (outOfRange != 0) { 1145b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang startExtraScalingIfNeeded(); 1146534b12fd804610dd67b8109bc08ba76f31afb33eChih-Chung Chang } else { 1147b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang stopExtraScalingIfNeeded(); 1148534b12fd804610dd67b8109bc08ba76f31afb33eChih-Chung Chang } 1149f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return true; 1150f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1151f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 115233f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang @Override 115333f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang public void onScaleEnd() { 11546575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang if (mIgnoreSwipingGesture) return; 11556575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang if (mIgnoreScalingGesture) return; 115633f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang if (mModeChanged) return; 115733f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang mPositionController.endScale(); 115833f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang } 115933f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang 1160b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void startExtraScalingIfNeeded() { 1161b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (!mCancelExtraScalingPending) { 1162b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mHandler.sendEmptyMessageDelayed( 1163b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang MSG_CANCEL_EXTRA_SCALING, 700); 1164b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.setExtraScalingRange(true); 1165b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mCancelExtraScalingPending = true; 1166b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1167b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1168b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1169b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void stopExtraScalingIfNeeded() { 1170b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mCancelExtraScalingPending) { 1171b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mHandler.removeMessages(MSG_CANCEL_EXTRA_SCALING); 1172b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.setExtraScalingRange(false); 1173b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mCancelExtraScalingPending = false; 1174b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1175b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1176b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1177f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 11786b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public void onDown(float x, float y) { 1179517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang checkHideUndoBar(UNDO_BAR_TOUCHED); 1180517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang 11816b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mDeltaY = 0; 11822ce59cbd4368eaf0f30cfea28891bd47155182cbChih-Chung Chang mSeenScaling = false; 11836b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 11846575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang if (mIgnoreSwipingGesture) return; 11856575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang 11862c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mHolding |= HOLD_TOUCH_DOWN; 118717ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang 118817ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang if (mFilmMode && mPositionController.isScrolling()) { 118917ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang mDownInScrolling = true; 119017ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang mPositionController.stopScrolling(); 119117ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang } else { 119217ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang mDownInScrolling = false; 119317ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang } 11946b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 11956b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mScrolledAfterDown = false; 11966b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (mFilmMode) { 11976b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int xi = (int) (x + 0.5f); 11986b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int yi = (int) (y + 0.5f); 11996b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mTouchBoxIndex = mPositionController.hitTest(xi, yi); 12006b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (mTouchBoxIndex < mPrevBound || mTouchBoxIndex > mNextBound) { 12016b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mTouchBoxIndex = Integer.MAX_VALUE; 12026b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } else { 12036b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mTouchBoxDeletable = 12046b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mPictures.get(mTouchBoxIndex).isDeletable(); 12056b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 12066b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } else { 12076b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mTouchBoxIndex = Integer.MAX_VALUE; 12086b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 12093a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang } 12103a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang 12113a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang @Override 12123a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang public void onUp() { 12136575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang if (mIgnoreSwipingGesture) return; 12146575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang 121518958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang mHolding &= ~HOLD_TOUCH_DOWN; 12163a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang mEdgeView.onRelease(); 12173a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang 12186b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // If we scrolled in Y direction far enough, treat it as a delete 12196b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // gesture. 12206b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (mFilmMode && mScrolledAfterDown && !mFirstScrollX 12216b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang && mTouchBoxIndex != Integer.MAX_VALUE) { 12226b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang Rect r = mPositionController.getPosition(mTouchBoxIndex); 12236b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int h = getHeight(); 12246b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (Math.abs(r.centerY() - h * 0.5f) > 0.4f * h) { 12256b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int duration = mPositionController 12266b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang .flingFilmY(mTouchBoxIndex, 0); 12276b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (duration >= 0) { 12286b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mPositionController.setPopFromTop(r.centerY() < h * 0.5f); 12296b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang deleteAfterAnimation(duration); 12306b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 12316b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 12326b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 12336b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 12343a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang if (mIgnoreUpEvent) { 12353a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang mIgnoreUpEvent = false; 12363a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang return; 12373a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang } 1238b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 12392c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang snapback(); 1240f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 12416575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang 12426575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang public void setSwipingEnabled(boolean enabled) { 12436575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang mIgnoreSwipingGesture = !enabled; 12446575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang } 12456575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang } 12466575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang 12476575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang public void setSwipingEnabled(boolean enabled) { 12486575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang mGestureListener.setSwipingEnabled(enabled); 1249f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1250f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1251b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void setFilmMode(boolean enabled) { 1252b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mFilmMode == enabled) return; 1253b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mFilmMode = enabled; 1254b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.setFilmMode(mFilmMode); 1255b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang mModel.setNeedFullImage(!enabled); 12566b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mModel.setFocusHintDirection( 12576b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mFilmMode ? Model.FOCUS_HINT_PREVIOUS : Model.FOCUS_HINT_NEXT); 125861f94714c3702115d2f89bb5f8829697be0c3680Chih-Chung Chang mListener.onActionBarAllowed(!enabled); 1259bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 1260e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang // Move into camera in page mode, lock 1261e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang if (!enabled && mPictures.get(0).isCamera()) { 1262e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang mListener.lockOrientation(); 1263bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 1264bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 1265bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 1266bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public boolean getFilmMode() { 1267bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang return mFilmMode; 1268f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1269f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1270b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1271b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Framework events 1272b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1273b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1274b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void pause() { 1275b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.skipAnimation(); 1276b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mTileView.freeTextures(); 1277b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = -SCREEN_NAIL_MAX; i <= SCREEN_NAIL_MAX; i++) { 1278b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang mPictures.get(i).setScreenNail(null); 1279b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 12806118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang hideUndoBar(); 1281f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1282f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1283b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void resume() { 1284b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mTileView.prepareTextures(); 1285f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1286f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 128733f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang // move to the camera preview and show controls after resume 128833f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang public void resetToFirstPicture() { 128933f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang mModel.moveTo(0); 129033f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang setFilmMode(false); 129133f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang } 129233f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang 1293517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1294517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang // Undo Bar 1295517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1296517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang 1297517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang private int mUndoBarState; 1298517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang private static final int UNDO_BAR_SHOW = 1; 1299517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang private static final int UNDO_BAR_TIMEOUT = 2; 1300517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang private static final int UNDO_BAR_TOUCHED = 4; 13016118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang private static final int UNDO_BAR_FULL_CAMERA = 8; 13026118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang private static final int UNDO_BAR_DELETE_LAST = 16; 1303517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang 13046118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang // "deleteLast" means if the deletion is on the last remaining picture in 13056118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang // the album. 13066118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang private void showUndoBar(boolean deleteLast) { 13076118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang mHandler.removeMessages(MSG_UNDO_BAR_TIMEOUT); 1308517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang mUndoBarState = UNDO_BAR_SHOW; 13096118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang if(deleteLast) mUndoBarState |= UNDO_BAR_DELETE_LAST; 1310517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang mUndoBar.animateVisibility(GLView.VISIBLE); 13116118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang mHandler.sendEmptyMessageDelayed(MSG_UNDO_BAR_TIMEOUT, 3000); 1312517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang } 1313517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang 13146118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang private void hideUndoBar() { 13156118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang mHandler.removeMessages(MSG_UNDO_BAR_TIMEOUT); 1316517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang mListener.onCommitDeleteImage(); 1317517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang mUndoBar.animateVisibility(GLView.INVISIBLE); 1318517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang mUndoBarState = 0; 1319517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang mUndoIndexHint = Integer.MAX_VALUE; 1320517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang } 1321517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang 13226118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang // Check if the one of the conditions for hiding the undo bar has been 13236118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang // met. The conditions are: 13246118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang // 13256118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang // 1. It has been three seconds since last showing, and (a) the user has 13266118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang // touched, or (b) the deleted picture is the last remaining picture in the 13276118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang // album. 13286118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang // 13296118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang // 2. The camera is shown in full screen. 1330517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang private void checkHideUndoBar(int addition) { 1331517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang mUndoBarState |= addition; 13326118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang if ((mUndoBarState & UNDO_BAR_SHOW) == 0) return; 13336118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang boolean timeout = (mUndoBarState & UNDO_BAR_TIMEOUT) != 0; 13346118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang boolean touched = (mUndoBarState & UNDO_BAR_TOUCHED) != 0; 13356118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang boolean fullCamera = (mUndoBarState & UNDO_BAR_FULL_CAMERA) != 0; 13366118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang boolean deleteLast = (mUndoBarState & UNDO_BAR_DELETE_LAST) != 0; 13376118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang if ((timeout && (touched || deleteLast)) || fullCamera) { 1338517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang hideUndoBar(); 1339517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang } 13406b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 13416b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 13426118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang // Returns true if the user can still undo the deletion of the last 13436118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang // remaining picture in the album. We need to check this and delay making 13446118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang // the camera preview full screen, otherwise the user won't have a chance to 13456118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang // undo it. 13466118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang private boolean canUndoLastPicture() { 13476118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang if ((mUndoBarState & UNDO_BAR_SHOW) == 0) return false; 13486118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang return (mUndoBarState & UNDO_BAR_DELETE_LAST) != 0; 13496118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang } 13506118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang 1351b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1352b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Rendering 1353b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1354b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1355b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 1356b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang protected void render(GLCanvas canvas) { 13579f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang // Check if the camera preview occupies the full screen. 13589f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang boolean full = !mFilmMode && mPictures.get(0).isCamera() 13599f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang && mPositionController.isCenter() 13609f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang && mPositionController.isAtMinimalScale(); 13619f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang if (full != mFullScreenCamera) { 13629f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang mFullScreenCamera = full; 13639f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang mListener.onFullScreenChanged(full); 13646118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang if (full) mHandler.sendEmptyMessage(MSG_UNDO_BAR_FULL_CAMERA); 13659f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang } 13669f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang 13679f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang // Determine how many photos we need to draw in addition to the center 13689f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang // one. 13699f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang int neighbors; 13709f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang if (mFullScreenCamera) { 13719f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang neighbors = 0; 13729f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang } else { 13739f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang // In page mode, we draw only one previous/next photo. But if we are 13749f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang // doing capture animation, we want to draw all photos. 13759f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang boolean inPageMode = (mPositionController.getFilmRatio() == 0f); 13769f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang boolean inCaptureAnimation = 13779f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang ((mHolding & HOLD_CAPTURE_ANIMATION) != 0); 13789f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang if (inPageMode && !inCaptureAnimation) { 13799f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang neighbors = 1; 13809f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang } else { 13819f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang neighbors = SCREEN_NAIL_MAX; 13829f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang } 13839f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang } 1384c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang 1385c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang // Draw photos from back to front 1386c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang for (int i = neighbors; i >= -neighbors; i--) { 1387b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Rect r = mPositionController.getPosition(i); 1388b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPictures.get(i).draw(canvas, r); 1389b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1390b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 13916b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang renderChild(canvas, mEdgeView); 13926b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang renderChild(canvas, mUndoBar); 13936b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 1394b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.advanceAnimation(); 1395b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang checkFocusSwitching(); 1396ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang } 1397ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 1398b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1399b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Film mode focus switching 1400b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1401f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1402b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Runs in GL thread. 1403b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void checkFocusSwitching() { 1404b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (!mFilmMode) return; 1405b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mHandler.hasMessages(MSG_SWITCH_FOCUS)) return; 1406b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (switchPosition() != 0) { 1407b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mHandler.sendEmptyMessage(MSG_SWITCH_FOCUS); 1408f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1409f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1410f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1411b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Runs in main thread. 1412b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void switchFocus() { 14132c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (mHolding != 0) return; 1414b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang switch (switchPosition()) { 1415b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang case -1: 1416b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang switchToPrevImage(); 1417b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang break; 1418b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang case 1: 1419b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang switchToNextImage(); 1420b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang break; 1421b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1422f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1423f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1424b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Returns -1 if we should switch focus to the previous picture, +1 if we 1425b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // should switch to the next, 0 otherwise. 1426b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private int switchPosition() { 1427b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Rect curr = mPositionController.getPosition(0); 1428b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int center = getWidth() / 2; 1429f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 14302c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (curr.left > center && mPrevBound < 0) { 1431b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Rect prev = mPositionController.getPosition(-1); 1432b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int currDist = curr.left - center; 1433b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int prevDist = center - prev.right; 1434b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (prevDist < currDist) { 1435b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return -1; 1436b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 14372c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } else if (curr.right < center && mNextBound > 0) { 1438b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Rect next = mPositionController.getPosition(1); 1439b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int currDist = center - curr.right; 1440b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int nextDist = next.left - center; 1441b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (nextDist < currDist) { 1442b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return 1; 1443b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1444b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1445f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1446b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return 0; 1447f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1448f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 144917ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang // Switch to the previous or next picture if the hit position is inside 145017ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang // one of their boxes. This runs in main thread. 145117ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang private void switchToHitPicture(int x, int y) { 145217ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang if (mPrevBound < 0) { 145317ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang Rect r = mPositionController.getPosition(-1); 145417ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang if (r.right >= x) { 145517ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang slideToPrevPicture(); 145617ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang return; 145717ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang } 145817ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang } 145917ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang 146017ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang if (mNextBound > 0) { 146117ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang Rect r = mPositionController.getPosition(1); 146217ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang if (r.left <= x) { 146317ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang slideToNextPicture(); 146417ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang return; 146517ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang } 146617ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang } 146717ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang } 146817ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang 1469b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1470b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Page mode focus switching 1471b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // 1472b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // We slide image to the next one or the previous one in two cases: 1: If 1473b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // the user did a fling gesture with enough velocity. 2 If the user has 1474b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // moved the picture a lot. 1475b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1476f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1477b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private boolean swipeImages(float velocityX, float velocityY) { 1478b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mFilmMode) return false; 1479f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1480b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Avoid swiping images if we're possibly flinging to view the 1481b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // zoomed in picture vertically. 1482b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang PositionController controller = mPositionController; 1483b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang boolean isMinimal = controller.isAtMinimalScale(); 1484b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int edges = controller.getImageAtEdges(); 1485b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (!isMinimal && Math.abs(velocityY) > Math.abs(velocityX)) 1486b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if ((edges & PositionController.IMAGE_AT_TOP_EDGE) == 0 1487b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang || (edges & PositionController.IMAGE_AT_BOTTOM_EDGE) == 0) 1488b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return false; 1489f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1490b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // If we are at the edge of the current photo and the sweeping velocity 1491b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // exceeds the threshold, slide to the next / previous image. 1492b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (velocityX < -SWIPE_THRESHOLD && (isMinimal 1493b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang || (edges & PositionController.IMAGE_AT_RIGHT_EDGE) != 0)) { 1494b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return slideToNextPicture(); 1495b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } else if (velocityX > SWIPE_THRESHOLD && (isMinimal 1496b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang || (edges & PositionController.IMAGE_AT_LEFT_EDGE) != 0)) { 1497b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return slideToPrevPicture(); 1498f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1499f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1500b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return false; 1501b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1502b29a27f475a2c449abdda8d4e03d30914feed8c6Chih-Chung Chang 15032c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang private void snapback() { 15046b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if ((mHolding & ~HOLD_DELETE) != 0) return; 15052c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (!snapToNeighborImage()) { 15062c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mPositionController.snapback(); 15072c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 15082c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 15092c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang 1510b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private boolean snapToNeighborImage() { 1511b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mFilmMode) return false; 1512f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1513b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Rect r = mPositionController.getPosition(0); 1514b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int viewW = getWidth(); 1515b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int threshold = MOVE_THRESHOLD + gapToSide(r.width(), viewW); 1516f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1517b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // If we have moved the picture a lot, switching. 1518b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (viewW - r.right > threshold) { 1519b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return slideToNextPicture(); 1520b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } else if (r.left > threshold) { 1521b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return slideToPrevPicture(); 1522f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1523f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1524b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return false; 1525b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1526f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1527b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private boolean slideToNextPicture() { 15282c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (mNextBound <= 0) return false; 1529b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang switchToNextImage(); 15302c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mPositionController.startHorizontalSlide(); 1531b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return true; 1532b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1533676170e619ad59ea97d04e0edcd62b1500304845Chih-Chung Chang 1534b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private boolean slideToPrevPicture() { 15352c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (mPrevBound >= 0) return false; 1536b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang switchToPrevImage(); 15372c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mPositionController.startHorizontalSlide(); 1538b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return true; 1539b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1540676170e619ad59ea97d04e0edcd62b1500304845Chih-Chung Chang 1541b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static int gapToSide(int imageWidth, int viewWidth) { 1542b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return Math.max(0, (viewWidth - imageWidth) / 2); 1543b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1544f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1545b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1546b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Focus switching 1547b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1548f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1549b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void switchToNextImage() { 1550bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mModel.moveTo(mModel.getCurrentIndex() + 1); 1551b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 155215b351a22d02e89d882fc9fe32b3f4c512080e0aChih-Chung Chang 1553b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void switchToPrevImage() { 1554bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mModel.moveTo(mModel.getCurrentIndex() - 1); 1555b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1556cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1557160e6d776daab93610b3d12413ad9ff2dd867d8bChih-Chung Chang private void switchToFirstImage() { 1558bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mModel.moveTo(0); 1559160e6d776daab93610b3d12413ad9ff2dd867d8bChih-Chung Chang } 1560160e6d776daab93610b3d12413ad9ff2dd867d8bChih-Chung Chang 1561b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1562b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Opening Animation 1563b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1564b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1565b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void setOpenAnimationRect(Rect rect) { 1566b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.setOpenAnimationRect(rect); 1567cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 156815b351a22d02e89d882fc9fe32b3f4c512080e0aChih-Chung Chang 1569b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 15702c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // Capture Animation 15712c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang //////////////////////////////////////////////////////////////////////////// 15722c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang 15732c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang public boolean switchWithCaptureAnimation(int offset) { 15742c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang GLRoot root = getGLRoot(); 157514ce29ab5608daaa3d0074cdfc9fc85988537ff2Bobby Georgescu if(root == null) return false; 15762c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang root.lockRenderThread(); 15772c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang try { 15782c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang return switchWithCaptureAnimationLocked(offset); 15792c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } finally { 15802c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang root.unlockRenderThread(); 15812c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 15822c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 15832c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang 15842c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang private boolean switchWithCaptureAnimationLocked(int offset) { 15852c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (mHolding != 0) return true; 15862c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (offset == 1) { 15872c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (mNextBound <= 0) return false; 158861f94714c3702115d2f89bb5f8829697be0c3680Chih-Chung Chang // Temporary disable action bar until the capture animation is done. 158961f94714c3702115d2f89bb5f8829697be0c3680Chih-Chung Chang if (!mFilmMode) mListener.onActionBarAllowed(false); 15902c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang switchToNextImage(); 15912c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mPositionController.startCaptureAnimationSlide(-1); 15922c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } else if (offset == -1) { 15932c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (mPrevBound >= 0) return false; 1594c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang if (mFilmMode) setFilmMode(false); 1595c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang 1596c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang // If we are too far away from the first image (so that we don't 1597c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang // have all the ScreenNails in-between), we go directly without 1598c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang // animation. 1599c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang if (mModel.getCurrentIndex() > SCREEN_NAIL_MAX) { 1600c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang switchToFirstImage(); 160142e1fed4edd9ed1e326aab2f7969242c56812952Chih-Chung Chang mPositionController.skipToFinalPosition(); 1602c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang return true; 1603c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang } 1604c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang 1605160e6d776daab93610b3d12413ad9ff2dd867d8bChih-Chung Chang switchToFirstImage(); 16062c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mPositionController.startCaptureAnimationSlide(1); 16072c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } else { 16082c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang return false; 16092c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 16102c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mHolding |= HOLD_CAPTURE_ANIMATION; 1611bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang Message m = mHandler.obtainMessage(MSG_CAPTURE_ANIMATION_DONE, offset, 0); 1612f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang mHandler.sendMessageDelayed(m, PositionController.CAPTURE_ANIMATION_TIME); 16132c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang return true; 16142c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 16152c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang 1616bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private void captureAnimationDone(int offset) { 16172c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mHolding &= ~HOLD_CAPTURE_ANIMATION; 1618e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang if (offset == 1 && !mFilmMode) { 1619e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang // Now the capture animation is done, enable the action bar. 1620e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang mListener.onActionBarAllowed(true); 1621e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang mListener.onActionBarWanted(); 1622bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 16232c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang snapback(); 16242c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 16252c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang 16262c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1627b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Card deck effect calculation 1628b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1629b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1630cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // Returns the scrolling progress value for an object moving out of a 1631cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // view. The progress value measures how much the object has moving out of 1632cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // the view. The object currently displays in [left, right), and the view is 1633cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // at [0, viewWidth]. 1634cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // 1635cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // The returned value is negative when the object is moving right, and 1636cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // positive when the object is moving left. The value goes to -1 or 1 when 1637cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // the object just moves out of the view completely. The value is 0 if the 1638cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // object currently fills the view. 1639cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private static float calculateMoveOutProgress(int left, int right, 1640cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang int viewWidth) { 1641cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // w = object width 1642cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // viewWidth = view width 1643cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang int w = right - left; 1644cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1645cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // If the object width is smaller than the view width, 1646cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // |....view....| 1647cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // |<-->| progress = -1 when left = viewWidth 1648bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // |<-->| progress = 0 when left = viewWidth / 2 - w / 2 1649cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // |<-->| progress = 1 when left = -w 1650cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang if (w < viewWidth) { 1651bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang int zx = viewWidth / 2 - w / 2; 1652bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (left > zx) { 1653bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang return -(left - zx) / (float) (viewWidth - zx); // progress = (0, -1] 1654bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } else { 1655bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang return (left - zx) / (float) (-w - zx); // progress = [0, 1] 1656bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 1657cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 1658cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1659cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // If the object width is larger than the view width, 1660cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // |..view..| 1661cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // |<--------->| progress = -1 when left = viewWidth 1662cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // |<--------->| progress = 0 between left = 0 1663cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // |<--------->| and right = viewWidth 1664cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // |<--------->| progress = 1 when right = 0 1665cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang if (left > 0) { 1666cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang return -left / (float) viewWidth; 1667cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 1668cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1669cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang if (right < viewWidth) { 1670cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang return (viewWidth - right) / (float) viewWidth; 1671cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 1672cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1673cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang return 0; 1674cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 1675cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1676cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // Maps a scrolling progress value to the alpha factor in the fading 1677cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // animation. 1678cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private float getScrollAlpha(float scrollProgress) { 1679cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang return scrollProgress < 0 ? mAlphaInterpolator.getInterpolation( 1680cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1 - Math.abs(scrollProgress)) : 1.0f; 1681cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 1682cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1683cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // Maps a scrolling progress value to the scaling factor in the fading 1684cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // animation. 1685cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private float getScrollScale(float scrollProgress) { 1686cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang float interpolatedProgress = mScaleInterpolator.getInterpolation( 1687cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang Math.abs(scrollProgress)); 1688cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang float scale = (1 - interpolatedProgress) + 1689cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang interpolatedProgress * TRANSITION_SCALE_FACTOR; 1690cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang return scale; 1691cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 1692cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1693cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1694cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // This interpolator emulates the rate at which the perceived scale of an 1695cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // object changes as its distance from a camera increases. When this 1696cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // interpolator is applied to a scale animation on a view, it evokes the 1697cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // sense that the object is shrinking due to moving away from the camera. 1698cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private static class ZInterpolator { 1699cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private float focalLength; 1700cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1701cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang public ZInterpolator(float foc) { 1702cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang focalLength = foc; 1703cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 1704cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1705cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang public float getInterpolation(float input) { 1706cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang return (1.0f - focalLength / (focalLength + input)) / 1707cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang (1.0f - focalLength / (focalLength + 1.0f)); 1708f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1709f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1710f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1711ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang // Returns an interpolated value for the page/film transition. 1712ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang // When ratio = 0, the result is from. 1713ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang // When ratio = 1, the result is to. 1714ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang private static float interpolate(float ratio, float from, float to) { 1715ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang return from + (to - from) * ratio * ratio; 1716ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang } 1717ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang 17186b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // Returns the alpha factor in film mode if a picture is not in the center. 17196b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // The 0.03 lower bound is to make the item always visible a bit. 17206b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private float getOffsetAlpha(float offset) { 17216b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang offset /= 0.5f; 17226b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang float alpha = (offset > 0) ? (1 - offset) : (1 + offset); 17236b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang return Utils.clamp(alpha, 0.03f, 1f); 17246b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 17256b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 1726b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1727b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Simple public utilities 1728b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1729f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1730bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public void setListener(Listener listener) { 1731bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mListener = listener; 1732f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1733616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin 1734616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin public Rect getPhotoRect(int index) { 1735616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin return mPositionController.getPosition(index); 1736616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin } 1737616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin 1738616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin public PhotoFallbackEffect buildFallbackEffect(GLView root, GLCanvas canvas) { 1739616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin Rect location = new Rect(); 1740616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin Utils.assertTrue(root.getBoundsOf(this, location)); 1741616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin 1742616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin Rect fullRect = bounds(); 1743616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin PhotoFallbackEffect effect = new PhotoFallbackEffect(); 1744616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin for (int i = -SCREEN_NAIL_MAX; i <= SCREEN_NAIL_MAX; ++i) { 1745616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin MediaItem item = mModel.getMediaItem(i); 1746616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin if (item == null) continue; 1747616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin ScreenNail sc = mModel.getScreenNail(i); 174849affdc4e274098a34e4eb2dbe4a89a750f1ba7fOwen Lin if (!(sc instanceof BitmapScreenNail) 174949affdc4e274098a34e4eb2dbe4a89a750f1ba7fOwen Lin || ((BitmapScreenNail) sc).isShowingPlaceholder()) continue; 175049affdc4e274098a34e4eb2dbe4a89a750f1ba7fOwen Lin 175149affdc4e274098a34e4eb2dbe4a89a750f1ba7fOwen Lin // Now, sc is BitmapScreenNail and is not showing placeholder 1752616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin Rect rect = new Rect(getPhotoRect(i)); 1753616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin if (!Rect.intersects(fullRect, rect)) continue; 1754616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin rect.offset(location.left, location.top); 1755616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin 175638155c4f4dd6f0173337eb9f3fea54803192e229Owen Lin int width = sc.getWidth(); 175738155c4f4dd6f0173337eb9f3fea54803192e229Owen Lin int height = sc.getHeight(); 175838155c4f4dd6f0173337eb9f3fea54803192e229Owen Lin 175938155c4f4dd6f0173337eb9f3fea54803192e229Owen Lin int rotation = mModel.getImageRotation(i); 176038155c4f4dd6f0173337eb9f3fea54803192e229Owen Lin RawTexture texture; 176138155c4f4dd6f0173337eb9f3fea54803192e229Owen Lin if ((rotation % 180) == 0) { 176238155c4f4dd6f0173337eb9f3fea54803192e229Owen Lin texture = new RawTexture(width, height, true); 176338155c4f4dd6f0173337eb9f3fea54803192e229Owen Lin canvas.beginRenderTarget(texture); 176438155c4f4dd6f0173337eb9f3fea54803192e229Owen Lin canvas.translate(width / 2f, height / 2f); 176538155c4f4dd6f0173337eb9f3fea54803192e229Owen Lin } else { 176638155c4f4dd6f0173337eb9f3fea54803192e229Owen Lin texture = new RawTexture(height, width, true); 176738155c4f4dd6f0173337eb9f3fea54803192e229Owen Lin canvas.beginRenderTarget(texture); 176838155c4f4dd6f0173337eb9f3fea54803192e229Owen Lin canvas.translate(height / 2f, width / 2f); 176938155c4f4dd6f0173337eb9f3fea54803192e229Owen Lin } 177038155c4f4dd6f0173337eb9f3fea54803192e229Owen Lin 177138155c4f4dd6f0173337eb9f3fea54803192e229Owen Lin canvas.rotate(rotation, 0, 0, 1); 177238155c4f4dd6f0173337eb9f3fea54803192e229Owen Lin canvas.translate(-width / 2f, -height / 2f); 177338155c4f4dd6f0173337eb9f3fea54803192e229Owen Lin sc.draw(canvas, 0, 0, width, height); 1774616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin canvas.endRenderTarget(); 1775616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin effect.addEntry(item.getPath(), rect, texture); 1776616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin } 1777616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin return effect; 1778616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin } 1779f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin} 1780