PhotoView.java revision 17ffedda6e3ed57b38afbb775594cf30d83fc652
1f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin/* 2f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Copyright (C) 2010 The Android Open Source Project 3f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 4f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Licensed under the Apache License, Version 2.0 (the "License"); 5f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * you may not use this file except in compliance with the License. 6f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * You may obtain a copy of the License at 7f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 8f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * http://www.apache.org/licenses/LICENSE-2.0 9f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 10f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Unless required by applicable law or agreed to in writing, software 11f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * distributed under the License is distributed on an "AS IS" BASIS, 12f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * See the License for the specific language governing permissions and 14f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * limitations under the License. 15f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */ 16f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 17f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpackage com.android.gallery3d.ui; 18f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 19f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.content.Context; 20f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.graphics.Color; 21cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Changimport android.graphics.Point; 2204ac045bf8da5082bbb0bdc9ea5f9c9b5b796ad0Yuli Huangimport android.graphics.Rect; 23f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.os.Message; 24f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.view.MotionEvent; 25cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Changimport android.view.animation.AccelerateInterpolator; 26f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 272b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Linimport com.android.gallery3d.R; 282b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Linimport com.android.gallery3d.app.GalleryActivity; 29cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Changimport com.android.gallery3d.common.Utils; 30b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Changimport com.android.gallery3d.data.MediaObject; 31b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Changimport com.android.gallery3d.util.RangeArray; 32b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 33b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Changimport java.util.Arrays; 342b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Lin 35f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpublic class PhotoView extends GLView { 36f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @SuppressWarnings("unused") 37f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final String TAG = "PhotoView"; 38c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang private static final int PLACEHOLDER_COLOR = 0xFF222222; 39f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 40f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static final int INVALID_SIZE = -1; 41b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public static final long INVALID_DATA_VERSION = 42b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang MediaObject.INVALID_DATA_VERSION; 43f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 44c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang public static class Size { 45c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang public int width; 46c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang public int height; 47c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang } 48c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang 49c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang public interface Model extends TileImageView.Model { 50bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public int getCurrentIndex(); 51bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public void moveTo(int index); 52c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang 53c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // Returns the size for the specified picture. If the size information is 54c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // not avaiable, width = height = 0. 55c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang public void getImageSize(int offset, Size size); 56c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang 57c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // Returns the rotation for the specified picture. 58c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang public int getImageRotation(int offset); 59f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 60b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // This amends the getScreenNail() method of TileImageView.Model to get 61b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // ScreenNail at previous (negative offset) or next (positive offset) 62b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // positions. Returns null if the specified ScreenNail is unavailable. 63b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public ScreenNail getScreenNail(int offset); 64c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang 65c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // Set this to true if we need the model to provide full images. 66b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang public void setNeedFullImage(boolean enabled); 67bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 68bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // Returns true if the item is the Camera preview. 69bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public boolean isCamera(int offset); 70b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 71b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 72bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public interface Listener { 73b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void onSingleTapUp(int x, int y); 74bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public void lockOrientation(); 75bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public void unlockOrientation(); 76bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public void onFullScreenChanged(boolean full); 7761f94714c3702115d2f89bb5f8829697be0c3680Chih-Chung Chang public void onActionBarAllowed(boolean allowed); 78b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 79f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 80bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // Here is a graph showing the places we need to lock/unlock device 81bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // orientation: 82bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // 83bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // +------------+ A +------------+ 84bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // Page mode | Camera |<---| Photo | 85bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // | [locked] |--->| [unlocked] | 86bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // +------------+ B +------------+ 87bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // ^ ^ 88bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // | C | D 89bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // +------------+ +------------+ 90bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // | Camera | | Photo | 91bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // Film mode | [*] | | [*] | 92bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // +------------+ +------------+ 93bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // 94bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // In Page mode, we want to lock in Camera because we don't want the system 95bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // rotation animation. We also want to unlock in Photo because we want to 96bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // show the system action bar in the right place. 97bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // 98bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // We don't show action bar in Film mode, so it's fine for it to be locked 99bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // or unlocked in Film mode. 100bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // 101bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // There are four transitions we need to check if we need to 102bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // lock/unlock. Marked as A to D above and in the code. 103bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 104b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static final int MSG_SHOW_LOADING = 1; 105b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static final int MSG_CANCEL_EXTRA_SCALING = 2; 106b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static final int MSG_SWITCH_FOCUS = 3; 1072c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang private static final int MSG_CAPTURE_ANIMATION_DONE = 4; 108f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 109b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static final long DELAY_SHOW_LOADING = 250; // 250ms; 110f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 111f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int LOADING_INIT = 0; 112f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int LOADING_TIMEOUT = 1; 113f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int LOADING_COMPLETE = 2; 114f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int LOADING_FAIL = 3; 115f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 116b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static final int MOVE_THRESHOLD = 256; 117f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final float SWIPE_THRESHOLD = 300f; 118f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 119f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final float DEFAULT_TEXT_SIZE = 20; 120cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private static float TRANSITION_SCALE_FACTOR = 0.74f; 1212c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang 1222c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // whether we want to apply card deck effect in page mode. 123b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static final boolean CARD_EFFECT = true; 124cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 125cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // Used to calculate the scaling factor for the fading animation. 126cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private ZInterpolator mScaleInterpolator = new ZInterpolator(0.5f); 127cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 128cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // Used to calculate the alpha factor for the fading animation. 129cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private AccelerateInterpolator mAlphaInterpolator = 130cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang new AccelerateInterpolator(0.9f); 131f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 132b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // We keep this many previous ScreenNails. (also this many next ScreenNails) 133b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public static final int SCREEN_NAIL_MAX = 3; 134b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 135b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // The picture entries, the valid index is from -SCREEN_NAIL_MAX to 136b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // SCREEN_NAIL_MAX. 137b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private final RangeArray<Picture> mPictures = 138b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang new RangeArray<Picture>(-SCREEN_NAIL_MAX, SCREEN_NAIL_MAX); 139f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 140b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private final long mDataVersion[] = new long[2 * SCREEN_NAIL_MAX + 1]; 141b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private final int mFromIndex[] = new int[2 * SCREEN_NAIL_MAX + 1]; 142f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1433a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang private final GestureRecognizer mGestureRecognizer; 144f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final PositionController mPositionController; 145f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 146bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private Listener mListener; 147f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private Model mModel; 148f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private StringTexture mLoadingText; 149f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private StringTexture mNoThumbnailText; 150b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private TileImageView mTileView; 151532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang private EdgeView mEdgeView; 152f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private Texture mVideoPlayIcon; 153f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 154f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private boolean mShowVideoPlayIcon; 155f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private ProgressSpinner mLoadingSpinner; 156f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 157f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private SynchronizedHandler mHandler; 158f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 159f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mLoadingState = LOADING_COMPLETE; 160f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 161cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private Point mImageCenter = new Point(); 162534b12fd804610dd67b8109bc08ba76f31afb33eChih-Chung Chang private boolean mCancelExtraScalingPending; 163b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private boolean mFilmMode = false; 164bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private int mDisplayRotation = 0; 165bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private int mCompensation = 0; 166bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private boolean mFullScreen = true; 167bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private Rect mCameraNaturalFrame = new Rect(); 168bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private Rect mCameraRect = new Rect(); 169f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 170c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // [mPrevBound, mNextBound] is the range of index for all pictures in the 171c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // model, if we assume the index of current focused picture is 0. So if 172c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // there are some previous pictures, mPrevBound < 0, and if there are some 173c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // next pictures, mNextBound > 0. 174c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang private int mPrevBound; 175c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang private int mNextBound; 176c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang 1772c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // This variable prevents us doing snapback until its values goes to 0. This 1782c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // happens if the user gesture is still in progress or we are in a capture 1792c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // animation. 1802c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang private int mHolding; 1812c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang private static final int HOLD_TOUCH_DOWN = 1; 18218958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang private static final int HOLD_CAPTURE_ANIMATION = 2; 1832c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang 184f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public PhotoView(GalleryActivity activity) { 185f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mTileView = new TileImageView(activity); 186f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin addComponent(mTileView); 187f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Context context = activity.getAndroidContext(); 188532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang mEdgeView = new EdgeView(context); 189532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang addComponent(mEdgeView); 190f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mLoadingSpinner = new ProgressSpinner(context); 191f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mLoadingText = StringTexture.newInstance( 192f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin context.getString(R.string.loading), 193f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin DEFAULT_TEXT_SIZE, Color.WHITE); 194f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mNoThumbnailText = StringTexture.newInstance( 195f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin context.getString(R.string.no_thumbnail), 196f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin DEFAULT_TEXT_SIZE, Color.WHITE); 197f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 198b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mHandler = new MyHandler(activity.getGLRoot()); 199f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 2003a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang mGestureRecognizer = new GestureRecognizer( 2013a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang context, new MyGestureListener()); 202f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 203b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController = new PositionController(context, 204b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang new PositionController.Listener() { 205b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void invalidate() { 206b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang PhotoView.this.invalidate(); 207b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 2082c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang public boolean isHolding() { 20918958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang return mHolding != 0; 210b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 211b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void onPull(int offset, int direction) { 212b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mEdgeView.onPull(offset, direction); 213b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 214b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void onRelease() { 215b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mEdgeView.onRelease(); 216b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 217b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void onAbsorb(int velocity, int direction) { 218b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mEdgeView.onAbsorb(velocity, direction); 219b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 220b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang }); 221f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mVideoPlayIcon = new ResourceTexture(context, R.drawable.ic_control_play); 222b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Arrays.fill(mDataVersion, INVALID_DATA_VERSION); 223b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = -SCREEN_NAIL_MAX; i <= SCREEN_NAIL_MAX; i++) { 224b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (i == 0) { 225b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPictures.put(i, new FullPicture()); 226cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } else { 227b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPictures.put(i, new ScreenNailPicture(i)); 228cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 229f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 230f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 231f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 232b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void setModel(Model model) { 233b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mModel = model; 234b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mTileView.setModel(mModel); 235f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 236f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 237b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang class MyHandler extends SynchronizedHandler { 238b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public MyHandler(GLRoot root) { 239b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang super(root); 240f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 241f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 242b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 243b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void handleMessage(Message message) { 244b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang switch (message.what) { 245b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang case MSG_SHOW_LOADING: { 246b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mLoadingState == LOADING_INIT) { 247b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // We don't need the opening animation 248b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.setOpenAnimationRect(null); 249b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 250b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mLoadingSpinner.startAnimation(); 251b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mLoadingState = LOADING_TIMEOUT; 252b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang invalidate(); 253b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 254b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang break; 255f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 256b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang case MSG_CANCEL_EXTRA_SCALING: { 257b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mGestureRecognizer.cancelScale(); 258b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.setExtraScalingRange(false); 259b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mCancelExtraScalingPending = false; 260b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang break; 261b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 262b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang case MSG_SWITCH_FOCUS: { 263b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang switchFocus(); 264b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang break; 265b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 2662c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang case MSG_CAPTURE_ANIMATION_DONE: { 267bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // message.arg1 is the offset parameter passed to 268bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // switchWithCaptureAnimation(). 269bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang captureAnimationDone(message.arg1); 2702c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang break; 2712c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 272b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang default: throw new AssertionError(message.what); 273f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 274f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 275b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang }; 276f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 277f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void updateLoadingState() { 278f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Possible transitions of mLoadingState: 279f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // INIT --> TIMEOUT, COMPLETE, FAIL 280f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // TIMEOUT --> COMPLETE, FAIL, INIT 281f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // COMPLETE --> INIT 282f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // FAIL --> INIT 28315b351a22d02e89d882fc9fe32b3f4c512080e0aChih-Chung Chang if (mModel.getLevelCount() != 0 || mModel.getScreenNail() != null) { 284f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mHandler.removeMessages(MSG_SHOW_LOADING); 285f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mLoadingState = LOADING_COMPLETE; 286f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else if (mModel.isFailedToLoad()) { 287f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mHandler.removeMessages(MSG_SHOW_LOADING); 288f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mLoadingState = LOADING_FAIL; 289a7b78e224b1808895ea2c3d42ae385526dea12aaYuli Huang // We don't want the opening animation after loading failure 290b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.setOpenAnimationRect(null); 291f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else if (mLoadingState != LOADING_INIT) { 292f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mLoadingState = LOADING_INIT; 293f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mHandler.removeMessages(MSG_SHOW_LOADING); 294f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mHandler.sendEmptyMessageDelayed( 295f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin MSG_SHOW_LOADING, DELAY_SHOW_LOADING); 296f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 297f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 298f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 299b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 300b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Data/Image change notifications 301b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 302b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 303c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang public void notifyDataChange(long[] versions, int prevBound, int nextBound) { 304c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang mPrevBound = prevBound; 305c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang mNextBound = nextBound; 306c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang 307b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Check if the data version actually changed. 308b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang boolean changed = false; 309b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int N = 2 * SCREEN_NAIL_MAX + 1; 310b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = 0; i < N; i++) { 311b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (versions[i] != mDataVersion[i]) { 312b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang changed = true; 313b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang break; 314b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 315f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 316b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (!changed) return; 317f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 318b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Create the mFromIndex array, which records the index where the picture 319b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // come from. The value Integer.MAX_VALUE means it's a new picture. 320b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = 0; i < N; i++) { 321b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang long v = versions[i]; 322b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (v == INVALID_DATA_VERSION) { 323b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mFromIndex[i] = Integer.MAX_VALUE; 324b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang continue; 325b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 326f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 327b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Try to find the same version number in the old array 328b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int j; 329b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (j = 0; j < N; j++) { 330b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mDataVersion[j] == v) { 331b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang break; 332b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 333f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 334b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mFromIndex[i] = (j < N) ? j - SCREEN_NAIL_MAX : Integer.MAX_VALUE; 335f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 336b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 337b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Copy the new data version 338b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = 0; i < N; i++) { 339b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mDataVersion[i] = versions[i]; 340b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 341b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 342b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Move the boxes 343bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mPositionController.moveBox(mFromIndex, mPrevBound < 0, mNextBound > 0, 344bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mModel.isCamera(0)); 345b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 346b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang // Update the ScreenNails. 347b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = -SCREEN_NAIL_MAX; i <= SCREEN_NAIL_MAX; i++) { 348b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPictures.get(i).reload(); 349b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 350b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 351b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang invalidate(); 352f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 353f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 354b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void notifyImageChange(int index) { 355b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPictures.get(index).reload(); 356b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang invalidate(); 357f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 358f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 359bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang @Override 360bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang protected void onOrient(int displayRotation, int compensation) { 361bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // onLayout will be called soon. We need to change the size and rotation 362bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // of the Camera ScreenNail, but we don't want it start moving because 363bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // the view size will be changed soon. 364bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mDisplayRotation = displayRotation; 365bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mCompensation = compensation; 366bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang for (int i = -SCREEN_NAIL_MAX; i <= SCREEN_NAIL_MAX; i++) { 367bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang Picture p = mPictures.get(i); 368bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (p.isCamera()) { 369bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang p.updateSize(true); 370bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 371bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 372bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 373bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 374bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang @Override 375bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang protected void onLayout( 376bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang boolean changeSize, int left, int top, int right, int bottom) { 377bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mTileView.layout(left, top, right, bottom); 378bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mEdgeView.layout(left, top, right, bottom); 379bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang updateConstrainedFrame(); 380bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (changeSize) { 381bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mPositionController.setViewSize(getWidth(), getHeight()); 382bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 383bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 384bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 385bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // Update the constrained frame due to layout change. 386bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private void updateConstrainedFrame() { 387bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang int w = getWidth(); 388bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang int h = getHeight(); 389bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang int rotation = getCameraRotation(); 390bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (rotation % 180 != 0) { 391bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang int tmp = w; 392bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang w = h; 393bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang h = tmp; 394bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 395bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 396bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang int l = mCameraNaturalFrame.left; 397bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang int t = mCameraNaturalFrame.top; 398bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang int r = mCameraNaturalFrame.right; 399bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang int b = mCameraNaturalFrame.bottom; 400bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 401bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang switch (rotation) { 402bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang case 0: mCameraRect.set(l, t, r, b); break; 403bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang case 90: mCameraRect.set(h - b, l, h - t, r); break; 404bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang case 180: mCameraRect.set(w - r, h - b, w - l, h - t); break; 405bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang case 270: mCameraRect.set(t, w - r, b, w - l); break; 406bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 407bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 408bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mPositionController.setConstrainedFrame(mCameraRect); 409bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 410bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 411bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public void setCameraNaturalFrame(Rect frame) { 412bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mCameraNaturalFrame.set(frame); 413bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 414bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 415bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // Returns the rotation we need to do to the camera texture before drawing 416bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // it to the canvas, assuming the camera texture is correct when the device 417bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // is in its natural orientation. 418bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private int getCameraRotation() { 419bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang return (mCompensation - mDisplayRotation + 360) % 360; 420bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 421bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 422b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 423b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Pictures 424b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 425b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 426b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private interface Picture { 427b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang void reload(); 428b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang void draw(GLCanvas canvas, Rect r); 429b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang void setScreenNail(ScreenNail s); 4302c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang boolean isCamera(); // whether the picture is a camera preview 431bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang void updateSize(boolean force); // called when mCompensation changes 432b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang }; 433f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 434b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang class FullPicture implements Picture { 435b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private int mRotation; 4362c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang private boolean mIsCamera; 437bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private boolean mWasCameraCenter; 438b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 439b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void FullPicture(TileImageView tileView) { 440b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mTileView = tileView; 441f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 442f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 443b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 444b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void reload() { 445b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // mImageWidth and mImageHeight will get updated 446b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mTileView.notifyModelInvalidated(); 4472c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mTileView.setAlpha(1.0f); 448b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 449bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mIsCamera = mModel.isCamera(0); 450bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang setScreenNail(mModel.getScreenNail(0)); 451bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang updateSize(false); 452bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang updateLoadingState(); 453bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 454bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 455bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang @Override 456bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public void updateSize(boolean force) { 457bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (mIsCamera) { 458bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mRotation = getCameraRotation(); 459bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } else { 460bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mRotation = mModel.getImageRotation(0); 461bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 462bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 463c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang int w = mTileView.mImageWidth; 464c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang int h = mTileView.mImageHeight; 465c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang mPositionController.setImageSize(0, 466c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang getRotated(mRotation, w, h), 467bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang getRotated(mRotation, h, w), 468bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang force); 469f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 470f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 471b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 472b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void draw(GLCanvas canvas, Rect r) { 473bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang boolean isCenter = mPositionController.isCenter(); 474bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 475b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mLoadingState == LOADING_COMPLETE) { 476b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang setTileViewPosition(r); 477b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang PhotoView.super.render(canvas); 478b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 479b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang renderMessage(canvas, r.centerX(), r.centerY()); 480cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 481aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang if (mIsCamera) { 482aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang boolean full = !mFilmMode && isCenter 483aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang && mPositionController.isAtMinimalScale(); 484aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang if (full != mFullScreen) { 485aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang mFullScreen = full; 486aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang mListener.onFullScreenChanged(full); 487aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang } 488aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang } 489aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang 490bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // We want to have the following transitions: 4912c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // (1) Move camera preview out of its place: switch to film mode 4922c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // (2) Move camera preview into its place: switch to page mode 4932c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // The extra mWasCenter check makes sure (1) does not apply if in 4942c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // page mode, we move _to_ the camera preview from another picture. 495bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 496bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // Holdings except touch-down prevent the transitions. 49718958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang if ((mHolding & ~HOLD_TOUCH_DOWN) != 0) return; 498bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 499bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang boolean isCameraCenter = mIsCamera && isCenter; 500bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 501bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (mWasCameraCenter && mIsCamera && !isCenter && !mFilmMode) { 50218958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang // Temporary disabled to de-emphasize filmstrip. 50318958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang // setFilmMode(true); 50418958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang } else if (!mWasCameraCenter && isCameraCenter && mFilmMode) { 505bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang setFilmMode(false); 506aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang } 507aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang 508aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang if (isCenter && !mFilmMode) { 509aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang if (mIsCamera) { 510aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang // move into camera, lock 511aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang mListener.lockOrientation(); // Transition A 512aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang } else { 513aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang // move out of camera, unlock 514aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang mListener.unlockOrientation(); // Transition B 515aeb3062e84ed28f0e25a73f511f287ae0a3e4294Chih-Chung Chang } 516bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 517bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 518bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mWasCameraCenter = isCameraCenter; 519cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 520cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 521b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 522b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang public void setScreenNail(ScreenNail s) { 523b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang mTileView.setScreenNail(s); 524cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 525f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 526b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 5272c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang public boolean isCamera() { 5282c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang return mIsCamera; 529f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 530f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 531b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void setTileViewPosition(Rect r) { 532b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang TileImageView t = mTileView; 533b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 534b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Find out the bitmap coordinates of the center of the view 535b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int imageW = mPositionController.getImageWidth(); 536b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int imageH = mPositionController.getImageHeight(); 537b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang float scale = mPositionController.getImageScale(); 538b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int viewW = getWidth(); 539b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int viewH = getHeight(); 540b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int centerX = (int) (imageW / 2f + 541b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang (viewW / 2f - r.exactCenterX()) / scale + 0.5f); 542b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int centerY = (int) (imageH / 2f + 543b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang (viewH / 2f - r.exactCenterY()) / scale + 0.5f); 544b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 5452c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang boolean wantsCardEffect = CARD_EFFECT && !mFilmMode 546bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang && !mIsCamera && !mPictures.get(-1).isCamera(); 5472c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (wantsCardEffect) { 548b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Calculate the move-out progress value. 549b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int left = r.left; 550b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int right = r.right; 551b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang float progress = calculateMoveOutProgress(left, right, viewW); 552b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang progress = Utils.clamp(progress, -1f, 1f); 553b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 554b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // We only want to apply the fading animation if the scrolling 555b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // movement is to the right. 556bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (progress < 0) { 557b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (right - left < viewW) { 558b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // If the picture is narrower than the view, keep it at 559b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // the center of the view. 560b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang centerX = imageW / 2; 561b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } else { 562b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // If the picture is wider than the view (it's 563b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // zoomed-in), keep the left edge of the object align 564b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // the the left edge of the view. 565b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang centerX = Math.round(viewW / 2f / scale); 566b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 567b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang scale *= getScrollScale(progress); 568b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang t.setAlpha(getScrollAlpha(progress)); 569b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 570b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 571f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 572b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // set the position of the tile view 573b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int inverseX = imageW - centerX; 574b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int inverseY = imageH - centerY; 575b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int rotation = mRotation; 576b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang switch (rotation) { 577b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang case 0: t.setPosition(centerX, centerY, scale, 0); break; 578b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang case 90: t.setPosition(centerY, inverseX, scale, 90); break; 579b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang case 180: t.setPosition(inverseX, inverseY, scale, 180); break; 580b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang case 270: t.setPosition(inverseY, centerX, scale, 270); break; 581b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang default: 582b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang throw new IllegalArgumentException(String.valueOf(rotation)); 583b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 584f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 585f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 586b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void renderMessage(GLCanvas canvas, int x, int y) { 587b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Draw the progress spinner and the text below it 588b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // 589b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // (x, y) is where we put the center of the spinner. 590b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // s is the size of the video play icon, and we use s to layout text 591b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // because we want to keep the text at the same place when the video 592b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // play icon is shown instead of the spinner. 593b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int w = getWidth(); 594b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int h = getHeight(); 595a11f19872b6059d97d31c047ac752354670e1267Ray Chen int s = Math.min(w, h) / 6; 596b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 597b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mLoadingState == LOADING_TIMEOUT) { 598b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang StringTexture m = mLoadingText; 599b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang ProgressSpinner p = mLoadingSpinner; 600b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang p.draw(canvas, x - p.getWidth() / 2, y - p.getHeight() / 2); 601b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang m.draw(canvas, x - m.getWidth() / 2, y + s / 2 + 5); 602b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang invalidate(); // we need to keep the spinner rotating 603b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } else if (mLoadingState == LOADING_FAIL) { 604b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang StringTexture m = mNoThumbnailText; 605b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang m.draw(canvas, x - m.getWidth() / 2, y + s / 2 + 5); 606b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 607f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 608b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Draw a debug indicator showing which picture has focus (index == 609b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // 0). 610b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // canvas.fillRect(x - 10, y - 10, 20, 20, 0x80FF00FF); 611f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 612b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Draw the video play icon (in the place where the spinner was) 613b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mShowVideoPlayIcon 614b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang && mLoadingState != LOADING_INIT 615b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang && mLoadingState != LOADING_TIMEOUT) { 616b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mVideoPlayIcon.draw(canvas, x - s / 2, y - s / 2, s, s); 617b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 618f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 619f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 620f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 621b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private class ScreenNailPicture implements Picture { 622b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private int mIndex; 623b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private int mRotation; 624b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private ScreenNail mScreenNail; 625c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang private Size mSize = new Size(); 6262c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang private boolean mIsCamera; 627f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 628b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public ScreenNailPicture(int index) { 629b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mIndex = index; 630b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 631532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 632b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 633b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void reload() { 634bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mIsCamera = mModel.isCamera(mIndex); 635c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang setScreenNail(mModel.getScreenNail(mIndex)); 636b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 637b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 638b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 639b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void draw(GLCanvas canvas, Rect r) { 640b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mScreenNail == null) { 641c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // Draw a placeholder rectange if there will be a picture in 642c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // this position. 643c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang if (mIndex >= mPrevBound && mIndex <= mNextBound) { 644c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang canvas.fillRect(r.left, r.top, r.width(), r.height(), 645c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang PLACEHOLDER_COLOR); 646c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang } 647b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return; 648f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 649b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (r.left >= getWidth() || r.right <= 0 || 650b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang r.top >= getHeight() || r.bottom <= 0) { 651b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mScreenNail.noDraw(); 652b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return; 653f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 654f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 655bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (mIsCamera && mFullScreen != false) { 656bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mFullScreen = false; 657bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mListener.onFullScreenChanged(false); 658bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 659bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 6602c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang boolean wantsCardEffect = CARD_EFFECT && !mFilmMode 6612c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang && (mIndex > 0) && !mPictures.get(0).isCamera(); 662532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 663b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int w = getWidth(); 664b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int drawW = getRotated(mRotation, r.width(), r.height()); 665b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int drawH = getRotated(mRotation, r.height(), r.width()); 6662c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang int cx = wantsCardEffect ? w / 2 : r.centerX(); 667b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int cy = r.centerY(); 668b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int flags = GLCanvas.SAVE_FLAG_MATRIX; 669f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 6702c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (wantsCardEffect) flags |= GLCanvas.SAVE_FLAG_ALPHA; 671b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang canvas.save(flags); 672b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang canvas.translate(cx, cy); 6732c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (wantsCardEffect) { 674b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang float progress = (float) (w / 2 - r.centerX()) / w; 675b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang progress = Utils.clamp(progress, -1, 1); 676b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang float alpha = getScrollAlpha(progress); 677b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang float scale = getScrollScale(progress); 678b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang canvas.multiplyAlpha(alpha); 679b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang canvas.scale(scale, scale, 1); 680b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 681b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mRotation != 0) { 682b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang canvas.rotate(mRotation, 0, 0, 1); 683b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 684b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mScreenNail.draw(canvas, -drawW / 2, -drawH / 2, drawW, drawH); 685b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang canvas.restore(); 686b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 687f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 688b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 689b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang public void setScreenNail(ScreenNail s) { 690b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mScreenNail == s) return; 691b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mScreenNail = s; 692bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang updateSize(false); 693bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 694bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 695bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang @Override 696bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public void updateSize(boolean force) { 697bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (mIsCamera) { 698bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mRotation = getCameraRotation(); 699bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } else { 700bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mRotation = mModel.getImageRotation(mIndex); 701bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 702c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang 703c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang int w = 0, h = 0; 704b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mScreenNail != null) { 705bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang w = mScreenNail.getWidth(); 706bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang h = mScreenNail.getHeight(); 707c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang } else if (mModel != null) { 708c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // If we don't have ScreenNail available, we can still try to 709c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang // get the size information of it. 710c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang mModel.getImageSize(mIndex, mSize); 711c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang w = mSize.width; 712c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang h = mSize.height; 713b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 714c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang 715c3b2d478f9032a8decf5c6254a238fc49e41b72cChih-Chung Chang if (w != 0 && h != 0) { 716b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.setImageSize(mIndex, 717b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang getRotated(mRotation, w, h), 718bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang getRotated(mRotation, h, w), 719bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang force); 720b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 721f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 722b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 723b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 7242c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang public boolean isCamera() { 7252c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang return mIsCamera; 726b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 727b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 728b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 729b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static int getRotated(int degree, int original, int theother) { 730b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return (degree % 180 == 0) ? original : theother; 731b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 732b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 733b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 734b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Gestures Handling 735b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 736b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 737b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 738b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang protected boolean onTouch(MotionEvent event) { 739b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mGestureRecognizer.onTouchEvent(event); 740b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return true; 741f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 742f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 7433a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang private class MyGestureListener implements GestureRecognizer.Listener { 7443a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang private boolean mIgnoreUpEvent = false; 745099989b310d84fe13eff0cdf2902bb3fb0bcbd14Chih-Chung Chang // If we can change mode for this scale gesture. 746099989b310d84fe13eff0cdf2902bb3fb0bcbd14Chih-Chung Chang private boolean mCanChangeMode; 74718958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang // If we have changed the film mode in this scaling gesture. 748b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private boolean mModeChanged; 74933f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang // If this scaling gesture should be ignored. 75033f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang private boolean mIgnoreScalingGesture; 75117ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang // whether the down action happened while the view is scrolling. 75217ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang private boolean mDownInScrolling; 753b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 7543a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang @Override 7553a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang public boolean onSingleTapUp(float x, float y) { 75617ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang if (mFilmMode && !mDownInScrolling) { 75717ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang switchToHitPicture((int) (x + 0.5f), (int) (y + 0.5f)); 758b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang setFilmMode(false); 75917ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang mIgnoreUpEvent = true; 760b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return true; 761b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 762b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 763bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (mListener != null) { 764bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mListener.onSingleTapUp((int) x, (int) y); 7653a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang } 7663a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang return true; 7673a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang } 7683a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang 7693a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang @Override 7703a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang public boolean onDoubleTap(float x, float y) { 77161f94714c3702115d2f89bb5f8829697be0c3680Chih-Chung Chang if (mPictures.get(0).isCamera()) return false; 7723a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang PositionController controller = mPositionController; 773b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang float scale = controller.getImageScale(); 7743a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang // onDoubleTap happened on the second ACTION_DOWN. 7753a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang // We need to ignore the next UP event. 7763a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang mIgnoreUpEvent = true; 7773a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang if (scale <= 1.0f || controller.isAtMinimalScale()) { 7783a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang controller.zoomIn(x, y, Math.max(1.5f, scale * 1.5f)); 7793a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang } else { 7803a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang controller.resetToFullView(); 7813a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang } 7823a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang return true; 7833a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang } 784f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 785f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 7863a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang public boolean onScroll(float dx, float dy) { 787b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.startScroll(-dx, -dy); 788f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return true; 789f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 790f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 791f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 7923a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang public boolean onFling(float velocityX, float velocityY) { 7932ce3c3bfe08fff5aee58007cc8ba8f4a50861ae2Yuli Huang if (swipeImages(velocityX, velocityY)) { 794b3aab90bb37aa9cc60be32e05678ee55d6575ee8Chih-Chung Chang mIgnoreUpEvent = true; 795b3aab90bb37aa9cc60be32e05678ee55d6575ee8Chih-Chung Chang } else if (mPositionController.fling(velocityX, velocityY)) { 796b3aab90bb37aa9cc60be32e05678ee55d6575ee8Chih-Chung Chang mIgnoreUpEvent = true; 797f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 798f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return true; 799f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 800f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 801f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 8023a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang public boolean onScaleBegin(float focusX, float focusY) { 80333f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang // We ignore the scaling gesture if it is a camera preview. 80433f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang mIgnoreScalingGesture = mPictures.get(0).isCamera(); 80533f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang if (mIgnoreScalingGesture) { 80633f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang return true; 80733f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang } 8083a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang mPositionController.beginScale(focusX, focusY); 809099989b310d84fe13eff0cdf2902bb3fb0bcbd14Chih-Chung Chang // We can change mode if we are in film mode, or we are in page 810099989b310d84fe13eff0cdf2902bb3fb0bcbd14Chih-Chung Chang // mode and at minimal scale. 811099989b310d84fe13eff0cdf2902bb3fb0bcbd14Chih-Chung Chang mCanChangeMode = mFilmMode 812099989b310d84fe13eff0cdf2902bb3fb0bcbd14Chih-Chung Chang || mPositionController.isAtMinimalScale(); 813b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mModeChanged = false; 814f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return true; 815f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 816f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 817f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 8183a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang public boolean onScale(float focusX, float focusY, float scale) { 81933f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang if (mIgnoreScalingGesture) { 82033f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang return true; 82133f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang } 82218958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang if (mModeChanged) return true; 823b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (Float.isNaN(scale) || Float.isInfinite(scale)) return false; 82433f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang 82533f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang // We wait for the scale change accumulated to a large enough change 82633f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang // before reacting to it. Otherwise we may mistakenly treat a 82733f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang // zoom-in gesture as zoom-out or vice versa. 82818958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang if (scale > 0.99f && scale < 1.01f) return false; 82933f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang 830b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int outOfRange = mPositionController.scaleBy(scale, focusX, focusY); 831b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 83218958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang // If mode changes, we treat this scaling gesture has ended. 83318958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang if (mCanChangeMode) { 834b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if ((outOfRange < 0 && !mFilmMode) || 835b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang (outOfRange > 0 && mFilmMode)) { 83618958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang stopExtraScalingIfNeeded(); 83718958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang 83818958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang // Removing the touch down flag allows snapback to happen 83933f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang // for film mode change. 84018958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang mHolding &= ~HOLD_TOUCH_DOWN; 841b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang setFilmMode(!mFilmMode); 84218958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang 84318958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang // We need to call onScaleEnd() before setting mModeChanged 84418958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang // to true. 84518958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang onScaleEnd(); 846b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mModeChanged = true; 847b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return true; 848534b12fd804610dd67b8109bc08ba76f31afb33eChih-Chung Chang } 849b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 850b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 85118958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang if (outOfRange != 0) { 852b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang startExtraScalingIfNeeded(); 853534b12fd804610dd67b8109bc08ba76f31afb33eChih-Chung Chang } else { 854b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang stopExtraScalingIfNeeded(); 855534b12fd804610dd67b8109bc08ba76f31afb33eChih-Chung Chang } 856f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return true; 857f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 858f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 85933f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang @Override 86033f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang public void onScaleEnd() { 86133f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang if (mIgnoreScalingGesture) { 86233f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang return; 86333f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang } 86433f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang if (mModeChanged) return; 86533f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang mPositionController.endScale(); 86633f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang } 86733f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang 868b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void startExtraScalingIfNeeded() { 869b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (!mCancelExtraScalingPending) { 870b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mHandler.sendEmptyMessageDelayed( 871b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang MSG_CANCEL_EXTRA_SCALING, 700); 872b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.setExtraScalingRange(true); 873b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mCancelExtraScalingPending = true; 874b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 875b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 876b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 877b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void stopExtraScalingIfNeeded() { 878b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mCancelExtraScalingPending) { 879b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mHandler.removeMessages(MSG_CANCEL_EXTRA_SCALING); 880b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.setExtraScalingRange(false); 881b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mCancelExtraScalingPending = false; 882b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 883b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 884b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 885f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 8863a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang public void onDown() { 8872c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mHolding |= HOLD_TOUCH_DOWN; 88817ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang 88917ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang if (mFilmMode && mPositionController.isScrolling()) { 89017ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang mDownInScrolling = true; 89117ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang mPositionController.stopScrolling(); 89217ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang } else { 89317ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang mDownInScrolling = false; 89417ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang } 8953a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang } 8963a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang 8973a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang @Override 8983a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang public void onUp() { 89918958c51f1412d959d52500ceefc46f987d035f3Chih-Chung Chang mHolding &= ~HOLD_TOUCH_DOWN; 9003a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang mEdgeView.onRelease(); 9013a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang 9023a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang if (mIgnoreUpEvent) { 9033a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang mIgnoreUpEvent = false; 9043a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang return; 9053a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang } 906b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 9072c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang snapback(); 908f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 909f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 910f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 911b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void setFilmMode(boolean enabled) { 912b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mFilmMode == enabled) return; 913b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mFilmMode = enabled; 914b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.setFilmMode(mFilmMode); 915b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang mModel.setNeedFullImage(!enabled); 91661f94714c3702115d2f89bb5f8829697be0c3680Chih-Chung Chang mListener.onActionBarAllowed(!enabled); 917bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 918bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // If we leave filmstrip mode, we should lock/unlock 919bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (!enabled) { 920bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (mPictures.get(0).isCamera()) { 921bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mListener.lockOrientation(); // Transition C 922bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } else { 923bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mListener.unlockOrientation(); // Transition D 924bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 925bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 926bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 927bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 928bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public boolean getFilmMode() { 929bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang return mFilmMode; 930f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 931f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 932b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 933b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Framework events 934b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 935b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 936b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void pause() { 937b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.skipAnimation(); 938b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mTileView.freeTextures(); 939b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = -SCREEN_NAIL_MAX; i <= SCREEN_NAIL_MAX; i++) { 940b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang mPictures.get(i).setScreenNail(null); 941b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 942f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 943f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 944b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void resume() { 945b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mTileView.prepareTextures(); 946f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 947f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 94833f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang // move to the camera preview and show controls after resume 94933f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang public void resetToFirstPicture() { 95033f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang mModel.moveTo(0); 95133f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang setFilmMode(false); 95233f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang } 95333f8567dd5003e4bb342683f3768ab7552648b02Chih-Chung Chang 954b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 955b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Rendering 956b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 957b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 958b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 959b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang protected void render(GLCanvas canvas) { 960b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Draw next photos 961b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = 1; i <= SCREEN_NAIL_MAX; i++) { 962b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Rect r = mPositionController.getPosition(i); 963b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPictures.get(i).draw(canvas, r); 964b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // In page mode, we draw only one next photo. 965b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (!mFilmMode) break; 966b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 967b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 968b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Draw current photo 969b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPictures.get(0).draw(canvas, mPositionController.getPosition(0)); 970b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 971b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Draw previous photos 972b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = -1; i >= -SCREEN_NAIL_MAX; i--) { 973b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Rect r = mPositionController.getPosition(i); 974b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPictures.get(i).draw(canvas, r); 975b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // In page mode, we draw only one previous photo. 976b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (!mFilmMode) break; 977b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 978b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 979b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.advanceAnimation(); 980b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang checkFocusSwitching(); 981ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang } 982ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 983b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 984b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Film mode focus switching 985b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 986f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 987b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Runs in GL thread. 988b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void checkFocusSwitching() { 989b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (!mFilmMode) return; 990b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mHandler.hasMessages(MSG_SWITCH_FOCUS)) return; 991b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (switchPosition() != 0) { 992b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mHandler.sendEmptyMessage(MSG_SWITCH_FOCUS); 993f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 994f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 995f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 996b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Runs in main thread. 997b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void switchFocus() { 9982c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (mHolding != 0) return; 999b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang switch (switchPosition()) { 1000b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang case -1: 1001b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang switchToPrevImage(); 1002b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang break; 1003b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang case 1: 1004b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang switchToNextImage(); 1005b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang break; 1006b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1007f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1008f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1009b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Returns -1 if we should switch focus to the previous picture, +1 if we 1010b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // should switch to the next, 0 otherwise. 1011b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private int switchPosition() { 1012b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Rect curr = mPositionController.getPosition(0); 1013b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int center = getWidth() / 2; 1014f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 10152c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (curr.left > center && mPrevBound < 0) { 1016b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Rect prev = mPositionController.getPosition(-1); 1017b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int currDist = curr.left - center; 1018b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int prevDist = center - prev.right; 1019b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (prevDist < currDist) { 1020b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return -1; 1021b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 10222c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } else if (curr.right < center && mNextBound > 0) { 1023b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Rect next = mPositionController.getPosition(1); 1024b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int currDist = center - curr.right; 1025b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int nextDist = next.left - center; 1026b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (nextDist < currDist) { 1027b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return 1; 1028b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1029b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1030f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1031b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return 0; 1032f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1033f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 103417ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang // Switch to the previous or next picture if the hit position is inside 103517ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang // one of their boxes. This runs in main thread. 103617ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang private void switchToHitPicture(int x, int y) { 103717ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang if (mPrevBound < 0) { 103817ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang Rect r = mPositionController.getPosition(-1); 103917ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang if (r.right >= x) { 104017ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang slideToPrevPicture(); 104117ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang return; 104217ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang } 104317ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang } 104417ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang 104517ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang if (mNextBound > 0) { 104617ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang Rect r = mPositionController.getPosition(1); 104717ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang if (r.left <= x) { 104817ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang slideToNextPicture(); 104917ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang return; 105017ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang } 105117ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang } 105217ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang } 105317ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang 1054b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1055b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Page mode focus switching 1056b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // 1057b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // We slide image to the next one or the previous one in two cases: 1: If 1058b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // the user did a fling gesture with enough velocity. 2 If the user has 1059b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // moved the picture a lot. 1060b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1061f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1062b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private boolean swipeImages(float velocityX, float velocityY) { 1063b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mFilmMode) return false; 1064f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1065b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Avoid swiping images if we're possibly flinging to view the 1066b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // zoomed in picture vertically. 1067b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang PositionController controller = mPositionController; 1068b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang boolean isMinimal = controller.isAtMinimalScale(); 1069b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int edges = controller.getImageAtEdges(); 1070b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (!isMinimal && Math.abs(velocityY) > Math.abs(velocityX)) 1071b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if ((edges & PositionController.IMAGE_AT_TOP_EDGE) == 0 1072b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang || (edges & PositionController.IMAGE_AT_BOTTOM_EDGE) == 0) 1073b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return false; 1074f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1075b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // If we are at the edge of the current photo and the sweeping velocity 1076b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // exceeds the threshold, slide to the next / previous image. 1077b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (velocityX < -SWIPE_THRESHOLD && (isMinimal 1078b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang || (edges & PositionController.IMAGE_AT_RIGHT_EDGE) != 0)) { 1079b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return slideToNextPicture(); 1080b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } else if (velocityX > SWIPE_THRESHOLD && (isMinimal 1081b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang || (edges & PositionController.IMAGE_AT_LEFT_EDGE) != 0)) { 1082b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return slideToPrevPicture(); 1083f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1084f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1085b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return false; 1086b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1087b29a27f475a2c449abdda8d4e03d30914feed8c6Chih-Chung Chang 10882c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang private void snapback() { 10892c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (mHolding != 0) return; 10902c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (!snapToNeighborImage()) { 10912c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mPositionController.snapback(); 10922c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 10932c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 10942c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang 1095b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private boolean snapToNeighborImage() { 1096b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mFilmMode) return false; 1097f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1098b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Rect r = mPositionController.getPosition(0); 1099b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int viewW = getWidth(); 1100b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int threshold = MOVE_THRESHOLD + gapToSide(r.width(), viewW); 1101f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1102b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // If we have moved the picture a lot, switching. 1103b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (viewW - r.right > threshold) { 1104b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return slideToNextPicture(); 1105b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } else if (r.left > threshold) { 1106b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return slideToPrevPicture(); 1107f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1108f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1109b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return false; 1110b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1111f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1112b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private boolean slideToNextPicture() { 11132c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (mNextBound <= 0) return false; 1114b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang switchToNextImage(); 11152c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mPositionController.startHorizontalSlide(); 1116b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return true; 1117b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1118676170e619ad59ea97d04e0edcd62b1500304845Chih-Chung Chang 1119b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private boolean slideToPrevPicture() { 11202c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (mPrevBound >= 0) return false; 1121b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang switchToPrevImage(); 11222c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mPositionController.startHorizontalSlide(); 1123b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return true; 1124b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1125676170e619ad59ea97d04e0edcd62b1500304845Chih-Chung Chang 1126b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static int gapToSide(int imageWidth, int viewWidth) { 1127b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return Math.max(0, (viewWidth - imageWidth) / 2); 1128b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1129f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1130b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1131b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Focus switching 1132b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1133f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1134b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void switchToNextImage() { 1135bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mModel.moveTo(mModel.getCurrentIndex() + 1); 1136b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 113715b351a22d02e89d882fc9fe32b3f4c512080e0aChih-Chung Chang 1138b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void switchToPrevImage() { 1139bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mModel.moveTo(mModel.getCurrentIndex() - 1); 1140b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1141cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1142160e6d776daab93610b3d12413ad9ff2dd867d8bChih-Chung Chang private void switchToFirstImage() { 1143bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mModel.moveTo(0); 1144160e6d776daab93610b3d12413ad9ff2dd867d8bChih-Chung Chang } 1145160e6d776daab93610b3d12413ad9ff2dd867d8bChih-Chung Chang 1146b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1147b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Opening Animation 1148b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1149b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1150b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void setOpenAnimationRect(Rect rect) { 1151b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPositionController.setOpenAnimationRect(rect); 1152cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 115315b351a22d02e89d882fc9fe32b3f4c512080e0aChih-Chung Chang 1154b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 11552c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // Capture Animation 11562c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang //////////////////////////////////////////////////////////////////////////// 11572c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang 11582c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang public boolean switchWithCaptureAnimation(int offset) { 11592c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang GLRoot root = getGLRoot(); 11602c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang root.lockRenderThread(); 11612c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang try { 11622c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang return switchWithCaptureAnimationLocked(offset); 11632c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } finally { 11642c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang root.unlockRenderThread(); 11652c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 11662c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 11672c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang 11682c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang private boolean switchWithCaptureAnimationLocked(int offset) { 11692c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (mHolding != 0) return true; 11702c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (offset == 1) { 11712c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (mNextBound <= 0) return false; 117261f94714c3702115d2f89bb5f8829697be0c3680Chih-Chung Chang // Temporary disable action bar until the capture animation is done. 117361f94714c3702115d2f89bb5f8829697be0c3680Chih-Chung Chang if (!mFilmMode) mListener.onActionBarAllowed(false); 11742c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang switchToNextImage(); 11752c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mPositionController.startCaptureAnimationSlide(-1); 11762c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } else if (offset == -1) { 11772c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (mPrevBound >= 0) return false; 1178160e6d776daab93610b3d12413ad9ff2dd867d8bChih-Chung Chang switchToFirstImage(); 11792c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mPositionController.startCaptureAnimationSlide(1); 11802c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } else { 11812c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang return false; 11822c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 11832c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mHolding |= HOLD_CAPTURE_ANIMATION; 1184bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang Message m = mHandler.obtainMessage(MSG_CAPTURE_ANIMATION_DONE, offset, 0); 1185bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mHandler.sendMessageDelayed(m, 800); 11862c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang return true; 11872c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 11882c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang 1189bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private void captureAnimationDone(int offset) { 11902c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mHolding &= ~HOLD_CAPTURE_ANIMATION; 1191bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (offset == 1) { 1192bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // move out of camera, unlock 119361f94714c3702115d2f89bb5f8829697be0c3680Chih-Chung Chang if (!mFilmMode) { 119461f94714c3702115d2f89bb5f8829697be0c3680Chih-Chung Chang // Now the capture animation is done, enable the action bar. 119561f94714c3702115d2f89bb5f8829697be0c3680Chih-Chung Chang mListener.onActionBarAllowed(true); 119661f94714c3702115d2f89bb5f8829697be0c3680Chih-Chung Chang } 1197bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 11982c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang snapback(); 11992c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 12002c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang 12012c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1202b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Card deck effect calculation 1203b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1204b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1205cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // Returns the scrolling progress value for an object moving out of a 1206cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // view. The progress value measures how much the object has moving out of 1207cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // the view. The object currently displays in [left, right), and the view is 1208cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // at [0, viewWidth]. 1209cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // 1210cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // The returned value is negative when the object is moving right, and 1211cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // positive when the object is moving left. The value goes to -1 or 1 when 1212cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // the object just moves out of the view completely. The value is 0 if the 1213cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // object currently fills the view. 1214cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private static float calculateMoveOutProgress(int left, int right, 1215cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang int viewWidth) { 1216cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // w = object width 1217cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // viewWidth = view width 1218cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang int w = right - left; 1219cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1220cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // If the object width is smaller than the view width, 1221cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // |....view....| 1222cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // |<-->| progress = -1 when left = viewWidth 1223bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // |<-->| progress = 0 when left = viewWidth / 2 - w / 2 1224cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // |<-->| progress = 1 when left = -w 1225cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang if (w < viewWidth) { 1226bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang int zx = viewWidth / 2 - w / 2; 1227bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (left > zx) { 1228bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang return -(left - zx) / (float) (viewWidth - zx); // progress = (0, -1] 1229bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } else { 1230bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang return (left - zx) / (float) (-w - zx); // progress = [0, 1] 1231bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 1232cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 1233cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1234cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // If the object width is larger than the view width, 1235cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // |..view..| 1236cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // |<--------->| progress = -1 when left = viewWidth 1237cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // |<--------->| progress = 0 between left = 0 1238cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // |<--------->| and right = viewWidth 1239cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // |<--------->| progress = 1 when right = 0 1240cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang if (left > 0) { 1241cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang return -left / (float) viewWidth; 1242cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 1243cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1244cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang if (right < viewWidth) { 1245cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang return (viewWidth - right) / (float) viewWidth; 1246cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 1247cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1248cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang return 0; 1249cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 1250cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1251cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // Maps a scrolling progress value to the alpha factor in the fading 1252cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // animation. 1253cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private float getScrollAlpha(float scrollProgress) { 1254cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang return scrollProgress < 0 ? mAlphaInterpolator.getInterpolation( 1255cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1 - Math.abs(scrollProgress)) : 1.0f; 1256cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 1257cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1258cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // Maps a scrolling progress value to the scaling factor in the fading 1259cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // animation. 1260cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private float getScrollScale(float scrollProgress) { 1261cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang float interpolatedProgress = mScaleInterpolator.getInterpolation( 1262cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang Math.abs(scrollProgress)); 1263cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang float scale = (1 - interpolatedProgress) + 1264cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang interpolatedProgress * TRANSITION_SCALE_FACTOR; 1265cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang return scale; 1266cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 1267cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1268cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1269cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // This interpolator emulates the rate at which the perceived scale of an 1270cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // object changes as its distance from a camera increases. When this 1271cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // interpolator is applied to a scale animation on a view, it evokes the 1272cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang // sense that the object is shrinking due to moving away from the camera. 1273cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private static class ZInterpolator { 1274cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang private float focalLength; 1275cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1276cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang public ZInterpolator(float foc) { 1277cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang focalLength = foc; 1278cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang } 1279cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang 1280cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang public float getInterpolation(float input) { 1281cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang return (1.0f - focalLength / (focalLength + input)) / 1282cb4fb7c19f20405fb5e08513e6297dffce824118Chih-Chung Chang (1.0f - focalLength / (focalLength + 1.0f)); 1283f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1284f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1285f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1286b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1287b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Simple public utilities 1288b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1289f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1290bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public void setListener(Listener listener) { 1291bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mListener = listener; 1292f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1293f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1294f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void showVideoPlayIcon(boolean show) { 1295f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mShowVideoPlayIcon = show; 1296f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1297f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin} 1298