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; 20b1a28418848ce0adeb8a845a78e246b01913d176John Reckimport android.content.res.Configuration; 21f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.graphics.Color; 222ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Changimport android.graphics.Matrix; 2304ac045bf8da5082bbb0bdc9ea5f9c9b5b796ad0Yuli Huangimport android.graphics.Rect; 244d47b3472cccf84e8c71d8fb389a79bc83b321eeHung-ying Tyanimport android.os.Build; 25f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.os.Message; 266b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Changimport android.util.FloatMath; 27f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.view.MotionEvent; 286b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Changimport android.view.View.MeasureSpec; 29cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Changimport android.view.animation.AccelerateInterpolator; 30f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 312b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Linimport com.android.gallery3d.R; 32b21b8e58a604f6c701245d84b141b5b87663192bOwen Linimport com.android.gallery3d.app.AbstractGalleryActivity; 334d47b3472cccf84e8c71d8fb389a79bc83b321eeHung-ying Tyanimport com.android.gallery3d.common.ApiHelper; 34cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Changimport com.android.gallery3d.common.Utils; 35616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Linimport com.android.gallery3d.data.MediaItem; 36b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Changimport com.android.gallery3d.data.MediaObject; 376b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Changimport com.android.gallery3d.data.Path; 38a4eae1abb4f2547dfbda84301ee764ce35464881John Reckimport com.android.gallery3d.glrenderer.GLCanvas; 39a4eae1abb4f2547dfbda84301ee764ce35464881John Reckimport com.android.gallery3d.glrenderer.RawTexture; 40a4eae1abb4f2547dfbda84301ee764ce35464881John Reckimport com.android.gallery3d.glrenderer.ResourceTexture; 41a4eae1abb4f2547dfbda84301ee764ce35464881John Reckimport com.android.gallery3d.glrenderer.StringTexture; 42a4eae1abb4f2547dfbda84301ee764ce35464881John Reckimport com.android.gallery3d.glrenderer.Texture; 436b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Changimport com.android.gallery3d.util.GalleryUtils; 44b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Changimport com.android.gallery3d.util.RangeArray; 45f37648b877bf6029d7afead31e965b473114c89cBobby Georgescuimport com.android.gallery3d.util.UsageStatistics; 46b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 47f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpublic class PhotoView extends GLView { 48f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @SuppressWarnings("unused") 49f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final String TAG = "PhotoView"; 50915c2c5b2c367df71599370613af0924bd7c4887Bobby Georgescu private final int mPlaceholderColor; 51f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 52f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static final int INVALID_SIZE = -1; 53b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public static final long INVALID_DATA_VERSION = 54b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang MediaObject.INVALID_DATA_VERSION; 55f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 56c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang public static class Size { 57c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang public int width; 58c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang public int height; 59c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang } 60c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang 616dc3866ac10cc6bf38e73f098fe1988d1a6eecd4Your Name public interface Model extends TileImageView.TileSource { 62bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public int getCurrentIndex(); 63bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public void moveTo(int index); 64c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang 65c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // Returns the size for the specified picture. If the size information is 66c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // not avaiable, width = height = 0. 67c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang public void getImageSize(int offset, Size size); 68c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang 69616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin // Returns the media item for the specified picture. 70616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin public MediaItem getMediaItem(int offset); 71616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin 72c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // Returns the rotation for the specified picture. 73c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang public int getImageRotation(int offset); 74f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 75b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // This amends the getScreenNail() method of TileImageView.Model to get 76b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // ScreenNail at previous (negative offset) or next (positive offset) 77b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // positions. Returns null if the specified ScreenNail is unavailable. 78b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public ScreenNail getScreenNail(int offset); 79c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang 80c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // Set this to true if we need the model to provide full images. 81b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang public void setNeedFullImage(boolean enabled); 82bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 83bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // Returns true if the item is the Camera preview. 84bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public boolean isCamera(int offset); 85d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang 8643a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong // Returns true if the item is the Panorama. 8743a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong public boolean isPanorama(int offset); 8843a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong 89dbb6acc204ba6f095eb0e49e1298e9ceda2c3096Wu-cheng Li // Returns true if the item is a static image that represents camera 90dbb6acc204ba6f095eb0e49e1298e9ceda2c3096Wu-cheng Li // preview. 91dbb6acc204ba6f095eb0e49e1298e9ceda2c3096Wu-cheng Li public boolean isStaticCamera(int offset); 92dbb6acc204ba6f095eb0e49e1298e9ceda2c3096Wu-cheng Li 93d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang // Returns true if the item is a Video. 94d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang public boolean isVideo(int offset); 95f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang 966b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // Returns true if the item can be deleted. 976b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public boolean isDeletable(int offset); 986b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 99f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang public static final int LOADING_INIT = 0; 100f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang public static final int LOADING_COMPLETE = 1; 101f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang public static final int LOADING_FAIL = 2; 102f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang 103f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang public int getLoadingState(int offset); 1046b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 1056b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // When data change happens, we need to decide which MediaItem to focus 1066b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // on. 1076b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // 1086b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // 1. If focus hint path != null, we try to focus on it if we can find 1096b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // it. This is used for undo a deletion, so we can focus on the 1106b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // undeleted item. 1116b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // 1126b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // 2. Otherwise try to focus on the MediaItem that is currently focused, 1136b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // if we can find it. 1146b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // 1156b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // 3. Otherwise try to focus on the previous MediaItem or the next 1166b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // MediaItem, depending on the value of focus hint direction. 1176b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public static final int FOCUS_HINT_NEXT = 0; 1186b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public static final int FOCUS_HINT_PREVIOUS = 1; 1196b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public void setFocusHintDirection(int direction); 1206b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public void setFocusHintPath(Path path); 121b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 122b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 123bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public interface Listener { 124b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void onSingleTapUp(int x, int y); 125bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public void onFullScreenChanged(boolean full); 12661f94714c3702115d2f89bb5f8829697be0c3680Chih-Chung Chang public void onActionBarAllowed(boolean allowed); 127e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang public void onActionBarWanted(); 128bd7c016d728853d38f98a3c6077b7bd9b08858b9Yuli Huang public void onCurrentImageUpdated(); 1296b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public void onDeleteImage(Path path, int offset); 1306b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public void onUndoDeleteImage(); 1316b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public void onCommitDeleteImage(); 1327eea4d3ac59aa88d327fc0d58f5e4052f43c54c9Bobby Georgescu public void onFilmModeChanged(boolean enabled); 133f4e22eb44bfae0c2a3b6570f19480c8c3535d808Bobby Georgescu public void onPictureCenter(boolean isCamera); 134949584340c9f5f41a6133ba06058af280490f0c8Bobby Georgescu public void onUndoBarVisibilityChanged(boolean visible); 135b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 136f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 137e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang // The rules about orientation locking: 138bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // 139e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang // (1) We need to lock the orientation if we are in page mode camera 140e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang // preview, so there is no (unwanted) rotation animation when the user 141e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang // rotates the device. 142bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // 143e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang // (2) We need to unlock the orientation if we want to show the action bar 144e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang // because the action bar follows the system orientation. 145bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // 146e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang // The rules about action bar: 147bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // 148e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang // (1) If we are in film mode, we don't show action bar. 149e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang // 150e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang // (2) If we go from camera to gallery with capture animation, we show 151e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang // action bar. 152b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static final int MSG_CANCEL_EXTRA_SCALING = 2; 153b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static final int MSG_SWITCH_FOCUS = 3; 1542c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang private static final int MSG_CAPTURE_ANIMATION_DONE = 4; 1556b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private static final int MSG_DELETE_ANIMATION_DONE = 5; 1566b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private static final int MSG_DELETE_DONE = 6; 1576118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang private static final int MSG_UNDO_BAR_TIMEOUT = 7; 1586118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang private static final int MSG_UNDO_BAR_FULL_CAMERA = 8; 159f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 160f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final float SWIPE_THRESHOLD = 300f; 161f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 162f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final float DEFAULT_TEXT_SIZE = 20; 163cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private static float TRANSITION_SCALE_FACTOR = 0.74f; 164d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang private static final int ICON_RATIO = 6; 1652c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang 1662c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // whether we want to apply card deck effect in page mode. 167b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static final boolean CARD_EFFECT = true; 168cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1696b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // whether we want to apply offset effect in film mode. 1706b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private static final boolean OFFSET_EFFECT = true; 1716b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 1726b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // Used to calculate the scaling factor for the card deck effect. 173cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private ZInterpolator mScaleInterpolator = new ZInterpolator(0.5f); 174cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 175cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // Used to calculate the alpha factor for the fading animation. 176cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private AccelerateInterpolator mAlphaInterpolator = 177cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang new AccelerateInterpolator(0.9f); 178f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 179b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // We keep this many previous ScreenNails. (also this many next ScreenNails) 180b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public static final int SCREEN_NAIL_MAX = 3; 181b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1826b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // These are constants for the delete gesture. 183137c6d060f9710f1a460326f27459e89b49820c2Bobby Georgescu private static final int SWIPE_ESCAPE_VELOCITY = 500; // dp/sec 184137c6d060f9710f1a460326f27459e89b49820c2Bobby Georgescu private static final int MAX_DISMISS_VELOCITY = 2500; // dp/sec 185137c6d060f9710f1a460326f27459e89b49820c2Bobby Georgescu private static final int SWIPE_ESCAPE_DISTANCE = 150; // dp 1866b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 187b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // The picture entries, the valid index is from -SCREEN_NAIL_MAX to 188b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // SCREEN_NAIL_MAX. 189b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private final RangeArray<Picture> mPictures = 190b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang new RangeArray<Picture>(-SCREEN_NAIL_MAX, SCREEN_NAIL_MAX); 1916b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private Size[] mSizes = new Size[2 * SCREEN_NAIL_MAX + 1]; 192f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1936575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang private final MyGestureListener mGestureListener; 1943a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang private final GestureRecognizer mGestureRecognizer; 195f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final PositionController mPositionController; 196f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 197bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private Listener mListener; 198f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private Model mModel; 199f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private StringTexture mNoThumbnailText; 200b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private TileImageView mTileView; 201532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private EdgeView mEdgeView; 2026b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private UndoBarView mUndoBar; 203f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private Texture mVideoPlayIcon; 204f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 205f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private SynchronizedHandler mHandler; 206f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 207534b12fd804610dd67b8109bc08ba76f31afb33eChih-Chung Chang private boolean mCancelExtraScalingPending; 208b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private boolean mFilmMode = false; 209f4e22eb44bfae0c2a3b6570f19480c8c3535d808Bobby Georgescu private boolean mWantPictureCenterCallbacks = false; 210bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private int mDisplayRotation = 0; 211bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private int mCompensation = 0; 2129f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang private boolean mFullScreenCamera; 2132ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang private Rect mCameraRelativeFrame = new Rect(); 214bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private Rect mCameraRect = new Rect(); 2156bf226e45ec542eae4f766a2417bfdda625af4f0Michael Kolb private boolean mFirst = true; 216f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 217c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // [mPrevBound, mNextBound] is the range of index for all pictures in the 218c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // model, if we assume the index of current focused picture is 0. So if 219c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // there are some previous pictures, mPrevBound < 0, and if there are some 220c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // next pictures, mNextBound > 0. 221c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang private int mPrevBound; 222c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang private int mNextBound; 223c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang 2242c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // This variable prevents us doing snapback until its values goes to 0. This 2252c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // happens if the user gesture is still in progress or we are in a capture 2262c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // animation. 2272c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang private int mHolding; 2282c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang private static final int HOLD_TOUCH_DOWN = 1; 22918958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang private static final int HOLD_CAPTURE_ANIMATION = 2; 2306b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private static final int HOLD_DELETE = 4; 2316b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 2326b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // mTouchBoxIndex is the index of the box that is touched by the down 2336b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // gesture in film mode. The value Integer.MAX_VALUE means no box was 2346b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // touched. 2356b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private int mTouchBoxIndex = Integer.MAX_VALUE; 2366b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // Whether the box indicated by mTouchBoxIndex is deletable. Only meaningful 2376b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // if mTouchBoxIndex is not Integer.MAX_VALUE. 2386b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private boolean mTouchBoxDeletable; 239517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang // This is the index of the last deleted item. This is only used as a hint 240517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang // to hide the undo button when we are too far away from the deleted 241517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang // item. The value Integer.MAX_VALUE means there is no such hint. 242517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang private int mUndoIndexHint = Integer.MAX_VALUE; 2432c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang 244e6c566e7e25b7f961f501c878e98d3ca640e63d8John Reck private Context mContext; 245e6c566e7e25b7f961f501c878e98d3ca640e63d8John Reck 246b21b8e58a604f6c701245d84b141b5b87663192bOwen Lin public PhotoView(AbstractGalleryActivity activity) { 247f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mTileView = new TileImageView(activity); 248f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin addComponent(mTileView); 249e6c566e7e25b7f961f501c878e98d3ca640e63d8John Reck mContext = activity.getAndroidContext(); 250e6c566e7e25b7f961f501c878e98d3ca640e63d8John Reck mPlaceholderColor = mContext.getResources().getColor( 251915c2c5b2c367df71599370613af0924bd7c4887Bobby Georgescu R.color.photo_placeholder); 252e6c566e7e25b7f961f501c878e98d3ca640e63d8John Reck mEdgeView = new EdgeView(mContext); 253532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang addComponent(mEdgeView); 254e6c566e7e25b7f961f501c878e98d3ca640e63d8John Reck mUndoBar = new UndoBarView(mContext); 2556b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang addComponent(mUndoBar); 2566b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mUndoBar.setVisibility(GLView.INVISIBLE); 2576b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mUndoBar.setOnClickListener(new OnClickListener() { 2586b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang @Override 2596b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public void onClick(GLView v) { 2606b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mListener.onUndoDeleteImage(); 2616118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang hideUndoBar(); 2626b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 2636b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang }); 264f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mNoThumbnailText = StringTexture.newInstance( 265e6c566e7e25b7f961f501c878e98d3ca640e63d8John Reck mContext.getString(R.string.no_thumbnail), 266f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin DEFAULT_TEXT_SIZE, Color.WHITE); 267f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 268b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mHandler = new MyHandler(activity.getGLRoot()); 269f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 2706575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang mGestureListener = new MyGestureListener(); 271e6c566e7e25b7f961f501c878e98d3ca640e63d8John Reck mGestureRecognizer = new GestureRecognizer(mContext, mGestureListener); 272f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 273e6c566e7e25b7f961f501c878e98d3ca640e63d8John Reck mPositionController = new PositionController(mContext, 274b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang new PositionController.Listener() { 27528cb4161da5fc3756933ca67d509b8af1c6275f1Owen Lin 27628cb4161da5fc3756933ca67d509b8af1c6275f1Owen Lin @Override 27728cb4161da5fc3756933ca67d509b8af1c6275f1Owen Lin public void invalidate() { 27828cb4161da5fc3756933ca67d509b8af1c6275f1Owen Lin PhotoView.this.invalidate(); 27928cb4161da5fc3756933ca67d509b8af1c6275f1Owen Lin } 28028cb4161da5fc3756933ca67d509b8af1c6275f1Owen Lin 28128cb4161da5fc3756933ca67d509b8af1c6275f1Owen Lin @Override 28228cb4161da5fc3756933ca67d509b8af1c6275f1Owen Lin public boolean isHoldingDown() { 28328cb4161da5fc3756933ca67d509b8af1c6275f1Owen Lin return (mHolding & HOLD_TOUCH_DOWN) != 0; 28428cb4161da5fc3756933ca67d509b8af1c6275f1Owen Lin } 28528cb4161da5fc3756933ca67d509b8af1c6275f1Owen Lin 28628cb4161da5fc3756933ca67d509b8af1c6275f1Owen Lin @Override 28728cb4161da5fc3756933ca67d509b8af1c6275f1Owen Lin public boolean isHoldingDelete() { 28828cb4161da5fc3756933ca67d509b8af1c6275f1Owen Lin return (mHolding & HOLD_DELETE) != 0; 28928cb4161da5fc3756933ca67d509b8af1c6275f1Owen Lin } 29028cb4161da5fc3756933ca67d509b8af1c6275f1Owen Lin 29128cb4161da5fc3756933ca67d509b8af1c6275f1Owen Lin @Override 29228cb4161da5fc3756933ca67d509b8af1c6275f1Owen Lin public void onPull(int offset, int direction) { 29328cb4161da5fc3756933ca67d509b8af1c6275f1Owen Lin mEdgeView.onPull(offset, direction); 29428cb4161da5fc3756933ca67d509b8af1c6275f1Owen Lin } 29528cb4161da5fc3756933ca67d509b8af1c6275f1Owen Lin 29628cb4161da5fc3756933ca67d509b8af1c6275f1Owen Lin @Override 29728cb4161da5fc3756933ca67d509b8af1c6275f1Owen Lin public void onRelease() { 29828cb4161da5fc3756933ca67d509b8af1c6275f1Owen Lin mEdgeView.onRelease(); 29928cb4161da5fc3756933ca67d509b8af1c6275f1Owen Lin } 30028cb4161da5fc3756933ca67d509b8af1c6275f1Owen Lin 30128cb4161da5fc3756933ca67d509b8af1c6275f1Owen Lin @Override 30228cb4161da5fc3756933ca67d509b8af1c6275f1Owen Lin public void onAbsorb(int velocity, int direction) { 30328cb4161da5fc3756933ca67d509b8af1c6275f1Owen Lin mEdgeView.onAbsorb(velocity, direction); 30428cb4161da5fc3756933ca67d509b8af1c6275f1Owen Lin } 30528cb4161da5fc3756933ca67d509b8af1c6275f1Owen Lin }); 306e6c566e7e25b7f961f501c878e98d3ca640e63d8John Reck mVideoPlayIcon = new ResourceTexture(mContext, R.drawable.ic_control_play); 307b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = -SCREEN_NAIL_MAX; i <= SCREEN_NAIL_MAX; i++) { 308b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (i == 0) { 309b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPictures.put(i, new FullPicture()); 310cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } else { 311b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPictures.put(i, new ScreenNailPicture(i)); 312cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 313f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 314f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 315f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 316b27df4650459068b409924493bbadaf25bb7e191Bobby Georgescu public void stopScrolling() { 317b27df4650459068b409924493bbadaf25bb7e191Bobby Georgescu mPositionController.stopScrolling(); 318b27df4650459068b409924493bbadaf25bb7e191Bobby Georgescu } 319b27df4650459068b409924493bbadaf25bb7e191Bobby Georgescu 320b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void setModel(Model model) { 321b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mModel = model; 322b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mTileView.setModel(mModel); 323f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 324f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 325b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang class MyHandler extends SynchronizedHandler { 326b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public MyHandler(GLRoot root) { 327b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang super(root); 328f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 329f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 330b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 331b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void handleMessage(Message message) { 332b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang switch (message.what) { 333b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang case MSG_CANCEL_EXTRA_SCALING: { 334b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mGestureRecognizer.cancelScale(); 335b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.setExtraScalingRange(false); 336b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mCancelExtraScalingPending = false; 337b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang break; 338b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 339b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang case MSG_SWITCH_FOCUS: { 340b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang switchFocus(); 341b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang break; 342b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 3432c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang case MSG_CAPTURE_ANIMATION_DONE: { 344bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // message.arg1 is the offset parameter passed to 345bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // switchWithCaptureAnimation(). 346bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang captureAnimationDone(message.arg1); 3472c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang break; 3482c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 3496b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang case MSG_DELETE_ANIMATION_DONE: { 3506b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // message.obj is the Path of the MediaItem which should be 3516b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // deleted. message.arg1 is the offset of the image. 3526b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mListener.onDeleteImage((Path) message.obj, message.arg1); 3536b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // Normally a box which finishes delete animation will hold 3546b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // position until the underlying MediaItem is actually 3556b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // deleted, and HOLD_DELETE will be cancelled that time. In 3566b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // case the MediaItem didn't actually get deleted in 2 3576b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // seconds, we will cancel HOLD_DELETE and make it bounce 3586b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // back. 3596b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 3606b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // We make sure there is at most one MSG_DELETE_DONE 3616b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // in the handler. 3626b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mHandler.removeMessages(MSG_DELETE_DONE); 3636b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang Message m = mHandler.obtainMessage(MSG_DELETE_DONE); 3646b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mHandler.sendMessageDelayed(m, 2000); 3656118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang 3666118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang int numberOfPictures = mNextBound - mPrevBound + 1; 3676118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang if (numberOfPictures == 2) { 3686118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang if (mModel.isCamera(mNextBound) 3696118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang || mModel.isCamera(mPrevBound)) { 3706118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang numberOfPictures--; 3716118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang } 3726118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang } 3736118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang showUndoBar(numberOfPictures <= 1); 3746b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang break; 3756b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 3766b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang case MSG_DELETE_DONE: { 3776b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (!mHandler.hasMessages(MSG_DELETE_ANIMATION_DONE)) { 3786b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mHolding &= ~HOLD_DELETE; 3796b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang snapback(); 3806b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 3816b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang break; 3826b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 3836118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang case MSG_UNDO_BAR_TIMEOUT: { 384517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang checkHideUndoBar(UNDO_BAR_TIMEOUT); 385517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang break; 386517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang } 3876118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang case MSG_UNDO_BAR_FULL_CAMERA: { 3886118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang checkHideUndoBar(UNDO_BAR_FULL_CAMERA); 3896118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang break; 3906118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang } 391b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang default: throw new AssertionError(message.what); 392f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 393f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 39428cb4161da5fc3756933ca67d509b8af1c6275f1Owen Lin } 395f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 396f4e22eb44bfae0c2a3b6570f19480c8c3535d808Bobby Georgescu public void setWantPictureCenterCallbacks(boolean wanted) { 397f4e22eb44bfae0c2a3b6570f19480c8c3535d808Bobby Georgescu mWantPictureCenterCallbacks = wanted; 398b27df4650459068b409924493bbadaf25bb7e191Bobby Georgescu } 399b27df4650459068b409924493bbadaf25bb7e191Bobby Georgescu 400b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 401b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Data/Image change notifications 402b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 403b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 404214993dc4abf87c386123af50e3c34184ba11cb6Chih-Chung Chang public void notifyDataChange(int[] fromIndex, int prevBound, int nextBound) { 405c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang mPrevBound = prevBound; 406c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang mNextBound = nextBound; 407c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang 4086b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // Update mTouchBoxIndex 4096b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (mTouchBoxIndex != Integer.MAX_VALUE) { 4106b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int k = mTouchBoxIndex; 4116b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mTouchBoxIndex = Integer.MAX_VALUE; 4126b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang for (int i = 0; i < 2 * SCREEN_NAIL_MAX + 1; i++) { 4136b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (fromIndex[i] == k) { 4146b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mTouchBoxIndex = i - SCREEN_NAIL_MAX; 4156b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang break; 4166b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 4176b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 4186b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 4196b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 420517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang // Hide undo button if we are too far away 421517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang if (mUndoIndexHint != Integer.MAX_VALUE) { 422517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang if (Math.abs(mUndoIndexHint - mModel.getCurrentIndex()) >= 3) { 423517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang hideUndoBar(); 424517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang } 425517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang } 426517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang 4276b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // Update the ScreenNails. 4286b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang for (int i = -SCREEN_NAIL_MAX; i <= SCREEN_NAIL_MAX; i++) { 4296b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang Picture p = mPictures.get(i); 4306b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang p.reload(); 4316b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mSizes[i + SCREEN_NAIL_MAX] = p.getSize(); 4326b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 4336b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 4346b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang boolean wasDeleting = mPositionController.hasDeletingBox(); 4356b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 436b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Move the boxes 437214993dc4abf87c386123af50e3c34184ba11cb6Chih-Chung Chang mPositionController.moveBox(fromIndex, mPrevBound < 0, mNextBound > 0, 4386b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mModel.isCamera(0), mSizes); 439b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 440b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = -SCREEN_NAIL_MAX; i <= SCREEN_NAIL_MAX; i++) { 4416b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang setPictureSize(i); 4426b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 4436b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 4446b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang boolean isDeleting = mPositionController.hasDeletingBox(); 4456b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 4466b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // If the deletion is done, make HOLD_DELETE persist for only the time 4476b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // needed for a snapback animation. 4486b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (wasDeleting && !isDeleting) { 4496b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mHandler.removeMessages(MSG_DELETE_DONE); 4506b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang Message m = mHandler.obtainMessage(MSG_DELETE_DONE); 4516b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mHandler.sendMessageDelayed( 4526b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang m, PositionController.SNAPBACK_ANIMATION_TIME); 453b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 454b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 455b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang invalidate(); 456f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 457f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 4586b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public boolean isDeleting() { 4596b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang return (mHolding & HOLD_DELETE) != 0 4606b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang && mPositionController.hasDeletingBox(); 4616b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 4626b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 463b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void notifyImageChange(int index) { 464bd7c016d728853d38f98a3c6077b7bd9b08858b9Yuli Huang if (index == 0) { 465bd7c016d728853d38f98a3c6077b7bd9b08858b9Yuli Huang mListener.onCurrentImageUpdated(); 466bd7c016d728853d38f98a3c6077b7bd9b08858b9Yuli Huang } 467b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPictures.get(index).reload(); 4686b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang setPictureSize(index); 469b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang invalidate(); 470f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 471f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 4726b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private void setPictureSize(int index) { 4736b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang Picture p = mPictures.get(index); 4746b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mPositionController.setImageSize(index, p.getSize(), 4756b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang index == 0 && p.isCamera() ? mCameraRect : null); 4766b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 4776b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 478bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang @Override 4792ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang protected void onLayout( 4802ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang boolean changeSize, int left, int top, int right, int bottom) { 4812ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang int w = right - left; 4822ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang int h = bottom - top; 4832ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang mTileView.layout(0, 0, w, h); 4842ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang mEdgeView.layout(0, 0, w, h); 4856b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mUndoBar.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); 4866b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mUndoBar.layout(0, h - mUndoBar.getMeasuredHeight(), w, h); 4872ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang 4882ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang GLRoot root = getGLRoot(); 4892ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang int displayRotation = root.getDisplayRotation(); 4902ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang int compensation = root.getCompensation(); 4912ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang if (mDisplayRotation != displayRotation 4922ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang || mCompensation != compensation) { 4932ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang mDisplayRotation = displayRotation; 4942ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang mCompensation = compensation; 4952ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang 4963b4a8aeb0353fa18a2b5267b3952a80a6c6d4d13Chih-Chung Chang // We need to change the size and rotation of the Camera ScreenNail, 4973b4a8aeb0353fa18a2b5267b3952a80a6c6d4d13Chih-Chung Chang // but we don't want it to animate because the size doen't actually 4982ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang // change in the eye of the user. 4992ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang for (int i = -SCREEN_NAIL_MAX; i <= SCREEN_NAIL_MAX; i++) { 5002ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang Picture p = mPictures.get(i); 5012ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang if (p.isCamera()) { 5029f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang p.forceSize(); 5032ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang } 504bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 505bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 506bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 5079f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang updateCameraRect(); 5089f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang mPositionController.setConstrainedFrame(mCameraRect); 509bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (changeSize) { 510bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mPositionController.setViewSize(getWidth(), getHeight()); 511bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 512bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 513bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 5149f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang // Update the camera rectangle due to layout change or camera relative frame 5159f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang // change. 5169f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang private void updateCameraRect() { 5172ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang // Get the width and height in framework orientation because the given 5182ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang // mCameraRelativeFrame is in that coordinates. 519bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang int w = getWidth(); 520bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang int h = getHeight(); 5212ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang if (mCompensation % 180 != 0) { 522bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang int tmp = w; 523bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang w = h; 524bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang h = tmp; 525bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 5262ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang int l = mCameraRelativeFrame.left; 5272ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang int t = mCameraRelativeFrame.top; 5282ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang int r = mCameraRelativeFrame.right; 5292ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang int b = mCameraRelativeFrame.bottom; 530bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 5312ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang // Now convert it to the coordinates we are using. 5322ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang switch (mCompensation) { 533bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang case 0: mCameraRect.set(l, t, r, b); break; 534bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang case 90: mCameraRect.set(h - b, l, h - t, r); break; 535bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang case 180: mCameraRect.set(w - r, h - b, w - l, h - t); break; 536bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang case 270: mCameraRect.set(t, w - r, b, w - l); break; 537bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 538bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 5392ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang Log.d(TAG, "compensation = " + mCompensation 5402ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang + ", CameraRelativeFrame = " + mCameraRelativeFrame 5412ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang + ", mCameraRect = " + mCameraRect); 542bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 543bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 5442ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang public void setCameraRelativeFrame(Rect frame) { 5452ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang mCameraRelativeFrame.set(frame); 5469f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang updateCameraRect(); 5479f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang // Originally we do 5489f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang // mPositionController.setConstrainedFrame(mCameraRect); 5499f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang // here, but it is moved to a parameter of the setImageSize() call, so 5509f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang // it can be updated atomically with the CameraScreenNail's size change. 551bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 552bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 553bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // Returns the rotation we need to do to the camera texture before drawing 554bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // it to the canvas, assuming the camera texture is correct when the device 555bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // is in its natural orientation. 556bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private int getCameraRotation() { 557bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang return (mCompensation - mDisplayRotation + 360) % 360; 558bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 559bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 56043a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong private int getPanoramaRotation() { 561b1a28418848ce0adeb8a845a78e246b01913d176John Reck // This function is magic 562b1a28418848ce0adeb8a845a78e246b01913d176John Reck // The issue here is that Pano makes bad assumptions about rotation and 563b1a28418848ce0adeb8a845a78e246b01913d176John Reck // orientation. The first is it assumes only two rotations are possible, 564b1a28418848ce0adeb8a845a78e246b01913d176John Reck // 0 and 90. Thus, if display rotation is >= 180, we invert the output. 565b1a28418848ce0adeb8a845a78e246b01913d176John Reck // The second is that it assumes landscape is a 90 rotation from portrait, 566b1a28418848ce0adeb8a845a78e246b01913d176John Reck // however on landscape devices this is not true. Thus, if we are in portrait 567b1a28418848ce0adeb8a845a78e246b01913d176John Reck // on a landscape device, we need to invert the output 568e6c566e7e25b7f961f501c878e98d3ca640e63d8John Reck int orientation = mContext.getResources().getConfiguration().orientation; 569b1a28418848ce0adeb8a845a78e246b01913d176John Reck boolean invertPortrait = (orientation == Configuration.ORIENTATION_PORTRAIT 570b1a28418848ce0adeb8a845a78e246b01913d176John Reck && (mDisplayRotation == 90 || mDisplayRotation == 270)); 571b1a28418848ce0adeb8a845a78e246b01913d176John Reck boolean invert = (mDisplayRotation >= 180); 572b1a28418848ce0adeb8a845a78e246b01913d176John Reck if (invert != invertPortrait) { 573866ed7abd7960efc7986a3624414a730e17f33a6John Reck return (mCompensation + 180) % 360; 574b1a28418848ce0adeb8a845a78e246b01913d176John Reck } 57543a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong return mCompensation; 57643a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong } 57743a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong 578b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 579b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Pictures 580b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 581b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 582b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private interface Picture { 583b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang void reload(); 584b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang void draw(GLCanvas canvas, Rect r); 585b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang void setScreenNail(ScreenNail s); 5862c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang boolean isCamera(); // whether the picture is a camera preview 5876b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang boolean isDeletable(); // whether the picture can be deleted 5889f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang void forceSize(); // called when mCompensation changes 5896b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang Size getSize(); 5907817979db0c52ffeacb951625b1e821eba303285Ahbong Chang } 591f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 592b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang class FullPicture implements Picture { 593b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private int mRotation; 5942c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang private boolean mIsCamera; 59543a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong private boolean mIsPanorama; 596dbb6acc204ba6f095eb0e49e1298e9ceda2c3096Wu-cheng Li private boolean mIsStaticCamera; 597d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang private boolean mIsVideo; 5986b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private boolean mIsDeletable; 599f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang private int mLoadingState = Model.LOADING_INIT; 6006b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private Size mSize = new Size(); 601f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 602b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 603b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void reload() { 604b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // mImageWidth and mImageHeight will get updated 605b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mTileView.notifyModelInvalidated(); 606b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 607bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mIsCamera = mModel.isCamera(0); 60843a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong mIsPanorama = mModel.isPanorama(0); 609dbb6acc204ba6f095eb0e49e1298e9ceda2c3096Wu-cheng Li mIsStaticCamera = mModel.isStaticCamera(0); 610d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang mIsVideo = mModel.isVideo(0); 6116b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mIsDeletable = mModel.isDeletable(0); 612f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang mLoadingState = mModel.getLoadingState(0); 613bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang setScreenNail(mModel.getScreenNail(0)); 6146b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang updateSize(); 6159f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang } 6169f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang 6176b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang @Override 6186b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public Size getSize() { 6196b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang return mSize; 620bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 621bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 622bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang @Override 6239f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang public void forceSize() { 6249f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang updateSize(); 6256b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mPositionController.forceImageSize(0, mSize); 6269f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang } 6279f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang 6289f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang private void updateSize() { 62943a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong if (mIsPanorama) { 63043a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong mRotation = getPanoramaRotation(); 631dbb6acc204ba6f095eb0e49e1298e9ceda2c3096Wu-cheng Li } else if (mIsCamera && !mIsStaticCamera) { 632bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mRotation = getCameraRotation(); 633bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } else { 634bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mRotation = mModel.getImageRotation(0); 635bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 636bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 637c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang int w = mTileView.mImageWidth; 638c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang int h = mTileView.mImageHeight; 6396b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mSize.width = getRotated(mRotation, w, h); 6406b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mSize.height = getRotated(mRotation, h, w); 641f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 642f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 643b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 644b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void draw(GLCanvas canvas, Rect r) { 645f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang drawTileView(canvas, r); 646cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 647bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // We want to have the following transitions: 6482c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // (1) Move camera preview out of its place: switch to film mode 6492c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // (2) Move camera preview into its place: switch to page mode 6502c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // The extra mWasCenter check makes sure (1) does not apply if in 6512c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // page mode, we move _to_ the camera preview from another picture. 652bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 653bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // Holdings except touch-down prevent the transitions. 65418958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang if ((mHolding & ~HOLD_TOUCH_DOWN) != 0) return; 655bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 656f4e22eb44bfae0c2a3b6570f19480c8c3535d808Bobby Georgescu if (mWantPictureCenterCallbacks && mPositionController.isCenter()) { 657639095c6bed84ab0bf9ebc7c4f8b8c944df285a1Bobby Georgescu mListener.onPictureCenter(mIsCamera); 658bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 659cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 660cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 661b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 662b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang public void setScreenNail(ScreenNail s) { 663b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang mTileView.setScreenNail(s); 664cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 665f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 666b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 6672c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang public boolean isCamera() { 6682c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang return mIsCamera; 669f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 670f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 6716b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang @Override 6726b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public boolean isDeletable() { 6736b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang return mIsDeletable; 6746b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 6756b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 676d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang private void drawTileView(GLCanvas canvas, Rect r) { 677ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang float imageScale = mPositionController.getImageScale(); 678b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int viewW = getWidth(); 679b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int viewH = getHeight(); 680d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang float cx = r.exactCenterX(); 681d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang float cy = r.exactCenterY(); 682ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang float scale = 1f; // the scaling factor due to card effect 683b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 684d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang canvas.save(GLCanvas.SAVE_FLAG_MATRIX | GLCanvas.SAVE_FLAG_ALPHA); 685ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang float filmRatio = mPositionController.getFilmRatio(); 686ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang boolean wantsCardEffect = CARD_EFFECT && !mIsCamera 687f320b8429dd5c68c117b8e9b1a36a435f4f4ff13Yuli Huang && filmRatio != 1f && !mPictures.get(-1).isCamera() 688f320b8429dd5c68c117b8e9b1a36a435f4f4ff13Yuli Huang && !mPositionController.inOpeningAnimation(); 6896b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang boolean wantsOffsetEffect = OFFSET_EFFECT && mIsDeletable 6906b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang && filmRatio == 1f && r.centerY() != viewH / 2; 6912c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (wantsCardEffect) { 692b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Calculate the move-out progress value. 693b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int left = r.left; 694b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int right = r.right; 695b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang float progress = calculateMoveOutProgress(left, right, viewW); 696b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang progress = Utils.clamp(progress, -1f, 1f); 697b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 698b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // We only want to apply the fading animation if the scrolling 699b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // movement is to the right. 700bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (progress < 0) { 701ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang scale = getScrollScale(progress); 702ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang float alpha = getScrollAlpha(progress); 703ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang scale = interpolate(filmRatio, scale, 1f); 704ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang alpha = interpolate(filmRatio, alpha, 1f); 705d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang 706ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang imageScale *= scale; 707ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang canvas.multiplyAlpha(alpha); 708ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang 709ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang float cxPage; // the cx value in page mode 710d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang if (right - left <= viewW) { 711b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // If the picture is narrower than the view, keep it at 712b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // the center of the view. 713ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang cxPage = viewW / 2f; 714b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } else { 715b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // If the picture is wider than the view (it's 716b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // zoomed-in), keep the left edge of the object align 717b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // the the left edge of the view. 718ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang cxPage = (right - left) * scale / 2f; 719b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 720ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang cx = interpolate(filmRatio, cxPage, cx); 721b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 7226b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } else if (wantsOffsetEffect) { 7236b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang float offset = (float) (r.centerY() - viewH / 2) / viewH; 7246b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang float alpha = getOffsetAlpha(offset); 7256b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang canvas.multiplyAlpha(alpha); 726b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 727f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 728d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang // Draw the tile view. 729ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang setTileViewPosition(cx, cy, viewW, viewH, imageScale); 7306b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang renderChild(canvas, mTileView); 731d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang 732f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang // Draw the play video icon and the message. 733f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang canvas.translate((int) (cx + 0.5f), (int) (cy + 0.5f)); 734f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang int s = (int) (scale * Math.min(r.width(), r.height()) + 0.5f); 735c1c67ea813421a6173d1dab2ad75c11b51c7976dMangesh Ghiware if (mIsVideo) drawVideoPlayIcon(canvas, s); 736f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang if (mLoadingState == Model.LOADING_FAIL) { 737f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang drawLoadingFailMessage(canvas); 738d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang } 739d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang 740f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang // Draw a debug indicator showing which picture has focus (index == 741f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang // 0). 742f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang //canvas.fillRect(-10, -10, 20, 20, 0x80FF00FF); 743f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang 744d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang canvas.restore(); 745d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang } 746d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang 747d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang // Set the position of the tile view 748d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang private void setTileViewPosition(float cx, float cy, 749d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang int viewW, int viewH, float scale) { 750d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang // Find out the bitmap coordinates of the center of the view 751d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang int imageW = mPositionController.getImageWidth(); 752d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang int imageH = mPositionController.getImageHeight(); 753d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang int centerX = (int) (imageW / 2f + (viewW / 2f - cx) / scale + 0.5f); 754d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang int centerY = (int) (imageH / 2f + (viewH / 2f - cy) / scale + 0.5f); 755d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang 756b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int inverseX = imageW - centerX; 757b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int inverseY = imageH - centerY; 758d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang int x, y; 759d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang switch (mRotation) { 760d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang case 0: x = centerX; y = centerY; break; 761d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang case 90: x = centerY; y = inverseX; break; 762d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang case 180: x = inverseX; y = inverseY; break; 763d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang case 270: x = inverseY; y = centerX; break; 764b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang default: 765d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang throw new RuntimeException(String.valueOf(mRotation)); 766b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 767d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang mTileView.setPosition(x, y, scale, mRotation); 768f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 769f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 770f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 771b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private class ScreenNailPicture implements Picture { 772b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private int mIndex; 773b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private int mRotation; 774b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private ScreenNail mScreenNail; 7752c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang private boolean mIsCamera; 77643a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong private boolean mIsPanorama; 777dbb6acc204ba6f095eb0e49e1298e9ceda2c3096Wu-cheng Li private boolean mIsStaticCamera; 778d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang private boolean mIsVideo; 7796b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private boolean mIsDeletable; 780f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang private int mLoadingState = Model.LOADING_INIT; 7816b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private Size mSize = new Size(); 782f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 783b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public ScreenNailPicture(int index) { 784b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mIndex = index; 785b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 786532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 787b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 788b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void reload() { 789bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mIsCamera = mModel.isCamera(mIndex); 79043a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong mIsPanorama = mModel.isPanorama(mIndex); 791dbb6acc204ba6f095eb0e49e1298e9ceda2c3096Wu-cheng Li mIsStaticCamera = mModel.isStaticCamera(mIndex); 792d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang mIsVideo = mModel.isVideo(mIndex); 7936b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mIsDeletable = mModel.isDeletable(mIndex); 794f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang mLoadingState = mModel.getLoadingState(mIndex); 795c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang setScreenNail(mModel.getScreenNail(mIndex)); 7966b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang updateSize(); 7976b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 7986b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 7996b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang @Override 8006b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public Size getSize() { 8016b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang return mSize; 802b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 803b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 804b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 805b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void draw(GLCanvas canvas, Rect r) { 806b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mScreenNail == null) { 807f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang // Draw a placeholder rectange if there should be a picture in 808f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang // this position (but somehow there isn't). 809c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang if (mIndex >= mPrevBound && mIndex <= mNextBound) { 810f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang drawPlaceHolder(canvas, r); 811c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang } 812b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return; 813f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 8146b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int w = getWidth(); 8156b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int h = getHeight(); 8166b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (r.left >= w || r.right <= 0 || r.top >= h || r.bottom <= 0) { 817b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mScreenNail.noDraw(); 818b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return; 819f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 820f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 821ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang float filmRatio = mPositionController.getFilmRatio(); 822ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang boolean wantsCardEffect = CARD_EFFECT && mIndex > 0 823ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang && filmRatio != 1f && !mPictures.get(0).isCamera(); 8246b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang boolean wantsOffsetEffect = OFFSET_EFFECT && mIsDeletable 8256b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang && filmRatio == 1f && r.centerY() != h / 2; 826ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang int cx = wantsCardEffect 827ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang ? (int) (interpolate(filmRatio, w / 2, r.centerX()) + 0.5f) 828ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang : r.centerX(); 829b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int cy = r.centerY(); 830ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang canvas.save(GLCanvas.SAVE_FLAG_MATRIX | GLCanvas.SAVE_FLAG_ALPHA); 831b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang canvas.translate(cx, cy); 8322c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (wantsCardEffect) { 833b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang float progress = (float) (w / 2 - r.centerX()) / w; 834b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang progress = Utils.clamp(progress, -1, 1); 835b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang float alpha = getScrollAlpha(progress); 836b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang float scale = getScrollScale(progress); 837ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang alpha = interpolate(filmRatio, alpha, 1f); 838ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang scale = interpolate(filmRatio, scale, 1f); 839b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang canvas.multiplyAlpha(alpha); 840b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang canvas.scale(scale, scale, 1); 8416b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } else if (wantsOffsetEffect) { 8426b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang float offset = (float) (r.centerY() - h / 2) / h; 8436b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang float alpha = getOffsetAlpha(offset); 8446b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang canvas.multiplyAlpha(alpha); 845b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 846b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mRotation != 0) { 847b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang canvas.rotate(mRotation, 0, 0, 1); 848b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 849ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang int drawW = getRotated(mRotation, r.width(), r.height()); 850ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang int drawH = getRotated(mRotation, r.height(), r.width()); 851b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mScreenNail.draw(canvas, -drawW / 2, -drawH / 2, drawW, drawH); 852f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang if (isScreenNailAnimating()) { 853f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang invalidate(); 854f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang } 855f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang int s = Math.min(drawW, drawH); 856c1c67ea813421a6173d1dab2ad75c11b51c7976dMangesh Ghiware if (mIsVideo) drawVideoPlayIcon(canvas, s); 857f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang if (mLoadingState == Model.LOADING_FAIL) { 858f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang drawLoadingFailMessage(canvas); 859f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang } 860b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang canvas.restore(); 861b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 862f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 863f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang private boolean isScreenNailAnimating() { 864030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin return (mScreenNail instanceof TiledScreenNail) 865030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin && ((TiledScreenNail) mScreenNail).isAnimating(); 866f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang } 867f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang 868b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 869b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang public void setScreenNail(ScreenNail s) { 870b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mScreenNail = s; 8719f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang } 8729f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang 873bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang @Override 8749f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang public void forceSize() { 8759f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang updateSize(); 8766b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mPositionController.forceImageSize(mIndex, mSize); 8779f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang } 8789f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang 8799f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang private void updateSize() { 88043a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong if (mIsPanorama) { 88143a80fd806247cb50e81bacda3ad21d210e9ae88Angus Kong mRotation = getPanoramaRotation(); 882dbb6acc204ba6f095eb0e49e1298e9ceda2c3096Wu-cheng Li } else if (mIsCamera && !mIsStaticCamera) { 883bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mRotation = getCameraRotation(); 884bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } else { 885bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mRotation = mModel.getImageRotation(mIndex); 886bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 887c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang 888b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mScreenNail != null) { 8896b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mSize.width = mScreenNail.getWidth(); 8906b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mSize.height = mScreenNail.getHeight(); 8916b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } else { 892c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // If we don't have ScreenNail available, we can still try to 893c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // get the size information of it. 894c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang mModel.getImageSize(mIndex, mSize); 895b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 896c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang 8976b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int w = mSize.width; 8986b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int h = mSize.height; 8996b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mSize.width = getRotated(mRotation, w, h); 9006b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mSize.height = getRotated(mRotation, h, w); 901f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 902b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 903b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 9042c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang public boolean isCamera() { 9052c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang return mIsCamera; 906b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 9076b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 9086b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang @Override 9096b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public boolean isDeletable() { 9106b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang return mIsDeletable; 9116b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 912b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 913b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 914f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang // Draw a gray placeholder in the specified rectangle. 915f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang private void drawPlaceHolder(GLCanvas canvas, Rect r) { 916915c2c5b2c367df71599370613af0924bd7c4887Bobby Georgescu canvas.fillRect(r.left, r.top, r.width(), r.height(), mPlaceholderColor); 917f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang } 918f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang 919d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang // Draw the video play icon (in the place where the spinner was) 920d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang private void drawVideoPlayIcon(GLCanvas canvas, int side) { 921d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang int s = side / ICON_RATIO; 922d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang // Draw the video play icon at the center 923d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang mVideoPlayIcon.draw(canvas, -s / 2, -s / 2, s, s); 924d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang } 925d9355113da391f8bbddef1d2a2126ce6edc72291Chih-Chung Chang 926f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang // Draw the "no thumbnail" message 927f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang private void drawLoadingFailMessage(GLCanvas canvas) { 928f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang StringTexture m = mNoThumbnailText; 929f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang m.draw(canvas, -m.getWidth() / 2, -m.getHeight() / 2); 930f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang } 931f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang 932b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static int getRotated(int degree, int original, int theother) { 933b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return (degree % 180 == 0) ? original : theother; 934b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 935b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 936b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 937b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Gestures Handling 938b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 939b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 940b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 941b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang protected boolean onTouch(MotionEvent event) { 942b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mGestureRecognizer.onTouchEvent(event); 943b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return true; 944f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 945f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 9463a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang private class MyGestureListener implements GestureRecognizer.Listener { 9473a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang private boolean mIgnoreUpEvent = false; 948099989b310d84fe13eff0cdf2902bb3fb0bcbd14Chih-Chung Chang // If we can change mode for this scale gesture. 949099989b310d84fe13eff0cdf2902bb3fb0bcbd14Chih-Chung Chang private boolean mCanChangeMode; 95018958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang // If we have changed the film mode in this scaling gesture. 951b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private boolean mModeChanged; 95233f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang // If this scaling gesture should be ignored. 95333f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang private boolean mIgnoreScalingGesture; 95417ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang // whether the down action happened while the view is scrolling. 95517ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang private boolean mDownInScrolling; 9566575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang // If we should ignore all gestures other than onSingleTapUp. 9576575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang private boolean mIgnoreSwipingGesture; 9586b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // If a scrolling has happened after a down gesture. 9596b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private boolean mScrolledAfterDown; 9606b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // If the first scrolling move is in X direction. In the film mode, X 9616b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // direction scrolling is normal scrolling. but Y direction scrolling is 9626b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // a delete gesture. 9636b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private boolean mFirstScrollX; 9646b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // The accumulated Y delta that has been sent to mPositionController. 9656b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private int mDeltaY; 9662ce59cbd4368eaf0f30cfea28891bd47155182cbChih-Chung Chang // The accumulated scaling change from a scaling gesture. 9672ce59cbd4368eaf0f30cfea28891bd47155182cbChih-Chung Chang private float mAccScale; 968499ac9eae0eb26eaf7ebf79fb88ba929b71c8145Bobby Georgescu // If an onFling happened after the last onDown 969499ac9eae0eb26eaf7ebf79fb88ba929b71c8145Bobby Georgescu private boolean mHadFling; 970b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 9713a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang @Override 9723a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang public boolean onSingleTapUp(float x, float y) { 9734d47b3472cccf84e8c71d8fb389a79bc83b321eeHung-ying Tyan // On crespo running Android 2.3.6 (gingerbread), a pinch out gesture results in the 9744d47b3472cccf84e8c71d8fb389a79bc83b321eeHung-ying Tyan // following call sequence: onDown(), onUp() and then onSingleTapUp(). The correct 9754d47b3472cccf84e8c71d8fb389a79bc83b321eeHung-ying Tyan // sequence for a single-tap-up gesture should be: onDown(), onSingleTapUp() and onUp(). 9764d47b3472cccf84e8c71d8fb389a79bc83b321eeHung-ying Tyan // The call sequence for a pinch out gesture in JB is: onDown(), then onUp() and there's 9774d47b3472cccf84e8c71d8fb389a79bc83b321eeHung-ying Tyan // no onSingleTapUp(). Base on these observations, the following condition is added to 9784d47b3472cccf84e8c71d8fb389a79bc83b321eeHung-ying Tyan // filter out the false alarm where onSingleTapUp() is called within a pinch out 9794d47b3472cccf84e8c71d8fb389a79bc83b321eeHung-ying Tyan // gesture. The framework fix went into ICS. Refer to b/4588114. 9804d47b3472cccf84e8c71d8fb389a79bc83b321eeHung-ying Tyan if (Build.VERSION.SDK_INT < ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH) { 9814d47b3472cccf84e8c71d8fb389a79bc83b321eeHung-ying Tyan if ((mHolding & HOLD_TOUCH_DOWN) == 0) { 9824d47b3472cccf84e8c71d8fb389a79bc83b321eeHung-ying Tyan return true; 9834d47b3472cccf84e8c71d8fb389a79bc83b321eeHung-ying Tyan } 9844d47b3472cccf84e8c71d8fb389a79bc83b321eeHung-ying Tyan } 9854d47b3472cccf84e8c71d8fb389a79bc83b321eeHung-ying Tyan 986ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang // We do this in addition to onUp() because we want the snapback of 987ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang // setFilmMode to happen. 988ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang mHolding &= ~HOLD_TOUCH_DOWN; 989ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang 99017ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang if (mFilmMode && !mDownInScrolling) { 99117ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang switchToHitPicture((int) (x + 0.5f), (int) (y + 0.5f)); 992743f8152a1dd6ea47bcabc6fd95b6e8d8f1cd3e5Wu-cheng Li 993743f8152a1dd6ea47bcabc6fd95b6e8d8f1cd3e5Wu-cheng Li // If this is a lock screen photo, let the listener handle the 994743f8152a1dd6ea47bcabc6fd95b6e8d8f1cd3e5Wu-cheng Li // event. Tapping on lock screen photo should take the user 995743f8152a1dd6ea47bcabc6fd95b6e8d8f1cd3e5Wu-cheng Li // directly to the lock screen. 996743f8152a1dd6ea47bcabc6fd95b6e8d8f1cd3e5Wu-cheng Li MediaItem item = mModel.getMediaItem(0); 997743f8152a1dd6ea47bcabc6fd95b6e8d8f1cd3e5Wu-cheng Li int supported = 0; 998743f8152a1dd6ea47bcabc6fd95b6e8d8f1cd3e5Wu-cheng Li if (item != null) supported = item.getSupportedOperations(); 999c7e3c76d6965f520a9651d309052c5f01726cd58Bobby Georgescu if ((supported & MediaItem.SUPPORT_ACTION) == 0) { 1000743f8152a1dd6ea47bcabc6fd95b6e8d8f1cd3e5Wu-cheng Li setFilmMode(false); 1001743f8152a1dd6ea47bcabc6fd95b6e8d8f1cd3e5Wu-cheng Li mIgnoreUpEvent = true; 1002743f8152a1dd6ea47bcabc6fd95b6e8d8f1cd3e5Wu-cheng Li return true; 1003743f8152a1dd6ea47bcabc6fd95b6e8d8f1cd3e5Wu-cheng Li } 1004b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1005b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1006bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (mListener != null) { 10072ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang // Do the inverse transform of the touch coordinates. 10082ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang Matrix m = getGLRoot().getCompensationMatrix(); 10092ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang Matrix inv = new Matrix(); 10102ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang m.invert(inv); 10112ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang float[] pts = new float[] {x, y}; 10122ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang inv.mapPoints(pts); 10132ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang mListener.onSingleTapUp((int) (pts[0] + 0.5f), (int) (pts[1] + 0.5f)); 10143a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang } 10153a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang return true; 10163a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang } 10173a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang 10183a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang @Override 10193a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang public boolean onDoubleTap(float x, float y) { 10206575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang if (mIgnoreSwipingGesture) return true; 102161f94714c3702115d2f89bb5f8829697be0c3680Chih-Chung Chang if (mPictures.get(0).isCamera()) return false; 10223a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang PositionController controller = mPositionController; 1023b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang float scale = controller.getImageScale(); 10243a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang // onDoubleTap happened on the second ACTION_DOWN. 10253a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang // We need to ignore the next UP event. 10263a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang mIgnoreUpEvent = true; 102724958c5d4a63e1d7c49d9e7007ee10958ad23e8fJohn Reck if (scale <= .75f || controller.isAtMinimalScale()) { 102824958c5d4a63e1d7c49d9e7007ee10958ad23e8fJohn Reck controller.zoomIn(x, y, Math.max(1.0f, scale * 1.5f)); 10293a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang } else { 10303a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang controller.resetToFullView(); 10313a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang } 10323a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang return true; 10333a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang } 1034f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1035f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 10366b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public boolean onScroll(float dx, float dy, float totalX, float totalY) { 10376575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang if (mIgnoreSwipingGesture) return true; 10386b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (!mScrolledAfterDown) { 10396b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mScrolledAfterDown = true; 10406b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mFirstScrollX = (Math.abs(dx) > Math.abs(dy)); 10416b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 10426b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 10436b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int dxi = (int) (-dx + 0.5f); 10446b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int dyi = (int) (-dy + 0.5f); 10456b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (mFilmMode) { 10466b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (mFirstScrollX) { 10476b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mPositionController.scrollFilmX(dxi); 10486b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } else { 10496b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (mTouchBoxIndex == Integer.MAX_VALUE) return true; 10506b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int newDeltaY = calculateDeltaY(totalY); 10516b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int d = newDeltaY - mDeltaY; 10526b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (d != 0) { 10536b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mPositionController.scrollFilmY(mTouchBoxIndex, d); 10546b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mDeltaY = newDeltaY; 10556b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 10566b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 10576b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } else { 10586b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mPositionController.scrollPage(dxi, dyi); 10596b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 1060f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return true; 1061f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1062f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 10636b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private int calculateDeltaY(float delta) { 10646b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (mTouchBoxDeletable) return (int) (delta + 0.5f); 10656b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 10666b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // don't let items that can't be deleted be dragged more than 10676b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // maxScrollDistance, and make it harder and harder to drag. 10686b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int size = getHeight(); 10696b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang float maxScrollDistance = 0.15f * size; 10706b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (Math.abs(delta) >= size) { 10716b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang delta = delta > 0 ? maxScrollDistance : -maxScrollDistance; 10726b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } else { 10736b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang delta = maxScrollDistance * 10746b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang FloatMath.sin((delta / size) * (float) (Math.PI / 2)); 10756b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 10766b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang return (int) (delta + 0.5f); 10776b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 10786b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 1079f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 1080137c6d060f9710f1a460326f27459e89b49820c2Bobby Georgescu public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { 10816575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang if (mIgnoreSwipingGesture) return true; 1082e9494164bd7dd1c55c99b3ae1e842b88bf6abd78Chih-Chung Chang if (mModeChanged) return true; 10832ce3c3bfe08fff5aee58007cc8ba8f4a50861ae2Yuli Huang if (swipeImages(velocityX, velocityY)) { 1084b3aab90bb37aa9cc60be32e05678ee55d6575ee8Chih-Chung Chang mIgnoreUpEvent = true; 10856b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } else { 1086137c6d060f9710f1a460326f27459e89b49820c2Bobby Georgescu flingImages(velocityX, velocityY, Math.abs(e2.getY() - e1.getY())); 1087f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1088499ac9eae0eb26eaf7ebf79fb88ba929b71c8145Bobby Georgescu mHadFling = true; 1089f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return true; 1090f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1091f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1092137c6d060f9710f1a460326f27459e89b49820c2Bobby Georgescu private boolean flingImages(float velocityX, float velocityY, float dY) { 10936b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int vx = (int) (velocityX + 0.5f); 10946b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int vy = (int) (velocityY + 0.5f); 10956b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (!mFilmMode) { 10966b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang return mPositionController.flingPage(vx, vy); 10976b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 10986b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (Math.abs(velocityX) > Math.abs(velocityY)) { 10996b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang return mPositionController.flingFilmX(vx); 11006b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 11016b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // If we scrolled in Y direction fast enough, treat it as a delete 11026b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // gesture. 11036b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (!mFilmMode || mTouchBoxIndex == Integer.MAX_VALUE 11046b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang || !mTouchBoxDeletable) { 11056b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang return false; 11066b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 11077817979db0c52ffeacb951625b1e821eba303285Ahbong Chang int maxVelocity = GalleryUtils.dpToPixel(MAX_DISMISS_VELOCITY); 11087817979db0c52ffeacb951625b1e821eba303285Ahbong Chang int escapeVelocity = GalleryUtils.dpToPixel(SWIPE_ESCAPE_VELOCITY); 1109137c6d060f9710f1a460326f27459e89b49820c2Bobby Georgescu int escapeDistance = GalleryUtils.dpToPixel(SWIPE_ESCAPE_DISTANCE); 11106b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int centerY = mPositionController.getPosition(mTouchBoxIndex) 11116b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang .centerY(); 11126b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang boolean fastEnough = (Math.abs(vy) > escapeVelocity) 11136b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang && (Math.abs(vy) > Math.abs(vx)) 1114137c6d060f9710f1a460326f27459e89b49820c2Bobby Georgescu && ((vy > 0) == (centerY > getHeight() / 2)) 1115137c6d060f9710f1a460326f27459e89b49820c2Bobby Georgescu && dY >= escapeDistance; 11166b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (fastEnough) { 11176b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang vy = Math.min(vy, maxVelocity); 11186b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int duration = mPositionController.flingFilmY(mTouchBoxIndex, vy); 11196b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (duration >= 0) { 11206b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mPositionController.setPopFromTop(vy < 0); 11216b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang deleteAfterAnimation(duration); 11226b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // We reset mTouchBoxIndex, so up() won't check if Y 11236b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // scrolled far enough to be a delete gesture. 11246b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mTouchBoxIndex = Integer.MAX_VALUE; 11256b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang return true; 11266b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 11276b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 11286b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang return false; 11296b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 11306b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 11316b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private void deleteAfterAnimation(int duration) { 11326b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang MediaItem item = mModel.getMediaItem(mTouchBoxIndex); 11336b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (item == null) return; 1134517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang mListener.onCommitDeleteImage(); 1135517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang mUndoIndexHint = mModel.getCurrentIndex() + mTouchBoxIndex; 11366b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mHolding |= HOLD_DELETE; 11376b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang Message m = mHandler.obtainMessage(MSG_DELETE_ANIMATION_DONE); 11386b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang m.obj = item.getPath(); 11396b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang m.arg1 = mTouchBoxIndex; 11406b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mHandler.sendMessageDelayed(m, duration); 11416b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 11426b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 1143f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 11443a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang public boolean onScaleBegin(float focusX, float focusY) { 11456575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang if (mIgnoreSwipingGesture) return true; 114633f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang // We ignore the scaling gesture if it is a camera preview. 114733f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang mIgnoreScalingGesture = mPictures.get(0).isCamera(); 114833f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang if (mIgnoreScalingGesture) { 114933f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang return true; 115033f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang } 11513a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang mPositionController.beginScale(focusX, focusY); 1152099989b310d84fe13eff0cdf2902bb3fb0bcbd14Chih-Chung Chang // We can change mode if we are in film mode, or we are in page 1153099989b310d84fe13eff0cdf2902bb3fb0bcbd14Chih-Chung Chang // mode and at minimal scale. 1154099989b310d84fe13eff0cdf2902bb3fb0bcbd14Chih-Chung Chang mCanChangeMode = mFilmMode 1155099989b310d84fe13eff0cdf2902bb3fb0bcbd14Chih-Chung Chang || mPositionController.isAtMinimalScale(); 11562ce59cbd4368eaf0f30cfea28891bd47155182cbChih-Chung Chang mAccScale = 1f; 1157f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return true; 1158f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1159f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1160f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 11613a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang public boolean onScale(float focusX, float focusY, float scale) { 11626575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang if (mIgnoreSwipingGesture) return true; 11636575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang if (mIgnoreScalingGesture) return true; 116418958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang if (mModeChanged) return true; 1165b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (Float.isNaN(scale) || Float.isInfinite(scale)) return false; 116633f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang 1167b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int outOfRange = mPositionController.scaleBy(scale, focusX, focusY); 1168b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 11692ce59cbd4368eaf0f30cfea28891bd47155182cbChih-Chung Chang // We wait for a large enough scale change before changing mode. 11702ce59cbd4368eaf0f30cfea28891bd47155182cbChih-Chung Chang // Otherwise we may mistakenly treat a zoom-in gesture as zoom-out 11712ce59cbd4368eaf0f30cfea28891bd47155182cbChih-Chung Chang // or vice versa. 11722ce59cbd4368eaf0f30cfea28891bd47155182cbChih-Chung Chang mAccScale *= scale; 11732ce59cbd4368eaf0f30cfea28891bd47155182cbChih-Chung Chang boolean largeEnough = (mAccScale < 0.97f || mAccScale > 1.03f); 11742ce59cbd4368eaf0f30cfea28891bd47155182cbChih-Chung Chang 117518958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang // If mode changes, we treat this scaling gesture has ended. 11762ce59cbd4368eaf0f30cfea28891bd47155182cbChih-Chung Chang if (mCanChangeMode && largeEnough) { 1177b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if ((outOfRange < 0 && !mFilmMode) || 1178b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang (outOfRange > 0 && mFilmMode)) { 117918958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang stopExtraScalingIfNeeded(); 118018958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang 118118958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang // Removing the touch down flag allows snapback to happen 118233f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang // for film mode change. 118318958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang mHolding &= ~HOLD_TOUCH_DOWN; 1184f37648b877bf6029d7afead31e965b473114c89cBobby Georgescu if (mFilmMode) { 1185f37648b877bf6029d7afead31e965b473114c89cBobby Georgescu UsageStatistics.setPendingTransitionCause( 1186f37648b877bf6029d7afead31e965b473114c89cBobby Georgescu UsageStatistics.TRANSITION_PINCH_OUT); 1187f37648b877bf6029d7afead31e965b473114c89cBobby Georgescu } else { 1188f37648b877bf6029d7afead31e965b473114c89cBobby Georgescu UsageStatistics.setPendingTransitionCause( 1189f37648b877bf6029d7afead31e965b473114c89cBobby Georgescu UsageStatistics.TRANSITION_PINCH_IN); 1190f37648b877bf6029d7afead31e965b473114c89cBobby Georgescu } 1191b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang setFilmMode(!mFilmMode); 119218958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang 1193f37648b877bf6029d7afead31e965b473114c89cBobby Georgescu 119418958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang // We need to call onScaleEnd() before setting mModeChanged 119518958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang // to true. 119618958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang onScaleEnd(); 1197b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mModeChanged = true; 1198b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return true; 1199534b12fd804610dd67b8109bc08ba76f31afb33eChih-Chung Chang } 1200b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1201b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 120218958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang if (outOfRange != 0) { 1203b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang startExtraScalingIfNeeded(); 1204534b12fd804610dd67b8109bc08ba76f31afb33eChih-Chung Chang } else { 1205b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang stopExtraScalingIfNeeded(); 1206534b12fd804610dd67b8109bc08ba76f31afb33eChih-Chung Chang } 1207f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return true; 1208f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1209f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 121033f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang @Override 121133f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang public void onScaleEnd() { 12126575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang if (mIgnoreSwipingGesture) return; 12136575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang if (mIgnoreScalingGesture) return; 121433f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang if (mModeChanged) return; 121533f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang mPositionController.endScale(); 121633f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang } 121733f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang 1218b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void startExtraScalingIfNeeded() { 1219b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (!mCancelExtraScalingPending) { 1220b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mHandler.sendEmptyMessageDelayed( 1221b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang MSG_CANCEL_EXTRA_SCALING, 700); 1222b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.setExtraScalingRange(true); 1223b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mCancelExtraScalingPending = true; 1224b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1225b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1226b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1227b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void stopExtraScalingIfNeeded() { 1228b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mCancelExtraScalingPending) { 1229b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mHandler.removeMessages(MSG_CANCEL_EXTRA_SCALING); 1230b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.setExtraScalingRange(false); 1231b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mCancelExtraScalingPending = false; 1232b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1233b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1234b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1235f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 12366b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public void onDown(float x, float y) { 1237517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang checkHideUndoBar(UNDO_BAR_TOUCHED); 1238517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang 12396b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mDeltaY = 0; 1240e9494164bd7dd1c55c99b3ae1e842b88bf6abd78Chih-Chung Chang mModeChanged = false; 12416b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 12426575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang if (mIgnoreSwipingGesture) return; 12436575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang 12442c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mHolding |= HOLD_TOUCH_DOWN; 124517ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang 124617ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang if (mFilmMode && mPositionController.isScrolling()) { 124717ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang mDownInScrolling = true; 124817ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang mPositionController.stopScrolling(); 124917ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang } else { 125017ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang mDownInScrolling = false; 125117ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang } 1252499ac9eae0eb26eaf7ebf79fb88ba929b71c8145Bobby Georgescu mHadFling = false; 12536b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mScrolledAfterDown = false; 12546b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (mFilmMode) { 12556b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int xi = (int) (x + 0.5f); 12566b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int yi = (int) (y + 0.5f); 1257137c6d060f9710f1a460326f27459e89b49820c2Bobby Georgescu // We only care about being within the x bounds, necessary for 1258137c6d060f9710f1a460326f27459e89b49820c2Bobby Georgescu // handling very wide images which are otherwise very hard to fling 1259137c6d060f9710f1a460326f27459e89b49820c2Bobby Georgescu mTouchBoxIndex = mPositionController.hitTest(xi, getHeight() / 2); 1260137c6d060f9710f1a460326f27459e89b49820c2Bobby Georgescu 12616b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (mTouchBoxIndex < mPrevBound || mTouchBoxIndex > mNextBound) { 12626b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mTouchBoxIndex = Integer.MAX_VALUE; 12636b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } else { 12646b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mTouchBoxDeletable = 12656b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mPictures.get(mTouchBoxIndex).isDeletable(); 12666b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 12676b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } else { 12686b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mTouchBoxIndex = Integer.MAX_VALUE; 12696b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 12703a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang } 12713a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang 12723a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang @Override 12733a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang public void onUp() { 12746575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang if (mIgnoreSwipingGesture) return; 12756575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang 127618958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang mHolding &= ~HOLD_TOUCH_DOWN; 12773a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang mEdgeView.onRelease(); 12783a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang 12796b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // If we scrolled in Y direction far enough, treat it as a delete 12806b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // gesture. 12816b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (mFilmMode && mScrolledAfterDown && !mFirstScrollX 12826b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang && mTouchBoxIndex != Integer.MAX_VALUE) { 12836b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang Rect r = mPositionController.getPosition(mTouchBoxIndex); 12846b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int h = getHeight(); 12856b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (Math.abs(r.centerY() - h * 0.5f) > 0.4f * h) { 12866b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int duration = mPositionController 12876b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang .flingFilmY(mTouchBoxIndex, 0); 12886b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (duration >= 0) { 12896b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mPositionController.setPopFromTop(r.centerY() < h * 0.5f); 12906b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang deleteAfterAnimation(duration); 12916b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 12926b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 12936b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 12946b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 12953a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang if (mIgnoreUpEvent) { 12963a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang mIgnoreUpEvent = false; 12973a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang return; 12983a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang } 1299b1a513974d59c1dc14e004338b6795d6c3c5e5e8Bobby Georgescu 1300dc55d3b1a614b95a36aab60c06f7961a800ec85aBobby Georgescu if (!(mFilmMode && !mHadFling && mFirstScrollX 1301dc55d3b1a614b95a36aab60c06f7961a800ec85aBobby Georgescu && snapToNeighborImage())) { 1302b1a513974d59c1dc14e004338b6795d6c3c5e5e8Bobby Georgescu snapback(); 1303499ac9eae0eb26eaf7ebf79fb88ba929b71c8145Bobby Georgescu } 1304f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 13056575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang 13066575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang public void setSwipingEnabled(boolean enabled) { 13076575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang mIgnoreSwipingGesture = !enabled; 13086575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang } 13096575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang } 13106575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang 13116575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang public void setSwipingEnabled(boolean enabled) { 13126575794a9c09f22d5721e212c093e0a2df376d0cChih-Chung Chang mGestureListener.setSwipingEnabled(enabled); 1313f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1314f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 131500ccf35f8ec016b2cb8fdcf0c65ba643dca54a14Bobby Georgescu private void updateActionBar() { 131600ccf35f8ec016b2cb8fdcf0c65ba643dca54a14Bobby Georgescu boolean isCamera = mPictures.get(0).isCamera(); 131700ccf35f8ec016b2cb8fdcf0c65ba643dca54a14Bobby Georgescu if (isCamera && !mFilmMode) { 131800ccf35f8ec016b2cb8fdcf0c65ba643dca54a14Bobby Georgescu // Move into camera in page mode, lock 131900ccf35f8ec016b2cb8fdcf0c65ba643dca54a14Bobby Georgescu mListener.onActionBarAllowed(false); 132000ccf35f8ec016b2cb8fdcf0c65ba643dca54a14Bobby Georgescu } else { 132100ccf35f8ec016b2cb8fdcf0c65ba643dca54a14Bobby Georgescu mListener.onActionBarAllowed(true); 132200ccf35f8ec016b2cb8fdcf0c65ba643dca54a14Bobby Georgescu if (mFilmMode) mListener.onActionBarWanted(); 132300ccf35f8ec016b2cb8fdcf0c65ba643dca54a14Bobby Georgescu } 132400ccf35f8ec016b2cb8fdcf0c65ba643dca54a14Bobby Georgescu } 132500ccf35f8ec016b2cb8fdcf0c65ba643dca54a14Bobby Georgescu 13267eea4d3ac59aa88d327fc0d58f5e4052f43c54c9Bobby Georgescu public void setFilmMode(boolean enabled) { 1327b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mFilmMode == enabled) return; 1328b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mFilmMode = enabled; 1329b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.setFilmMode(mFilmMode); 1330b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang mModel.setNeedFullImage(!enabled); 133141b3cff60905a96ab5b6f8e5f42bcc3bab1eb605Bobby Georgescu mModel.setFocusHintDirection( 133241b3cff60905a96ab5b6f8e5f42bcc3bab1eb605Bobby Georgescu mFilmMode ? Model.FOCUS_HINT_PREVIOUS : Model.FOCUS_HINT_NEXT); 133300ccf35f8ec016b2cb8fdcf0c65ba643dca54a14Bobby Georgescu updateActionBar(); 13347eea4d3ac59aa88d327fc0d58f5e4052f43c54c9Bobby Georgescu mListener.onFilmModeChanged(enabled); 1335bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 1336bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 1337bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public boolean getFilmMode() { 1338bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang return mFilmMode; 1339f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1340f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1341b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1342b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Framework events 1343b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1344b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1345b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void pause() { 1346b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.skipAnimation(); 1347b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mTileView.freeTextures(); 1348b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = -SCREEN_NAIL_MAX; i <= SCREEN_NAIL_MAX; i++) { 1349b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang mPictures.get(i).setScreenNail(null); 1350b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 13516118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang hideUndoBar(); 1352f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1353f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1354b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void resume() { 1355b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mTileView.prepareTextures(); 13563ed6ae23e43be73c83b6be3dcaafe7400a7b3355Bobby Georgescu mPositionController.skipToFinalPosition(); 1357f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1358f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 135933f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang // move to the camera preview and show controls after resume 136033f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang public void resetToFirstPicture() { 136133f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang mModel.moveTo(0); 136233f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang setFilmMode(false); 136333f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang } 136433f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang 1365517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1366517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang // Undo Bar 1367517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1368517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang 1369517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang private int mUndoBarState; 1370517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang private static final int UNDO_BAR_SHOW = 1; 1371517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang private static final int UNDO_BAR_TIMEOUT = 2; 1372517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang private static final int UNDO_BAR_TOUCHED = 4; 13736118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang private static final int UNDO_BAR_FULL_CAMERA = 8; 13746118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang private static final int UNDO_BAR_DELETE_LAST = 16; 1375517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang 13766118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang // "deleteLast" means if the deletion is on the last remaining picture in 13776118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang // the album. 13786118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang private void showUndoBar(boolean deleteLast) { 13796118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang mHandler.removeMessages(MSG_UNDO_BAR_TIMEOUT); 1380517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang mUndoBarState = UNDO_BAR_SHOW; 13816118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang if(deleteLast) mUndoBarState |= UNDO_BAR_DELETE_LAST; 1382517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang mUndoBar.animateVisibility(GLView.VISIBLE); 13836118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang mHandler.sendEmptyMessageDelayed(MSG_UNDO_BAR_TIMEOUT, 3000); 1384949584340c9f5f41a6133ba06058af280490f0c8Bobby Georgescu if (mListener != null) mListener.onUndoBarVisibilityChanged(true); 1385517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang } 1386517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang 13876118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang private void hideUndoBar() { 13886118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang mHandler.removeMessages(MSG_UNDO_BAR_TIMEOUT); 1389517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang mListener.onCommitDeleteImage(); 1390517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang mUndoBar.animateVisibility(GLView.INVISIBLE); 1391517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang mUndoBarState = 0; 1392517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang mUndoIndexHint = Integer.MAX_VALUE; 1393949584340c9f5f41a6133ba06058af280490f0c8Bobby Georgescu mListener.onUndoBarVisibilityChanged(false); 1394517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang } 1395517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang 13966118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang // Check if the one of the conditions for hiding the undo bar has been 13976118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang // met. The conditions are: 13986118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang // 13996118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang // 1. It has been three seconds since last showing, and (a) the user has 14006118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang // touched, or (b) the deleted picture is the last remaining picture in the 14016118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang // album. 14026118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang // 14036118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang // 2. The camera is shown in full screen. 1404517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang private void checkHideUndoBar(int addition) { 1405517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang mUndoBarState |= addition; 14066118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang if ((mUndoBarState & UNDO_BAR_SHOW) == 0) return; 14076118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang boolean timeout = (mUndoBarState & UNDO_BAR_TIMEOUT) != 0; 14086118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang boolean touched = (mUndoBarState & UNDO_BAR_TOUCHED) != 0; 14096118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang boolean fullCamera = (mUndoBarState & UNDO_BAR_FULL_CAMERA) != 0; 14106118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang boolean deleteLast = (mUndoBarState & UNDO_BAR_DELETE_LAST) != 0; 141141b3cff60905a96ab5b6f8e5f42bcc3bab1eb605Bobby Georgescu if ((timeout && deleteLast) || fullCamera || touched) { 1412517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang hideUndoBar(); 1413517e1bd25305d4e82d101a8c06be0119dde2eab3Chih-Chung Chang } 14146b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 14156b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 1416639095c6bed84ab0bf9ebc7c4f8b8c944df285a1Bobby Georgescu public boolean canUndo() { 1417639095c6bed84ab0bf9ebc7c4f8b8c944df285a1Bobby Georgescu return (mUndoBarState & UNDO_BAR_SHOW) != 0; 14186118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang } 14196118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang 1420b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1421b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Rendering 1422b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1423b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1424b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 1425b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang protected void render(GLCanvas canvas) { 142658ed4d197795147f9f4a202da00b411a6ed53bd2Doris Liu if (mFirst) { 142758ed4d197795147f9f4a202da00b411a6ed53bd2Doris Liu // Make sure the fields are properly initialized before checking 142858ed4d197795147f9f4a202da00b411a6ed53bd2Doris Liu // whether isCamera() 142958ed4d197795147f9f4a202da00b411a6ed53bd2Doris Liu mPictures.get(0).reload(); 143058ed4d197795147f9f4a202da00b411a6ed53bd2Doris Liu } 14319f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang // Check if the camera preview occupies the full screen. 14329f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang boolean full = !mFilmMode && mPictures.get(0).isCamera() 14339f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang && mPositionController.isCenter() 14349f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang && mPositionController.isAtMinimalScale(); 14356bf226e45ec542eae4f766a2417bfdda625af4f0Michael Kolb if (mFirst || full != mFullScreenCamera) { 14369f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang mFullScreenCamera = full; 14376bf226e45ec542eae4f766a2417bfdda625af4f0Michael Kolb mFirst = false; 14389f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang mListener.onFullScreenChanged(full); 14396118af9ddad8acc050133154f8f60c842c7f9bfaChih-Chung Chang if (full) mHandler.sendEmptyMessage(MSG_UNDO_BAR_FULL_CAMERA); 14409f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang } 14419f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang 14429f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang // Determine how many photos we need to draw in addition to the center 14439f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang // one. 14449f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang int neighbors; 14459f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang if (mFullScreenCamera) { 14469f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang neighbors = 0; 14479f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang } else { 14489f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang // In page mode, we draw only one previous/next photo. But if we are 14499f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang // doing capture animation, we want to draw all photos. 14509f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang boolean inPageMode = (mPositionController.getFilmRatio() == 0f); 14519f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang boolean inCaptureAnimation = 14529f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang ((mHolding & HOLD_CAPTURE_ANIMATION) != 0); 14539f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang if (inPageMode && !inCaptureAnimation) { 14549f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang neighbors = 1; 14559f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang } else { 14569f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang neighbors = SCREEN_NAIL_MAX; 14579f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang } 14589f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang } 1459c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang 1460c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang // Draw photos from back to front 1461c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang for (int i = neighbors; i >= -neighbors; i--) { 1462b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Rect r = mPositionController.getPosition(i); 1463b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPictures.get(i).draw(canvas, r); 1464b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1465b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 14666b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang renderChild(canvas, mEdgeView); 14676b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang renderChild(canvas, mUndoBar); 14686b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 1469b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.advanceAnimation(); 1470b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang checkFocusSwitching(); 1471ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang } 1472ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 1473b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1474b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Film mode focus switching 1475b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1476f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1477b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Runs in GL thread. 1478b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void checkFocusSwitching() { 1479b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (!mFilmMode) return; 1480b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mHandler.hasMessages(MSG_SWITCH_FOCUS)) return; 1481b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (switchPosition() != 0) { 1482b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mHandler.sendEmptyMessage(MSG_SWITCH_FOCUS); 1483f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1484f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1485f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1486b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Runs in main thread. 1487b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void switchFocus() { 14882c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (mHolding != 0) return; 1489b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang switch (switchPosition()) { 1490b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang case -1: 1491b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang switchToPrevImage(); 1492b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang break; 1493b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang case 1: 1494b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang switchToNextImage(); 1495b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang break; 1496b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1497f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1498f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1499b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Returns -1 if we should switch focus to the previous picture, +1 if we 1500b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // should switch to the next, 0 otherwise. 1501b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private int switchPosition() { 1502b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Rect curr = mPositionController.getPosition(0); 1503b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int center = getWidth() / 2; 1504f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 15052c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (curr.left > center && mPrevBound < 0) { 1506b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Rect prev = mPositionController.getPosition(-1); 1507b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int currDist = curr.left - center; 1508b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int prevDist = center - prev.right; 1509b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (prevDist < currDist) { 1510b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return -1; 1511b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 15122c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } else if (curr.right < center && mNextBound > 0) { 1513b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Rect next = mPositionController.getPosition(1); 1514b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int currDist = center - curr.right; 1515b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int nextDist = next.left - center; 1516b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (nextDist < currDist) { 1517b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return 1; 1518b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1519b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1520f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1521b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return 0; 1522f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1523f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 152417ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang // Switch to the previous or next picture if the hit position is inside 152517ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang // one of their boxes. This runs in main thread. 152617ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang private void switchToHitPicture(int x, int y) { 152717ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang if (mPrevBound < 0) { 152817ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang Rect r = mPositionController.getPosition(-1); 152917ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang if (r.right >= x) { 153017ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang slideToPrevPicture(); 153117ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang return; 153217ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang } 153317ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang } 153417ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang 153517ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang if (mNextBound > 0) { 153617ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang Rect r = mPositionController.getPosition(1); 153717ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang if (r.left <= x) { 153817ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang slideToNextPicture(); 153917ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang return; 154017ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang } 154117ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang } 154217ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang } 154317ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang 1544b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1545b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Page mode focus switching 1546b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // 1547b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // We slide image to the next one or the previous one in two cases: 1: If 1548b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // the user did a fling gesture with enough velocity. 2 If the user has 1549b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // moved the picture a lot. 1550b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1551f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1552b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private boolean swipeImages(float velocityX, float velocityY) { 1553b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mFilmMode) return false; 1554f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1555b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Avoid swiping images if we're possibly flinging to view the 1556b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // zoomed in picture vertically. 1557b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang PositionController controller = mPositionController; 1558b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang boolean isMinimal = controller.isAtMinimalScale(); 1559b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int edges = controller.getImageAtEdges(); 1560b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (!isMinimal && Math.abs(velocityY) > Math.abs(velocityX)) 1561b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if ((edges & PositionController.IMAGE_AT_TOP_EDGE) == 0 1562b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang || (edges & PositionController.IMAGE_AT_BOTTOM_EDGE) == 0) 1563b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return false; 1564f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1565b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // If we are at the edge of the current photo and the sweeping velocity 1566b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // exceeds the threshold, slide to the next / previous image. 1567b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (velocityX < -SWIPE_THRESHOLD && (isMinimal 1568b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang || (edges & PositionController.IMAGE_AT_RIGHT_EDGE) != 0)) { 1569b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return slideToNextPicture(); 1570b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } else if (velocityX > SWIPE_THRESHOLD && (isMinimal 1571b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang || (edges & PositionController.IMAGE_AT_LEFT_EDGE) != 0)) { 1572b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return slideToPrevPicture(); 1573f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1574f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1575b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return false; 1576b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1577b29a27f475a2c449abdda8d4e03d30914feed8c6Chih-Chung Chang 15782c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang private void snapback() { 15796b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if ((mHolding & ~HOLD_DELETE) != 0) return; 1580499ac9eae0eb26eaf7ebf79fb88ba929b71c8145Bobby Georgescu if (mFilmMode || !snapToNeighborImage()) { 15812c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mPositionController.snapback(); 15822c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 15832c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 15842c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang 1585b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private boolean snapToNeighborImage() { 1586b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Rect r = mPositionController.getPosition(0); 1587b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int viewW = getWidth(); 1588cda9315a4b3fb0228cbcd3e9a18d8c90f0a8a3e0Doris Liu // Setting the move threshold proportional to the width of the view 1589cda9315a4b3fb0228cbcd3e9a18d8c90f0a8a3e0Doris Liu int moveThreshold = viewW / 5 ; 1590cda9315a4b3fb0228cbcd3e9a18d8c90f0a8a3e0Doris Liu int threshold = moveThreshold + gapToSide(r.width(), viewW); 1591f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1592b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // If we have moved the picture a lot, switching. 1593b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (viewW - r.right > threshold) { 1594b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return slideToNextPicture(); 1595b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } else if (r.left > threshold) { 1596b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return slideToPrevPicture(); 1597f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1598f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1599b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return false; 1600b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1601f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1602b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private boolean slideToNextPicture() { 16032c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (mNextBound <= 0) return false; 1604b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang switchToNextImage(); 16052c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mPositionController.startHorizontalSlide(); 1606b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return true; 1607b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1608676170e619ad59ea97d04e0edcd62b1500304845Chih-Chung Chang 1609b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private boolean slideToPrevPicture() { 16102c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (mPrevBound >= 0) return false; 1611b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang switchToPrevImage(); 16122c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mPositionController.startHorizontalSlide(); 1613b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return true; 1614b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1615676170e619ad59ea97d04e0edcd62b1500304845Chih-Chung Chang 1616b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static int gapToSide(int imageWidth, int viewWidth) { 1617b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return Math.max(0, (viewWidth - imageWidth) / 2); 1618b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1619f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1620b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1621b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Focus switching 1622b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1623f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 16247eea4d3ac59aa88d327fc0d58f5e4052f43c54c9Bobby Georgescu public void switchToImage(int index) { 16257eea4d3ac59aa88d327fc0d58f5e4052f43c54c9Bobby Georgescu mModel.moveTo(index); 16267eea4d3ac59aa88d327fc0d58f5e4052f43c54c9Bobby Georgescu } 16277eea4d3ac59aa88d327fc0d58f5e4052f43c54c9Bobby Georgescu 1628b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void switchToNextImage() { 1629bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mModel.moveTo(mModel.getCurrentIndex() + 1); 1630b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 163115b351a22d02e89d882fc9fe32b3f4c512080e0aChih-Chung Chang 1632b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void switchToPrevImage() { 1633bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mModel.moveTo(mModel.getCurrentIndex() - 1); 1634b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1635cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1636160e6d776daab93610b3d12413ad9ff2dd867d8bChih-Chung Chang private void switchToFirstImage() { 1637bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mModel.moveTo(0); 1638160e6d776daab93610b3d12413ad9ff2dd867d8bChih-Chung Chang } 1639160e6d776daab93610b3d12413ad9ff2dd867d8bChih-Chung Chang 1640b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1641b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Opening Animation 1642b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1643b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1644b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void setOpenAnimationRect(Rect rect) { 1645b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.setOpenAnimationRect(rect); 1646cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 164715b351a22d02e89d882fc9fe32b3f4c512080e0aChih-Chung Chang 1648b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 16492c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // Capture Animation 16502c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang //////////////////////////////////////////////////////////////////////////// 16512c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang 16522c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang public boolean switchWithCaptureAnimation(int offset) { 16532c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang GLRoot root = getGLRoot(); 165414ce29ab5608daaa3d0074cdfc9fc85988537ff2Bobby Georgescu if(root == null) return false; 16552c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang root.lockRenderThread(); 16562c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang try { 16572c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang return switchWithCaptureAnimationLocked(offset); 16582c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } finally { 16592c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang root.unlockRenderThread(); 16602c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 16612c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 16622c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang 16632c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang private boolean switchWithCaptureAnimationLocked(int offset) { 16642c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (mHolding != 0) return true; 16652c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (offset == 1) { 16662c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (mNextBound <= 0) return false; 166761f94714c3702115d2f89bb5f8829697be0c3680Chih-Chung Chang // Temporary disable action bar until the capture animation is done. 166861f94714c3702115d2f89bb5f8829697be0c3680Chih-Chung Chang if (!mFilmMode) mListener.onActionBarAllowed(false); 16692c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang switchToNextImage(); 16702c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mPositionController.startCaptureAnimationSlide(-1); 16712c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } else if (offset == -1) { 16722c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (mPrevBound >= 0) return false; 1673c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang if (mFilmMode) setFilmMode(false); 1674c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang 1675c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang // If we are too far away from the first image (so that we don't 1676c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang // have all the ScreenNails in-between), we go directly without 1677c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang // animation. 1678c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang if (mModel.getCurrentIndex() > SCREEN_NAIL_MAX) { 1679c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang switchToFirstImage(); 168042e1fed4edd9ed1e326aab2f7969242c56812952Chih-Chung Chang mPositionController.skipToFinalPosition(); 1681c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang return true; 1682c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang } 1683c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang 1684160e6d776daab93610b3d12413ad9ff2dd867d8bChih-Chung Chang switchToFirstImage(); 16852c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mPositionController.startCaptureAnimationSlide(1); 16862c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } else { 16872c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang return false; 16882c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 16892c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mHolding |= HOLD_CAPTURE_ANIMATION; 1690bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang Message m = mHandler.obtainMessage(MSG_CAPTURE_ANIMATION_DONE, offset, 0); 1691f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang mHandler.sendMessageDelayed(m, PositionController.CAPTURE_ANIMATION_TIME); 16922c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang return true; 16932c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 16942c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang 1695bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private void captureAnimationDone(int offset) { 16962c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mHolding &= ~HOLD_CAPTURE_ANIMATION; 1697e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang if (offset == 1 && !mFilmMode) { 1698e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang // Now the capture animation is done, enable the action bar. 1699e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang mListener.onActionBarAllowed(true); 1700e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang mListener.onActionBarWanted(); 1701bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 17022c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang snapback(); 17032c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 17042c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang 17052c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1706b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Card deck effect calculation 1707b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1708b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1709cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // Returns the scrolling progress value for an object moving out of a 1710cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // view. The progress value measures how much the object has moving out of 1711cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // the view. The object currently displays in [left, right), and the view is 1712cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // at [0, viewWidth]. 1713cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // 1714cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // The returned value is negative when the object is moving right, and 1715cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // positive when the object is moving left. The value goes to -1 or 1 when 1716cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // the object just moves out of the view completely. The value is 0 if the 1717cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // object currently fills the view. 1718cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private static float calculateMoveOutProgress(int left, int right, 1719cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang int viewWidth) { 1720cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // w = object width 1721cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // viewWidth = view width 1722cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang int w = right - left; 1723cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1724cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // If the object width is smaller than the view width, 1725cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // |....view....| 1726cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // |<-->| progress = -1 when left = viewWidth 1727bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // |<-->| progress = 0 when left = viewWidth / 2 - w / 2 1728cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // |<-->| progress = 1 when left = -w 1729cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang if (w < viewWidth) { 1730bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang int zx = viewWidth / 2 - w / 2; 1731bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (left > zx) { 1732bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang return -(left - zx) / (float) (viewWidth - zx); // progress = (0, -1] 1733bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } else { 1734bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang return (left - zx) / (float) (-w - zx); // progress = [0, 1] 1735bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 1736cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 1737cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1738cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // If the object width is larger than the view width, 1739cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // |..view..| 1740cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // |<--------->| progress = -1 when left = viewWidth 1741cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // |<--------->| progress = 0 between left = 0 1742cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // |<--------->| and right = viewWidth 1743cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // |<--------->| progress = 1 when right = 0 1744cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang if (left > 0) { 1745cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang return -left / (float) viewWidth; 1746cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 1747cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1748cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang if (right < viewWidth) { 1749cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang return (viewWidth - right) / (float) viewWidth; 1750cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 1751cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1752cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang return 0; 1753cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 1754cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1755cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // Maps a scrolling progress value to the alpha factor in the fading 1756cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // animation. 1757cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private float getScrollAlpha(float scrollProgress) { 1758cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang return scrollProgress < 0 ? mAlphaInterpolator.getInterpolation( 1759cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1 - Math.abs(scrollProgress)) : 1.0f; 1760cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 1761cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1762cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // Maps a scrolling progress value to the scaling factor in the fading 1763cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // animation. 1764cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private float getScrollScale(float scrollProgress) { 1765cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang float interpolatedProgress = mScaleInterpolator.getInterpolation( 1766cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang Math.abs(scrollProgress)); 1767cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang float scale = (1 - interpolatedProgress) + 1768cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang interpolatedProgress * TRANSITION_SCALE_FACTOR; 1769cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang return scale; 1770cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 1771cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1772cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1773cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // This interpolator emulates the rate at which the perceived scale of an 1774cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // object changes as its distance from a camera increases. When this 1775cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // interpolator is applied to a scale animation on a view, it evokes the 1776cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // sense that the object is shrinking due to moving away from the camera. 1777cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private static class ZInterpolator { 1778cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private float focalLength; 1779cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1780cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang public ZInterpolator(float foc) { 1781cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang focalLength = foc; 1782cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 1783cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1784cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang public float getInterpolation(float input) { 1785cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang return (1.0f - focalLength / (focalLength + input)) / 1786cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang (1.0f - focalLength / (focalLength + 1.0f)); 1787f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1788f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1789f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1790ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang // Returns an interpolated value for the page/film transition. 1791ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang // When ratio = 0, the result is from. 1792ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang // When ratio = 1, the result is to. 1793ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang private static float interpolate(float ratio, float from, float to) { 1794ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang return from + (to - from) * ratio * ratio; 1795ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang } 1796ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang 17976b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // Returns the alpha factor in film mode if a picture is not in the center. 17986b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // The 0.03 lower bound is to make the item always visible a bit. 17996b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private float getOffsetAlpha(float offset) { 18006b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang offset /= 0.5f; 18016b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang float alpha = (offset > 0) ? (1 - offset) : (1 + offset); 18026b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang return Utils.clamp(alpha, 0.03f, 1f); 18036b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 18046b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 1805b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1806b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Simple public utilities 1807b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1808f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1809bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public void setListener(Listener listener) { 1810bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mListener = listener; 1811f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1812616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin 1813616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin public Rect getPhotoRect(int index) { 1814616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin return mPositionController.getPosition(index); 1815616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin } 1816616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin 1817616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin public PhotoFallbackEffect buildFallbackEffect(GLView root, GLCanvas canvas) { 1818616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin Rect location = new Rect(); 1819616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin Utils.assertTrue(root.getBoundsOf(this, location)); 1820616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin 1821616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin Rect fullRect = bounds(); 1822616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin PhotoFallbackEffect effect = new PhotoFallbackEffect(); 1823616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin for (int i = -SCREEN_NAIL_MAX; i <= SCREEN_NAIL_MAX; ++i) { 1824616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin MediaItem item = mModel.getMediaItem(i); 1825616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin if (item == null) continue; 1826616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin ScreenNail sc = mModel.getScreenNail(i); 1827030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin if (!(sc instanceof TiledScreenNail) 1828030f8dad6aefc42d0af39bc1b93f370937d3e2abOwen Lin || ((TiledScreenNail) sc).isShowingPlaceholder()) continue; 182949affdc4e274098a34e4eb2dbe4a89a750f1ba7fOwen Lin 183049affdc4e274098a34e4eb2dbe4a89a750f1ba7fOwen Lin // Now, sc is BitmapScreenNail and is not showing placeholder 1831616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin Rect rect = new Rect(getPhotoRect(i)); 1832616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin if (!Rect.intersects(fullRect, rect)) continue; 1833616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin rect.offset(location.left, location.top); 1834616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin 183538155c4f4dd6f0173337eb9f3fea54803192e229Owen Lin int width = sc.getWidth(); 183638155c4f4dd6f0173337eb9f3fea54803192e229Owen Lin int height = sc.getHeight(); 183738155c4f4dd6f0173337eb9f3fea54803192e229Owen Lin 183838155c4f4dd6f0173337eb9f3fea54803192e229Owen Lin int rotation = mModel.getImageRotation(i); 183938155c4f4dd6f0173337eb9f3fea54803192e229Owen Lin RawTexture texture; 184038155c4f4dd6f0173337eb9f3fea54803192e229Owen Lin if ((rotation % 180) == 0) { 184138155c4f4dd6f0173337eb9f3fea54803192e229Owen Lin texture = new RawTexture(width, height, true); 184238155c4f4dd6f0173337eb9f3fea54803192e229Owen Lin canvas.beginRenderTarget(texture); 184338155c4f4dd6f0173337eb9f3fea54803192e229Owen Lin canvas.translate(width / 2f, height / 2f); 184438155c4f4dd6f0173337eb9f3fea54803192e229Owen Lin } else { 184538155c4f4dd6f0173337eb9f3fea54803192e229Owen Lin texture = new RawTexture(height, width, true); 184638155c4f4dd6f0173337eb9f3fea54803192e229Owen Lin canvas.beginRenderTarget(texture); 184738155c4f4dd6f0173337eb9f3fea54803192e229Owen Lin canvas.translate(height / 2f, width / 2f); 184838155c4f4dd6f0173337eb9f3fea54803192e229Owen Lin } 184938155c4f4dd6f0173337eb9f3fea54803192e229Owen Lin 185038155c4f4dd6f0173337eb9f3fea54803192e229Owen Lin canvas.rotate(rotation, 0, 0, 1); 185138155c4f4dd6f0173337eb9f3fea54803192e229Owen Lin canvas.translate(-width / 2f, -height / 2f); 185238155c4f4dd6f0173337eb9f3fea54803192e229Owen Lin sc.draw(canvas, 0, 0, width, height); 1853616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin canvas.endRenderTarget(); 1854616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin effect.addEntry(item.getPath(), rect, texture); 1855616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin } 1856616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin return effect; 1857616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin } 1858f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin} 1859