1ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang/* 2ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang * Copyright (C) 2011 The Android Open Source Project 3ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang * 4ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang * Licensed under the Apache License, Version 2.0 (the "License"); 5ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang * you may not use this file except in compliance with the License. 6ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang * You may obtain a copy of the License at 7ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang * 8ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang * http://www.apache.org/licenses/LICENSE-2.0 9ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang * 10ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang * Unless required by applicable law or agreed to in writing, software 11ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang * distributed under the License is distributed on an "AS IS" BASIS, 12ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang * See the License for the specific language governing permissions and 14ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang * limitations under the License. 15ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang */ 16ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 17ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Changpackage com.android.gallery3d.ui; 18ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 19ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Changimport android.content.Context; 2004ac045bf8da5082bbb0bdc9ea5f9c9b5b796ad0Yuli Huangimport android.graphics.Rect; 21b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Changimport android.util.Log; 22b27df4650459068b409924493bbadaf25bb7e191Bobby Georgescuimport android.widget.Scroller; 23ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 242abaaf7caa9a83ba1ea759868aabde7f21387184John Reckimport com.android.gallery3d.app.PhotoPage; 252b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Linimport com.android.gallery3d.common.Utils; 2628cb4161da5fc3756933ca67d509b8af1c6275f1Owen Linimport com.android.gallery3d.ui.PhotoView.Size; 272b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Linimport com.android.gallery3d.util.GalleryUtils; 28b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Changimport com.android.gallery3d.util.RangeArray; 29b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Changimport com.android.gallery3d.util.RangeIntArray; 302b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Lin 31ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Changclass PositionController { 32b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static final String TAG = "PositionController"; 33b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 342ce3c3bfe08fff5aee58007cc8ba8f4a50861ae2Yuli Huang public static final int IMAGE_AT_LEFT_EDGE = 1; 352ce3c3bfe08fff5aee58007cc8ba8f4a50861ae2Yuli Huang public static final int IMAGE_AT_RIGHT_EDGE = 2; 362ce3c3bfe08fff5aee58007cc8ba8f4a50861ae2Yuli Huang public static final int IMAGE_AT_TOP_EDGE = 4; 372ce3c3bfe08fff5aee58007cc8ba8f4a50861ae2Yuli Huang public static final int IMAGE_AT_BOTTOM_EDGE = 8; 382ce3c3bfe08fff5aee58007cc8ba8f4a50861ae2Yuli Huang 39c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang public static final int CAPTURE_ANIMATION_TIME = 700; 406b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public static final int SNAPBACK_ANIMATION_TIME = 600; 41f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang 42b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Special values for animation time. 43ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang private static final long NO_ANIMATION = -1; 44ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang private static final long LAST_ANIMATION = -2; 45ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 466b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private static final int ANIM_KIND_NONE = -1; 47b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static final int ANIM_KIND_SCROLL = 0; 48b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static final int ANIM_KIND_SCALE = 1; 49b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static final int ANIM_KIND_SNAPBACK = 2; 50b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static final int ANIM_KIND_SLIDE = 3; 51b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static final int ANIM_KIND_ZOOM = 4; 52b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static final int ANIM_KIND_OPENING = 5; 53b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static final int ANIM_KIND_FLING = 6; 546b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private static final int ANIM_KIND_FLING_X = 7; 556b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private static final int ANIM_KIND_DELETE = 8; 566b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private static final int ANIM_KIND_CAPTURE = 9; 57ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 58676170e619ad59ea97d04e0edcd62b1500304845Chih-Chung Chang // Animation time in milliseconds. The order must match ANIM_KIND_* above. 596b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // 606b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // The values for ANIM_KIND_FLING_X does't matter because we use 616b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // mFilmScroller.isFinished() to decide when to stop. We set it to 0 so it's 626b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // faster for Animatable.advanceAnimation() to calculate the progress 636b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // (always 1). 64b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static final int ANIM_TIME[] = { 65676170e619ad59ea97d04e0edcd62b1500304845Chih-Chung Chang 0, // ANIM_KIND_SCROLL 662ce59cbd4368eaf0f30cfea28891bd47155182cbChih-Chung Chang 0, // ANIM_KIND_SCALE 676b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang SNAPBACK_ANIMATION_TIME, // ANIM_KIND_SNAPBACK 68676170e619ad59ea97d04e0edcd62b1500304845Chih-Chung Chang 400, // ANIM_KIND_SLIDE 69676170e619ad59ea97d04e0edcd62b1500304845Chih-Chung Chang 300, // ANIM_KIND_ZOOM 704831c7494373c360062a7becac820eba3bc39287Bobby Georgescu 300, // ANIM_KIND_OPENING 71b3aab90bb37aa9cc60be32e05678ee55d6575ee8Chih-Chung Chang 0, // ANIM_KIND_FLING (the duration is calculated dynamically) 726b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 0, // ANIM_KIND_FLING_X (see the comment above) 736b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 0, // ANIM_KIND_DELETE (the duration is calculated dynamically) 74f5ce6aeba448f418c99736465f7a02dacd7715bbChih-Chung Chang CAPTURE_ANIMATION_TIME, // ANIM_KIND_CAPTURE 75676170e619ad59ea97d04e0edcd62b1500304845Chih-Chung Chang }; 76676170e619ad59ea97d04e0edcd62b1500304845Chih-Chung Chang 77ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang // We try to scale up the image to fill the screen. But in order not to 78ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang // scale too much for small icons, we limit the max up-scaling factor here. 79ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang private static final float SCALE_LIMIT = 4; 80ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 81b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // For user's gestures, we give a temporary extra scaling range which goes 82b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // above or below the usual scaling limits. 83b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static final float SCALE_MIN_EXTRA = 0.7f; 84534b12fd804610dd67b8109bc08ba76f31afb33eChih-Chung Chang private static final float SCALE_MAX_EXTRA = 1.4f; 85534b12fd804610dd67b8109bc08ba76f31afb33eChih-Chung Chang 86b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Setting this true makes the extra scaling range permanent (until this is 87b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // set to false again). 88534b12fd804610dd67b8109bc08ba76f31afb33eChih-Chung Chang private boolean mExtraScalingRange = false; 89676170e619ad59ea97d04e0edcd62b1500304845Chih-Chung Chang 90b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Film Mode v.s. Page Mode: in film mode we show smaller pictures. 91b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private boolean mFilmMode = false; 92b3aab90bb37aa9cc60be32e05678ee55d6575ee8Chih-Chung Chang 93642561dd3177f9511c8bbeb90839066ecc451054Chih-Chung Chang // These are the limits for width / height of the picture in film mode. 94642561dd3177f9511c8bbeb90839066ecc451054Chih-Chung Chang private static final float FILM_MODE_PORTRAIT_HEIGHT = 0.48f; 95642561dd3177f9511c8bbeb90839066ecc451054Chih-Chung Chang private static final float FILM_MODE_PORTRAIT_WIDTH = 0.7f; 96642561dd3177f9511c8bbeb90839066ecc451054Chih-Chung Chang private static final float FILM_MODE_LANDSCAPE_HEIGHT = 0.7f; 97642561dd3177f9511c8bbeb90839066ecc451054Chih-Chung Chang private static final float FILM_MODE_LANDSCAPE_WIDTH = 0.7f; 98b3aab90bb37aa9cc60be32e05678ee55d6575ee8Chih-Chung Chang 99b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // In addition to the focused box (index == 0). We also keep information 100b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // about this many boxes on each side. 101b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static final int BOX_MAX = PhotoView.SCREEN_NAIL_MAX; 1026b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private static final int[] CENTER_OUT_INDEX = new int[2 * BOX_MAX + 1]; 103ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 104fb1a15559bb2a0a1c8a41efd3e0420a2a2d70590Chih-Chung Chang private static final int IMAGE_GAP = GalleryUtils.dpToPixel(16); 105b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static final int HORIZONTAL_SLACK = GalleryUtils.dpToPixel(12); 106ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 1076b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // These are constants for the delete gesture. 1086b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private static final int DEFAULT_DELETE_ANIMATION_DURATION = 200; // ms 1096b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private static final int MAX_DELETE_ANIMATION_DURATION = 400; // ms 1106b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 111b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private Listener mListener; 112b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private volatile Rect mOpenAnimationRect; 113ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang 1148b930828c7a33d668876972c22a515e9163592f7Pin Ting // Use a large enough value, so we won't see the gray shadow in the beginning. 115ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang private int mViewW = 1200; 116ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang private int mViewH = 1200; 117ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 1188b930828c7a33d668876972c22a515e9163592f7Pin Ting // A scaling gesture is in progress. 119b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private boolean mInScale; 120b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // The focus point of the scaling gesture, relative to the center of the 121b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // picture in bitmap pixels. 122b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private float mFocusX, mFocusY; 123ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 124fb1a15559bb2a0a1c8a41efd3e0420a2a2d70590Chih-Chung Chang // whether there is a previous/next picture. 125fb1a15559bb2a0a1c8a41efd3e0420a2a2d70590Chih-Chung Chang private boolean mHasPrev, mHasNext; 126fb1a15559bb2a0a1c8a41efd3e0420a2a2d70590Chih-Chung Chang 127b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // This is used by the fling animation (page mode). 128b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private FlingScroller mPageScroller; 129ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 130b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // This is used by the fling animation (film mode). 131b27df4650459068b409924493bbadaf25bb7e191Bobby Georgescu private Scroller mFilmScroller; 132ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 133b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // The bound of the stable region that the focused box can stay, see the 134b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // comments above calculateStableBound() for details. 135b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private int mBoundLeft, mBoundRight, mBoundTop, mBoundBottom; 136ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 137bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // Constrained frame is a rectangle that the focused box should fit into if 138bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // it is constrained. It has two effects: 139bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // 140bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // (1) In page mode, if the focused box is constrained, scaling for the 141bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // focused box is adjusted to fit into the constrained frame, instead of the 142bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // whole view. 143bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // 144bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // (2) In page mode, if the focused box is constrained, the mPlatform's 145bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // default center (mDefaultX/Y) is moved to the center of the constrained 146bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // frame, instead of the view center. 147bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // 148bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private Rect mConstrainedFrame = new Rect(); 149bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 150bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // Whether the focused box is constrained. 151bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // 152bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // Our current program's first call to moveBox() sets constrained = true, so 153bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // we set the initial value of this variable to true, and we will not see 154bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // see unwanted transition animation. 155bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private boolean mConstrained = true; 156bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 157b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // 158b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // ___________________________________________________________ 159b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // | _____ _____ _____ _____ _____ | 160b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // | | | | | | | | | | | | 161b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // | | Box | | Box | | Box*| | Box | | Box | | 162b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // | |_____|.....|_____|.....|_____|.....|_____|.....|_____| | 163b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // | Gap Gap Gap Gap | 164b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // |___________________________________________________________| 165b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // 166b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // <-- Platform --> 167b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // 168bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // The focused box (Box*) centers at mPlatform's (mCurrentX, mCurrentY) 169ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 170b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private Platform mPlatform = new Platform(); 171b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private RangeArray<Box> mBoxes = new RangeArray<Box>(-BOX_MAX, BOX_MAX); 172b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // The gap at the right of a Box i is at index i. The gap at the left of a 173b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Box i is at index i - 1. 174b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private RangeArray<Gap> mGaps = new RangeArray<Gap>(-BOX_MAX, BOX_MAX - 1); 175ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang private FilmRatio mFilmRatio = new FilmRatio(); 176ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 177b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // These are only used during moveBox(). 178b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private RangeArray<Box> mTempBoxes = new RangeArray<Box>(-BOX_MAX, BOX_MAX); 179fb1a15559bb2a0a1c8a41efd3e0420a2a2d70590Chih-Chung Chang private RangeArray<Gap> mTempGaps = 180fb1a15559bb2a0a1c8a41efd3e0420a2a2d70590Chih-Chung Chang new RangeArray<Gap>(-BOX_MAX, BOX_MAX - 1); 181ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 1828b930828c7a33d668876972c22a515e9163592f7Pin Ting // The output of the PositionController. Available through getPosition(). 183b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private RangeArray<Rect> mRects = new RangeArray<Rect>(-BOX_MAX, BOX_MAX); 184b3aab90bb37aa9cc60be32e05678ee55d6575ee8Chih-Chung Chang 1856b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // The direction of a new picture should appear. New pictures pop from top 1866b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // if this value is true, or from bottom if this value is false. 1876b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang boolean mPopFromTop; 1886b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 189b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public interface Listener { 190b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang void invalidate(); 1916b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang boolean isHoldingDown(); 1926b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang boolean isHoldingDelete(); 193ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 194b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // EdgeView 195b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang void onPull(int offset, int direction); 196b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang void onRelease(); 197b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang void onAbsorb(int velocity, int direction); 198b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 199ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 2006b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang static { 2016b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // Initialize the CENTER_OUT_INDEX array. 2026b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // The array maps 0, 1, 2, 3, 4, ..., 2 * BOX_MAX 2036b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // to 0, 1, -1, 2, -2, ..., BOX_MAX, -BOX_MAX 2046b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang for (int i = 0; i < CENTER_OUT_INDEX.length; i++) { 2056b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int j = (i + 1) / 2; 2066b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if ((i & 1) == 0) j = -j; 2076b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang CENTER_OUT_INDEX[i] = j; 2086b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 2096b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 2106b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 211b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public PositionController(Context context, Listener listener) { 212b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mListener = listener; 213b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPageScroller = new FlingScroller(); 2142abaaf7caa9a83ba1ea759868aabde7f21387184John Reck mFilmScroller = new Scroller(context, null, false); 215b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 216b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Initialize the areas. 217b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang initPlatform(); 218b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = -BOX_MAX; i <= BOX_MAX; i++) { 219b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mBoxes.put(i, new Box()); 220b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang initBox(i); 221b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mRects.put(i, new Rect()); 222b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 223b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = -BOX_MAX; i < BOX_MAX; i++) { 224b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mGaps.put(i, new Gap()); 225b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang initGap(i); 226b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 227ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang } 228ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 229b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void setOpenAnimationRect(Rect r) { 230b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mOpenAnimationRect = r; 231b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 232676170e619ad59ea97d04e0edcd62b1500304845Chih-Chung Chang 233b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void setViewSize(int viewW, int viewH) { 234b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (viewW == mViewW && viewH == mViewH) return; 235ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 236f3f90752ca92372d61ca0ec22a9846261cfbcbdeChih-Chung Chang boolean wasMinimal = isAtMinimalScale(); 237f3f90752ca92372d61ca0ec22a9846261cfbcbdeChih-Chung Chang 238b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mViewW = viewW; 239b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mViewH = viewH; 240b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang initPlatform(); 241ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 242b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = -BOX_MAX; i <= BOX_MAX; i++) { 243b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang setBoxSize(i, viewW, viewH, true); 244b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 245ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 246b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang updateScaleAndGapLimit(); 247e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang 248f3f90752ca92372d61ca0ec22a9846261cfbcbdeChih-Chung Chang // If the focused box was at minimal scale, we try to make it the 249f3f90752ca92372d61ca0ec22a9846261cfbcbdeChih-Chung Chang // minimal scale under the new view size. 250f3f90752ca92372d61ca0ec22a9846261cfbcbdeChih-Chung Chang if (wasMinimal) { 251f3f90752ca92372d61ca0ec22a9846261cfbcbdeChih-Chung Chang Box b = mBoxes.get(0); 252f3f90752ca92372d61ca0ec22a9846261cfbcbdeChih-Chung Chang b.mCurrentScale = b.mScaleMin; 253f3f90752ca92372d61ca0ec22a9846261cfbcbdeChih-Chung Chang } 254f3f90752ca92372d61ca0ec22a9846261cfbcbdeChih-Chung Chang 255e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang // If we have the opening animation, do it. Otherwise go directly to the 256e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang // right position. 257e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang if (!startOpeningAnimationIfNeeded()) { 25842e1fed4edd9ed1e326aab2f7969242c56812952Chih-Chung Chang skipToFinalPosition(); 259e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang } 260ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang } 261ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 2629f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang public void setConstrainedFrame(Rect cFrame) { 2639f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang if (mConstrainedFrame.equals(cFrame)) return; 2649f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang mConstrainedFrame.set(cFrame); 265bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mPlatform.updateDefaultXY(); 266bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang updateScaleAndGapLimit(); 267bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang snapAndRedraw(); 268bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 269bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 2706b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public void forceImageSize(int index, Size s) { 2716b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (s.width == 0 || s.height == 0) return; 2729f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang Box b = mBoxes.get(index); 2736b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang b.mImageW = s.width; 2746b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang b.mImageH = s.height; 2759f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang return; 2769f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang } 2779f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang 2786b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public void setImageSize(int index, Size s, Rect cFrame) { 2796b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (s.width == 0 || s.height == 0) return; 280bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 2819f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang boolean needUpdate = false; 2829f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang if (cFrame != null && !mConstrainedFrame.equals(cFrame)) { 2839f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang mConstrainedFrame.set(cFrame); 2849f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang mPlatform.updateDefaultXY(); 2859f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang needUpdate = true; 286b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 2876b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang needUpdate |= setBoxSize(index, s.width, s.height, false); 288ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 2899f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang if (!needUpdate) return; 290b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang updateScaleAndGapLimit(); 291b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang snapAndRedraw(); 292ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang } 293ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 2942c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // Returns false if the box size doesn't change. 2952c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang private boolean setBoxSize(int i, int width, int height, boolean isViewSize) { 296b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Box b = mBoxes.get(i); 297d848862c1dd0689df8df5d684476cfd3897557d6Chih-Chung Chang boolean wasViewSize = b.mUseViewSize; 298d848862c1dd0689df8df5d684476cfd3897557d6Chih-Chung Chang 299d848862c1dd0689df8df5d684476cfd3897557d6Chih-Chung Chang // If we already have an image size, we don't want to use the view size. 3002c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (!wasViewSize && isViewSize) return false; 301ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 302b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang b.mUseViewSize = isViewSize; 303ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 304b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (width == b.mImageW && height == b.mImageH) { 3052c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang return false; 306676170e619ad59ea97d04e0edcd62b1500304845Chih-Chung Chang } 307676170e619ad59ea97d04e0edcd62b1500304845Chih-Chung Chang 308b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // The ratio of the old size and the new size. 3099f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang // 3109f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang // If the aspect ratio changes, we don't know if it is because one side 3119f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang // grows or the other side shrinks. Currently we just assume the view 3129f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang // angle of the longer side doesn't change (so the aspect ratio change 3139f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang // is because the view angle of the shorter side changes). This matches 3149f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang // what camera preview does. 3159f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang float ratio = (width > height) 3169f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang ? (float) b.mImageW / width 3179f44f35c211229bc0c5ca17823f5d7b6bb3583a1Chih-Chung Chang : (float) b.mImageH / height; 318b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 319bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang b.mImageW = width; 320bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang b.mImageH = height; 321bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 322a65914485de7b82b96b616c7be738ab952e09c83John Reck // If this is the first time we receive an image size or we are in fullscreen, 323a65914485de7b82b96b616c7be738ab952e09c83John Reck // we change the scale directly. Otherwise adjust the scales by a ratio, 324a65914485de7b82b96b616c7be738ab952e09c83John Reck // and snapback will animate the scale into the min/max bounds if necessary. 325a65914485de7b82b96b616c7be738ab952e09c83John Reck if ((wasViewSize && !isViewSize) || !mFilmMode) { 326bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang b.mCurrentScale = getMinimalScale(b); 327d848862c1dd0689df8df5d684476cfd3897557d6Chih-Chung Chang b.mAnimationStartTime = NO_ANIMATION; 328d848862c1dd0689df8df5d684476cfd3897557d6Chih-Chung Chang } else { 329d848862c1dd0689df8df5d684476cfd3897557d6Chih-Chung Chang b.mCurrentScale *= ratio; 330d848862c1dd0689df8df5d684476cfd3897557d6Chih-Chung Chang b.mFromScale *= ratio; 331d848862c1dd0689df8df5d684476cfd3897557d6Chih-Chung Chang b.mToScale *= ratio; 332d848862c1dd0689df8df5d684476cfd3897557d6Chih-Chung Chang } 333676170e619ad59ea97d04e0edcd62b1500304845Chih-Chung Chang 334b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (i == 0) { 335b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mFocusX /= ratio; 336b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mFocusY /= ratio; 337ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang } 3382c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang 3392c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang return true; 340ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang } 341ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 342e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang private boolean startOpeningAnimationIfNeeded() { 343e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang if (mOpenAnimationRect == null) return false; 344b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Box b = mBoxes.get(0); 345e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang if (b.mUseViewSize) return false; 346b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 347b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Start animation from the saved rectangle if we have one. 348b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Rect r = mOpenAnimationRect; 349b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mOpenAnimationRect = null; 350f320b8429dd5c68c117b8e9b1a36a435f4f4ff13Yuli Huang 351bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mPlatform.mCurrentX = r.centerX() - mViewW / 2; 352bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang b.mCurrentY = r.centerY() - mViewH / 2; 353b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang b.mCurrentScale = Math.max(r.width() / (float) b.mImageW, 354b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang r.height() / (float) b.mImageH); 355bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang startAnimation(mPlatform.mDefaultX, 0, b.mScaleMin, 356bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang ANIM_KIND_OPENING); 357f320b8429dd5c68c117b8e9b1a36a435f4f4ff13Yuli Huang 358f320b8429dd5c68c117b8e9b1a36a435f4f4ff13Yuli Huang // Animate from large gaps for neighbor boxes to avoid them 359f320b8429dd5c68c117b8e9b1a36a435f4f4ff13Yuli Huang // shown on the screen during opening animation. 360f320b8429dd5c68c117b8e9b1a36a435f4f4ff13Yuli Huang for (int i = -1; i < 1; i++) { 361f320b8429dd5c68c117b8e9b1a36a435f4f4ff13Yuli Huang Gap g = mGaps.get(i); 362f320b8429dd5c68c117b8e9b1a36a435f4f4ff13Yuli Huang g.mCurrentGap = mViewW; 363f320b8429dd5c68c117b8e9b1a36a435f4f4ff13Yuli Huang g.doAnimation(g.mDefaultSize, ANIM_KIND_OPENING); 364f320b8429dd5c68c117b8e9b1a36a435f4f4ff13Yuli Huang } 365e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang 366e6251df06f0b3c8f556043f8b725b4b19be7474dChih-Chung Chang return true; 367ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang } 368ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 369b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void setFilmMode(boolean enabled) { 370b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (enabled == mFilmMode) return; 371b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mFilmMode = enabled; 372b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 373bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mPlatform.updateDefaultXY(); 374b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang updateScaleAndGapLimit(); 375b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang stopAnimation(); 376b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang snapAndRedraw(); 377ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang } 378ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 379b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void setExtraScalingRange(boolean enabled) { 380b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mExtraScalingRange == enabled) return; 381b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mExtraScalingRange = enabled; 382b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (!enabled) { 383b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang snapAndRedraw(); 384b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 385ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang } 386ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 387b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // This should be called whenever the scale range of boxes or the default 388b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // gap size may change. Currently this can happen due to change of view 389bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // size, image size, mFilmMode, mConstrained, and mConstrainedFrame. 390b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void updateScaleAndGapLimit() { 391b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = -BOX_MAX; i <= BOX_MAX; i++) { 392b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Box b = mBoxes.get(i); 393bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang b.mScaleMin = getMinimalScale(b); 394bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang b.mScaleMax = getMaximalScale(b); 395b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 396ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 397b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = -BOX_MAX; i < BOX_MAX; i++) { 398b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Gap g = mGaps.get(i); 399b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang g.mDefaultSize = getDefaultGapSize(i); 400b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 401b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 402676170e619ad59ea97d04e0edcd62b1500304845Chih-Chung Chang 403b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Returns the default gap size according the the size of the boxes around 404b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // the gap and the current mode. 405b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private int getDefaultGapSize(int i) { 406b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mFilmMode) return IMAGE_GAP; 407b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Box a = mBoxes.get(i); 408b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Box b = mBoxes.get(i + 1); 409b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return IMAGE_GAP + Math.max(gapToSide(a), gapToSide(b)); 410ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang } 411ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 412b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Here is how we layout the boxes in the page mode. 413b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // 414b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // previous current next 415b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // ___________ ________________ __________ 416b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // | _______ | | __________ | | ______ | 417b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // | | | | | | right->| | | | | | 418b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // | | |<-------->|<--left | | | | | | 419b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // | |_______| | | | |__________| | | |______| | 420b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // |___________| | |________________| |__________| 421b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // | <--> gapToSide() 422b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // | 423b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // IMAGE_GAP + MAX(gapToSide(previous), gapToSide(current)) 424b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private int gapToSide(Box b) { 425b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return (int) ((mViewW - getMinimalScale(b) * b.mImageW) / 2 + 0.5f); 426ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang } 427ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 428b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Stop all animations at where they are now. 429b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void stopAnimation() { 430b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPlatform.mAnimationStartTime = NO_ANIMATION; 431b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = -BOX_MAX; i <= BOX_MAX; i++) { 432b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mBoxes.get(i).mAnimationStartTime = NO_ANIMATION; 433b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 434b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = -BOX_MAX; i < BOX_MAX; i++) { 435b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mGaps.get(i).mAnimationStartTime = NO_ANIMATION; 436534b12fd804610dd67b8109bc08ba76f31afb33eChih-Chung Chang } 437534b12fd804610dd67b8109bc08ba76f31afb33eChih-Chung Chang } 438534b12fd804610dd67b8109bc08ba76f31afb33eChih-Chung Chang 439b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void skipAnimation() { 440b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mPlatform.mAnimationStartTime != NO_ANIMATION) { 441b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPlatform.mCurrentX = mPlatform.mToX; 442bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mPlatform.mCurrentY = mPlatform.mToY; 443b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPlatform.mAnimationStartTime = NO_ANIMATION; 444b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 445b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = -BOX_MAX; i <= BOX_MAX; i++) { 446b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Box b = mBoxes.get(i); 447b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (b.mAnimationStartTime == NO_ANIMATION) continue; 448b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang b.mCurrentY = b.mToY; 449b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang b.mCurrentScale = b.mToScale; 450b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang b.mAnimationStartTime = NO_ANIMATION; 451b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 452b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = -BOX_MAX; i < BOX_MAX; i++) { 453b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Gap g = mGaps.get(i); 454b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (g.mAnimationStartTime == NO_ANIMATION) continue; 455b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang g.mCurrentGap = g.mToGap; 456b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang g.mAnimationStartTime = NO_ANIMATION; 457b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 458b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang redraw(); 459ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang } 460ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 4612c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang public void snapback() { 462b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang snapAndRedraw(); 463ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang } 464ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 46542e1fed4edd9ed1e326aab2f7969242c56812952Chih-Chung Chang public void skipToFinalPosition() { 46642e1fed4edd9ed1e326aab2f7969242c56812952Chih-Chung Chang stopAnimation(); 46742e1fed4edd9ed1e326aab2f7969242c56812952Chih-Chung Chang snapAndRedraw(); 46842e1fed4edd9ed1e326aab2f7969242c56812952Chih-Chung Chang skipAnimation(); 46942e1fed4edd9ed1e326aab2f7969242c56812952Chih-Chung Chang } 47042e1fed4edd9ed1e326aab2f7969242c56812952Chih-Chung Chang 471b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 472b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Start an animations for the focused box 473b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 474b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 475b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void zoomIn(float tapX, float tapY, float targetScale) { 476bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang tapX -= mViewW / 2; 477bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang tapY -= mViewH / 2; 478b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Box b = mBoxes.get(0); 479b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 480b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Convert the tap position to distance to center in bitmap coordinates 481b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang float tempX = (tapX - mPlatform.mCurrentX) / b.mCurrentScale; 482b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang float tempY = (tapY - b.mCurrentY) / b.mCurrentScale; 483b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 484bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang int x = (int) (-tempX * targetScale + 0.5f); 485bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang int y = (int) (-tempY * targetScale + 0.5f); 486b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 487b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang calculateStableBound(targetScale); 488b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int targetX = Utils.clamp(x, mBoundLeft, mBoundRight); 489b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int targetY = Utils.clamp(y, mBoundTop, mBoundBottom); 490b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang targetScale = Utils.clamp(targetScale, b.mScaleMin, b.mScaleMax); 491b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 492b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang startAnimation(targetX, targetY, targetScale, ANIM_KIND_ZOOM); 493ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang } 494ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 495b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void resetToFullView() { 496b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Box b = mBoxes.get(0); 497bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang startAnimation(mPlatform.mDefaultX, 0, b.mScaleMin, ANIM_KIND_ZOOM); 498b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 499b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 500b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void beginScale(float focusX, float focusY) { 501bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang focusX -= mViewW / 2; 502bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang focusY -= mViewH / 2; 503b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Box b = mBoxes.get(0); 504b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Platform p = mPlatform; 505b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mInScale = true; 506b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mFocusX = (int) ((focusX - p.mCurrentX) / b.mCurrentScale + 0.5f); 507b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mFocusY = (int) ((focusY - b.mCurrentY) / b.mCurrentScale + 0.5f); 508b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 509b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 510b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Scales the image by the given factor. 511b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Returns an out-of-range indicator: 512b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // 1 if the intended scale is too large for the stable range. 513b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // 0 if the intended scale is in the stable range. 514b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // -1 if the intended scale is too small for the stable range. 515b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public int scaleBy(float s, float focusX, float focusY) { 516bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang focusX -= mViewW / 2; 517bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang focusY -= mViewH / 2; 518b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Box b = mBoxes.get(0); 519b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Platform p = mPlatform; 520b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 521b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // We want to keep the focus point (on the bitmap) the same as when we 5228b930828c7a33d668876972c22a515e9163592f7Pin Ting // begin the scale gesture, that is, 523b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // 524b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // (focusX' - currentX') / scale' = (focusX - currentX) / scale 525b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // 526192b7f1ddf08e7bfa0c65dbf61edb81ebb5a0998Chih-Chung Chang s = b.clampScale(s * getTargetScale(b)); 527b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int x = mFilmMode ? p.mCurrentX : (int) (focusX - s * mFocusX + 0.5f); 528b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int y = mFilmMode ? b.mCurrentY : (int) (focusY - s * mFocusY + 0.5f); 529b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang startAnimation(x, y, s, ANIM_KIND_SCALE); 530b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (s < b.mScaleMin) return -1; 531b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (s > b.mScaleMax) return 1; 532b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return 0; 533b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 534b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 535b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public void endScale() { 536b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mInScale = false; 537b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang snapAndRedraw(); 538ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang } 539ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 5402c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // Slide the focused box to the center of the view. 5412c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang public void startHorizontalSlide() { 542b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Box b = mBoxes.get(0); 543bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang startAnimation(mPlatform.mDefaultX, 0, b.mScaleMin, ANIM_KIND_SLIDE); 5442c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 5452c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang 5462c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // Slide the focused box to the center of the view with the capture 5472c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // animation. In addition to the sliding, the animation will also scale the 5482c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // the focused box, the specified neighbor box, and the gap between the 5492c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang // two. The specified offset should be 1 or -1. 5502c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang public void startCaptureAnimationSlide(int offset) { 5512c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang Box b = mBoxes.get(0); 5522c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang Box n = mBoxes.get(offset); // the neighbor box 5532c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang Gap g = mGaps.get(offset); // the gap between the two boxes 5542c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang 555bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mPlatform.doAnimation(mPlatform.mDefaultX, mPlatform.mDefaultY, 556bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang ANIM_KIND_CAPTURE); 557bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang b.doAnimation(0, b.mScaleMin, ANIM_KIND_CAPTURE); 558bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang n.doAnimation(0, n.mScaleMin, ANIM_KIND_CAPTURE); 5592c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang g.doAnimation(g.mDefaultSize, ANIM_KIND_CAPTURE); 5602c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang redraw(); 561ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang } 562ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 5636b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // Only allow scrolling when we are not currently in an animation or we 5646b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // are in some animation with can be interrupted. 5656b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private boolean canScroll() { 566b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Box b = mBoxes.get(0); 5676b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (b.mAnimationStartTime == NO_ANIMATION) return true; 5686b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang switch (b.mAnimationKind) { 5696b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang case ANIM_KIND_SCROLL: 5706b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang case ANIM_KIND_FLING: 5716b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang case ANIM_KIND_FLING_X: 5726b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang return true; 573b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 5746b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang return false; 575676170e619ad59ea97d04e0edcd62b1500304845Chih-Chung Chang } 576676170e619ad59ea97d04e0edcd62b1500304845Chih-Chung Chang 5776b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public void scrollPage(int dx, int dy) { 5786b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (!canScroll()) return; 5796b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 580b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Box b = mBoxes.get(0); 5816b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang Platform p = mPlatform; 582532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 583b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang calculateStableBound(b.mCurrentScale); 584532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 5856b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int x = p.mCurrentX + dx; 5866b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int y = b.mCurrentY + dy; 5876b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 588532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang // Vertical direction: If we have space to move in the vertical 589532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang // direction, we show the edge effect when scrolling reaches the edge. 590532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang if (mBoundTop != mBoundBottom) { 591532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang if (y < mBoundTop) { 592b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mListener.onPull(mBoundTop - y, EdgeView.BOTTOM); 593532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang } else if (y > mBoundBottom) { 594b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mListener.onPull(y - mBoundBottom, EdgeView.TOP); 595532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang } 596532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang } 597532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 598532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang y = Utils.clamp(y, mBoundTop, mBoundBottom); 599532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 600532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang // Horizontal direction: we show the edge effect when the scrolling 601532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang // tries to go left of the first image or go right of the last image. 602fb1a15559bb2a0a1c8a41efd3e0420a2a2d70590Chih-Chung Chang if (!mHasPrev && x > mBoundRight) { 603b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int pixels = x - mBoundRight; 604b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mListener.onPull(pixels, EdgeView.LEFT); 605532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang x = mBoundRight; 606fb1a15559bb2a0a1c8a41efd3e0420a2a2d70590Chih-Chung Chang } else if (!mHasNext && x < mBoundLeft) { 607b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int pixels = mBoundLeft - x; 608b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mListener.onPull(pixels, EdgeView.RIGHT); 609b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang x = mBoundLeft; 610b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 611b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 612b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang startAnimation(x, y, b.mCurrentScale, ANIM_KIND_SCROLL); 613b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 614b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 6156b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public void scrollFilmX(int dx) { 6166b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (!canScroll()) return; 6176b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 618b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Box b = mBoxes.get(0); 6196b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang Platform p = mPlatform; 6206b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 6216b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // Only allow scrolling when we are not currently in an animation or we 6226b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // are in some animation with can be interrupted. 6236b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (b.mAnimationStartTime != NO_ANIMATION) { 6246b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang switch (b.mAnimationKind) { 6256b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang case ANIM_KIND_SCROLL: 6266b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang case ANIM_KIND_FLING: 6276b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang case ANIM_KIND_FLING_X: 6286b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang break; 6296b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang default: 6306b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang return; 6316b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 6326b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 6336b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 6346b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int x = p.mCurrentX + dx; 635b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 636b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Horizontal direction: we show the edge effect when the scrolling 637b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // tries to go left of the first image or go right of the last image. 638bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang x -= mPlatform.mDefaultX; 639bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (!mHasPrev && x > 0) { 640bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mListener.onPull(x, EdgeView.LEFT); 641bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang x = 0; 642bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } else if (!mHasNext && x < 0) { 643bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mListener.onPull(-x, EdgeView.RIGHT); 644bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang x = 0; 645532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang } 646bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang x += mPlatform.mDefaultX; 6476b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang startAnimation(x, b.mCurrentY, b.mCurrentScale, ANIM_KIND_SCROLL); 648532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang } 649532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 6506b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public void scrollFilmY(int boxIndex, int dy) { 6516b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (!canScroll()) return; 6526b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 6536b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang Box b = mBoxes.get(boxIndex); 6546b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int y = b.mCurrentY + dy; 6556b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang b.doAnimation(y, b.mCurrentScale, ANIM_KIND_SCROLL); 6566b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang redraw(); 657b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 658b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 6596b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public boolean flingPage(int velocityX, int velocityY) { 660b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Box b = mBoxes.get(0); 661b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Platform p = mPlatform; 662b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 663b3aab90bb37aa9cc60be32e05678ee55d6575ee8Chih-Chung Chang // We only want to do fling when the picture is zoomed-in. 664b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (viewWiderThanScaledImage(b.mCurrentScale) && 665b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang viewTallerThanScaledImage(b.mCurrentScale)) { 6662ce3c3bfe08fff5aee58007cc8ba8f4a50861ae2Yuli Huang return false; 6672ce3c3bfe08fff5aee58007cc8ba8f4a50861ae2Yuli Huang } 6682ce3c3bfe08fff5aee58007cc8ba8f4a50861ae2Yuli Huang 6692ce3c3bfe08fff5aee58007cc8ba8f4a50861ae2Yuli Huang // We only allow flinging in the directions where it won't go over the 6702ce3c3bfe08fff5aee58007cc8ba8f4a50861ae2Yuli Huang // picture. 6712ce3c3bfe08fff5aee58007cc8ba8f4a50861ae2Yuli Huang int edges = getImageAtEdges(); 6722ce3c3bfe08fff5aee58007cc8ba8f4a50861ae2Yuli Huang if ((velocityX > 0 && (edges & IMAGE_AT_LEFT_EDGE) != 0) || 6732ce3c3bfe08fff5aee58007cc8ba8f4a50861ae2Yuli Huang (velocityX < 0 && (edges & IMAGE_AT_RIGHT_EDGE) != 0)) { 6742ce3c3bfe08fff5aee58007cc8ba8f4a50861ae2Yuli Huang velocityX = 0; 6752ce3c3bfe08fff5aee58007cc8ba8f4a50861ae2Yuli Huang } 6762ce3c3bfe08fff5aee58007cc8ba8f4a50861ae2Yuli Huang if ((velocityY > 0 && (edges & IMAGE_AT_TOP_EDGE) != 0) || 6772ce3c3bfe08fff5aee58007cc8ba8f4a50861ae2Yuli Huang (velocityY < 0 && (edges & IMAGE_AT_BOTTOM_EDGE) != 0)) { 6782ce3c3bfe08fff5aee58007cc8ba8f4a50861ae2Yuli Huang velocityY = 0; 6792ce3c3bfe08fff5aee58007cc8ba8f4a50861ae2Yuli Huang } 680b3aab90bb37aa9cc60be32e05678ee55d6575ee8Chih-Chung Chang 681b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (velocityX == 0 && velocityY == 0) return false; 682b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 683b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPageScroller.fling(p.mCurrentX, b.mCurrentY, velocityX, velocityY, 684b3aab90bb37aa9cc60be32e05678ee55d6575ee8Chih-Chung Chang mBoundLeft, mBoundRight, mBoundTop, mBoundBottom); 685b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int targetX = mPageScroller.getFinalX(); 686b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int targetY = mPageScroller.getFinalY(); 687b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang ANIM_TIME[ANIM_KIND_FLING] = mPageScroller.getDuration(); 6886b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang return startAnimation(targetX, targetY, b.mCurrentScale, ANIM_KIND_FLING); 689b3aab90bb37aa9cc60be32e05678ee55d6575ee8Chih-Chung Chang } 690b3aab90bb37aa9cc60be32e05678ee55d6575ee8Chih-Chung Chang 6916b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public boolean flingFilmX(int velocityX) { 6926b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (velocityX == 0) return false; 6936b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 694b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Box b = mBoxes.get(0); 695b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Platform p = mPlatform; 696b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 697b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // If we are already at the edge, don't start the fling. 698bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang int defaultX = p.mDefaultX; 699bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if ((!mHasPrev && p.mCurrentX >= defaultX) 700bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang || (!mHasNext && p.mCurrentX <= defaultX)) { 701b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return false; 7026068de20f4f19ca82ca01bef3b6dda796a79f724Yuli Huang } 703ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 704b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mFilmScroller.fling(p.mCurrentX, 0, velocityX, 0, 705b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Integer.MIN_VALUE, Integer.MAX_VALUE, 0, 0); 706b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int targetX = mFilmScroller.getFinalX(); 7076b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang return startAnimation( 7086b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang targetX, b.mCurrentY, b.mCurrentScale, ANIM_KIND_FLING_X); 7096b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 7106b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 7116b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // Moves the specified box out of screen. If velocityY is 0, a default 7126b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // velocity is used. Returns the time for the duration, or -1 if we cannot 7136b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // not do the animation. 7146b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public int flingFilmY(int boxIndex, int velocityY) { 7156b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang Box b = mBoxes.get(boxIndex); 7166b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 7176b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // Calculate targetY 7186b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int h = heightOf(b); 7196b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int targetY; 7206b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int FUZZY = 3; // TODO: figure out why this is needed. 7216b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (velocityY < 0 || (velocityY == 0 && b.mCurrentY <= 0)) { 7226b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang targetY = -mViewH / 2 - (h + 1) / 2 - FUZZY; 7236b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } else { 7246b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang targetY = (mViewH + 1) / 2 + h / 2 + FUZZY; 7256b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 7266b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 7276b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // Calculate duration 7286b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int duration; 7296b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (velocityY != 0) { 7306b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang duration = (int) (Math.abs(targetY - b.mCurrentY) * 1000f 7316b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang / Math.abs(velocityY)); 7326b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang duration = Math.min(MAX_DELETE_ANIMATION_DURATION, duration); 7336b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } else { 7346b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang duration = DEFAULT_DELETE_ANIMATION_DURATION; 7356b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 7366b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 7376b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // Start animation 7386b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang ANIM_TIME[ANIM_KIND_DELETE] = duration; 7396b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (b.doAnimation(targetY, b.mCurrentScale, ANIM_KIND_DELETE)) { 7406b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang redraw(); 7416b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang return duration; 7426b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 7436b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang return -1; 7446b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 7456b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 7466b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // Returns the index of the box which contains the given point (x, y) 7476b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // Returns Integer.MAX_VALUE if there is no hit. There may be more than 7486b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // one box contains the given point, and we want to give priority to the 7496b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // one closer to the focused index (0). 7506b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public int hitTest(int x, int y) { 7516b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang for (int i = 0; i < 2 * BOX_MAX + 1; i++) { 7526b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int j = CENTER_OUT_INDEX[i]; 7536b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang Rect r = mRects.get(j); 7546b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (r.contains(x, y)) { 7556b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang return j; 7566b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 7576b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 7586b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 7596b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang return Integer.MAX_VALUE; 760b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 761ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 762b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 763b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Redraw 764b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // 765b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // If a method changes box positions directly, redraw() 766b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // should be called. 767b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // 768b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // If a method may also cause a snapback to happen, snapAndRedraw() should 769b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // be called. 770b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // 771b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // If a method starts an animation to change the position of focused box, 772b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // startAnimation() should be called. 773b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // 774b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // If time advances to change the box position, advanceAnimation() should 775b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // be called. 776b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 777b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void redraw() { 778b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang layoutAndSetPosition(); 779b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mListener.invalidate(); 780b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 781b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 782b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void snapAndRedraw() { 783b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPlatform.startSnapback(); 784b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = -BOX_MAX; i <= BOX_MAX; i++) { 785b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mBoxes.get(i).startSnapback(); 786b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 787b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = -BOX_MAX; i < BOX_MAX; i++) { 788b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mGaps.get(i).startSnapback(); 789ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang } 790ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang mFilmRatio.startSnapback(); 791b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang redraw(); 792b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 793ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 7946b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private boolean startAnimation(int targetX, int targetY, float targetScale, 795b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int kind) { 796b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang boolean changed = false; 797bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang changed |= mPlatform.doAnimation(targetX, mPlatform.mDefaultY, kind); 798b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang changed |= mBoxes.get(0).doAnimation(targetY, targetScale, kind); 799b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (changed) redraw(); 8006b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang return changed; 801b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 802b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 803b8be1e0ad76b6abc0da7ead39f7a9811195d001eChih-Chung Chang public void advanceAnimation() { 804b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang boolean changed = false; 805b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang changed |= mPlatform.advanceAnimation(); 806b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = -BOX_MAX; i <= BOX_MAX; i++) { 807b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang changed |= mBoxes.get(i).advanceAnimation(); 808b3aab90bb37aa9cc60be32e05678ee55d6575ee8Chih-Chung Chang } 809b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = -BOX_MAX; i < BOX_MAX; i++) { 810b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang changed |= mGaps.get(i).advanceAnimation(); 811b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 812ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang changed |= mFilmRatio.advanceAnimation(); 813b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (changed) redraw(); 814ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang } 815ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 816f320b8429dd5c68c117b8e9b1a36a435f4f4ff13Yuli Huang public boolean inOpeningAnimation() { 817f320b8429dd5c68c117b8e9b1a36a435f4f4ff13Yuli Huang return (mPlatform.mAnimationKind == ANIM_KIND_OPENING && 818f320b8429dd5c68c117b8e9b1a36a435f4f4ff13Yuli Huang mPlatform.mAnimationStartTime != NO_ANIMATION) || 819f320b8429dd5c68c117b8e9b1a36a435f4f4ff13Yuli Huang (mBoxes.get(0).mAnimationKind == ANIM_KIND_OPENING && 820f320b8429dd5c68c117b8e9b1a36a435f4f4ff13Yuli Huang mBoxes.get(0).mAnimationStartTime != NO_ANIMATION); 821f320b8429dd5c68c117b8e9b1a36a435f4f4ff13Yuli Huang } 822f320b8429dd5c68c117b8e9b1a36a435f4f4ff13Yuli Huang 823b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 824b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Layout 825b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 826b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 827b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Returns the display width of this box. 828b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private int widthOf(Box b) { 829b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return (int) (b.mImageW * b.mCurrentScale + 0.5f); 830b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 831b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 832b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Returns the display height of this box. 833b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private int heightOf(Box b) { 834b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return (int) (b.mImageH * b.mCurrentScale + 0.5f); 835b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 836b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 837b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Returns the display width of this box, using the given scale. 838b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private int widthOf(Box b, float scale) { 839b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return (int) (b.mImageW * scale + 0.5f); 840b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 841b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 842b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Returns the display height of this box, using the given scale. 843b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private int heightOf(Box b, float scale) { 844b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return (int) (b.mImageH * scale + 0.5f); 845b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 846b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 847b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Convert the information in mPlatform and mBoxes to mRects, so the user 848b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // can get the position of each box by getPosition(). 849b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // 8506b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // Note we go from center-out because each box's X coordinate 851b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // is relative to its anchor box (except the focused box). 852b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void layoutAndSetPosition() { 8536b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang for (int i = 0; i < 2 * BOX_MAX + 1; i++) { 8546b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang convertBoxToRect(CENTER_OUT_INDEX[i]); 855ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang } 856b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //dumpState(); 857b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 858ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 85928cb4161da5fc3756933ca67d509b8af1c6275f1Owen Lin @SuppressWarnings("unused") 860b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void dumpState() { 861b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = -BOX_MAX; i < BOX_MAX; i++) { 862b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Log.d(TAG, "Gap " + i + ": " + mGaps.get(i).mCurrentGap); 863ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang } 864ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 8656b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang for (int i = 0; i < 2 * BOX_MAX + 1; i++) { 8666b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang dumpRect(CENTER_OUT_INDEX[i]); 867b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 868b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 869b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = -BOX_MAX; i <= BOX_MAX; i++) { 870b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int j = i + 1; j <= BOX_MAX; j++) { 871b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (Rect.intersects(mRects.get(i), mRects.get(j))) { 872b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Log.d(TAG, "rect " + i + " and rect " + j + "intersects!"); 873b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 874ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang } 875b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 876b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 877b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 878b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void dumpRect(int i) { 879b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang StringBuilder sb = new StringBuilder(); 880b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Rect r = mRects.get(i); 881b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang sb.append("Rect " + i + ":"); 882b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang sb.append("("); 883b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang sb.append(r.centerX()); 884b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang sb.append(","); 885b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang sb.append(r.centerY()); 886b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang sb.append(") ["); 887b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang sb.append(r.width()); 888b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang sb.append("x"); 889b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang sb.append(r.height()); 890b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang sb.append("]"); 891b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Log.d(TAG, sb.toString()); 892b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 893b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 894b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void convertBoxToRect(int i) { 895b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Box b = mBoxes.get(i); 896b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Rect r = mRects.get(i); 897bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang int y = b.mCurrentY + mPlatform.mCurrentY + mViewH / 2; 898b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int w = widthOf(b); 899b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int h = heightOf(b); 900b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (i == 0) { 901bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang int x = mPlatform.mCurrentX + mViewW / 2; 902b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang r.left = x - w / 2; 903b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang r.right = r.left + w; 904b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } else if (i > 0) { 905b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Rect a = mRects.get(i - 1); 906b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Gap g = mGaps.get(i - 1); 907b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang r.left = a.right + g.mCurrentGap; 908b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang r.right = r.left + w; 909b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } else { // i < 0 910b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Rect a = mRects.get(i + 1); 911b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Gap g = mGaps.get(i); 912b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang r.right = a.left - g.mCurrentGap; 913b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang r.left = r.right - w; 914b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 915b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang r.top = y - h / 2; 916b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang r.bottom = r.top + h; 917b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 918b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 919b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Returns the position of a box. 920b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public Rect getPosition(int index) { 921b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return mRects.get(index); 922b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 923b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 924b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 925b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Box management 926b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 927b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 928b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Initialize the platform to be at the view center. 929b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void initPlatform() { 930bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mPlatform.updateDefaultXY(); 931bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mPlatform.mCurrentX = mPlatform.mDefaultX; 932bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mPlatform.mCurrentY = mPlatform.mDefaultY; 933b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPlatform.mAnimationStartTime = NO_ANIMATION; 934b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 935b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 936b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Initialize a box to have the size of the view. 937b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void initBox(int index) { 938b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Box b = mBoxes.get(index); 939b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang b.mImageW = mViewW; 940b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang b.mImageH = mViewH; 941b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang b.mUseViewSize = true; 942bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang b.mScaleMin = getMinimalScale(b); 943bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang b.mScaleMax = getMaximalScale(b); 944bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang b.mCurrentY = 0; 945b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang b.mCurrentScale = b.mScaleMin; 946b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang b.mAnimationStartTime = NO_ANIMATION; 9476b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang b.mAnimationKind = ANIM_KIND_NONE; 9486b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 9496b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 9506b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // Initialize a box to a given size. 9516b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang private void initBox(int index, Size size) { 9526b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (size.width == 0 || size.height == 0) { 9536b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang initBox(index); 9546b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang return; 9556b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 9566b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang Box b = mBoxes.get(index); 9576b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang b.mImageW = size.width; 9586b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang b.mImageH = size.height; 9596b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang b.mUseViewSize = false; 9606b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang b.mScaleMin = getMinimalScale(b); 9616b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang b.mScaleMax = getMaximalScale(b); 9626b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang b.mCurrentY = 0; 9636b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang b.mCurrentScale = b.mScaleMin; 9646b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang b.mAnimationStartTime = NO_ANIMATION; 9656b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang b.mAnimationKind = ANIM_KIND_NONE; 966b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 967b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 968b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Initialize a gap. This can only be called after the boxes around the gap 969b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // has been initialized. 970b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void initGap(int index) { 971b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Gap g = mGaps.get(index); 972b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang g.mDefaultSize = getDefaultGapSize(index); 973b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang g.mCurrentGap = g.mDefaultSize; 974b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang g.mAnimationStartTime = NO_ANIMATION; 975b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 976b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 977b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void initGap(int index, int size) { 978b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Gap g = mGaps.get(index); 979b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang g.mDefaultSize = getDefaultGapSize(index); 980b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang g.mCurrentGap = size; 981b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang g.mAnimationStartTime = NO_ANIMATION; 982b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 983b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 98428cb4161da5fc3756933ca67d509b8af1c6275f1Owen Lin @SuppressWarnings("unused") 985b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void debugMoveBox(int fromIndex[]) { 986b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang StringBuilder s = new StringBuilder("moveBox:"); 987b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = 0; i < fromIndex.length; i++) { 988b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int j = fromIndex[i]; 989b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (j == Integer.MAX_VALUE) { 990b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang s.append(" N"); 991b3aab90bb37aa9cc60be32e05678ee55d6575ee8Chih-Chung Chang } else { 992b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang s.append(" "); 993b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang s.append(fromIndex[i]); 994b3aab90bb37aa9cc60be32e05678ee55d6575ee8Chih-Chung Chang } 995ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang } 996b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Log.d(TAG, s.toString()); 9976068de20f4f19ca82ca01bef3b6dda796a79f724Yuli Huang } 9986068de20f4f19ca82ca01bef3b6dda796a79f724Yuli Huang 999b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Move the boxes: it may indicate focus change, box deleted, box appearing, 1000b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // box reordered, etc. 1001b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // 1002b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Each element in the fromIndex array indicates where each box was in the 1003b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // old array. If the value is Integer.MAX_VALUE (pictured as N below), it 1004b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // means the box is new. 1005b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // 1006b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // For example: 1007b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // N N N N N N N -- all new boxes 1008b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // -3 -2 -1 0 1 2 3 -- nothing changed 1009b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // -2 -1 0 1 2 3 N -- focus goes to the next box 10108b930828c7a33d668876972c22a515e9163592f7Pin Ting // N -3 -2 -1 0 1 2 -- focus goes to the previous box 1011b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // -3 -2 -1 1 2 3 N -- the focused box was deleted. 1012bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // 1013bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // hasPrev/hasNext indicates if there are previous/next boxes for the 1014bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // focused box. constrained indicates whether the focused box should be put 1015bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // into the constrained frame. 1016bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public void moveBox(int fromIndex[], boolean hasPrev, boolean hasNext, 10176b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang boolean constrained, Size[] sizes) { 1018b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //debugMoveBox(fromIndex); 1019fb1a15559bb2a0a1c8a41efd3e0420a2a2d70590Chih-Chung Chang mHasPrev = hasPrev; 1020fb1a15559bb2a0a1c8a41efd3e0420a2a2d70590Chih-Chung Chang mHasNext = hasNext; 1021bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 1022b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang RangeIntArray from = new RangeIntArray(fromIndex, -BOX_MAX, BOX_MAX); 1023b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 10248b930828c7a33d668876972c22a515e9163592f7Pin Ting // 1. Get the absolute X coordinates for the boxes. 1025b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang layoutAndSetPosition(); 1026b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = -BOX_MAX; i <= BOX_MAX; i++) { 1027b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Box b = mBoxes.get(i); 1028b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Rect r = mRects.get(i); 1029bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang b.mAbsoluteX = r.centerX() - mViewW / 2; 1030ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang } 1031ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 1032b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // 2. copy boxes and gaps to temporary storage. 1033b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = -BOX_MAX; i <= BOX_MAX; i++) { 1034b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mTempBoxes.put(i, mBoxes.get(i)); 1035b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mBoxes.put(i, null); 1036b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1037b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = -BOX_MAX; i < BOX_MAX; i++) { 1038b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mTempGaps.put(i, mGaps.get(i)); 1039b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mGaps.put(i, null); 1040b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1041b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1042b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // 3. move back boxes that are used in the new array. 1043b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = -BOX_MAX; i <= BOX_MAX; i++) { 1044b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int j = from.get(i); 1045b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (j == Integer.MAX_VALUE) continue; 1046b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mBoxes.put(i, mTempBoxes.get(j)); 1047b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mTempBoxes.put(j, null); 1048b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1049ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 1050b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // 4. move back gaps if both boxes around it are kept together. 1051b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = -BOX_MAX; i < BOX_MAX; i++) { 1052b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int j = from.get(i); 1053b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (j == Integer.MAX_VALUE) continue; 1054b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int k = from.get(i + 1); 1055b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (k == Integer.MAX_VALUE) continue; 1056b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (j + 1 == k) { 1057b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mGaps.put(i, mTempGaps.get(j)); 1058b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mTempGaps.put(j, null); 1059b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1060b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1061534b12fd804610dd67b8109bc08ba76f31afb33eChih-Chung Chang 1062b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // 5. recycle the boxes that are not used in the new array. 1063b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int k = -BOX_MAX; 1064b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = -BOX_MAX; i <= BOX_MAX; i++) { 1065b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mBoxes.get(i) != null) continue; 1066b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang while (mTempBoxes.get(k) == null) { 1067b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang k++; 1068b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1069b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mBoxes.put(i, mTempBoxes.get(k++)); 10706b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang initBox(i, sizes[i + BOX_MAX]); 1071ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang } 1072ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 1073b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // 6. Now give the recycled box a reasonable absolute X position. 1074b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // 1075b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // First try to find the first and the last box which the absolute X 1076b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // position is known. 1077b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int first, last; 1078b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (first = -BOX_MAX; first <= BOX_MAX; first++) { 1079b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (from.get(first) != Integer.MAX_VALUE) break; 1080b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1081b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (last = BOX_MAX; last >= -BOX_MAX; last--) { 1082b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (from.get(last) != Integer.MAX_VALUE) break; 1083b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1084b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // If there is no box has known X position at all, make the focused one 1085b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // as known. 1086b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (first > BOX_MAX) { 1087b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mBoxes.get(0).mAbsoluteX = mPlatform.mCurrentX; 1088b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang first = last = 0; 1089b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 10906b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // Now for those boxes between first and last, assign their position to 10916b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // align to the previous box or the next box with known position. For 10926b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // the boxes before first or after last, we will use a new default gap 10936b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // size below. 10946b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 10956b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // Align to the previous box 10966b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang for (int i = Math.max(0, first + 1); i < last; i++) { 1097b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (from.get(i) != Integer.MAX_VALUE) continue; 10986b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang Box a = mBoxes.get(i - 1); 10996b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang Box b = mBoxes.get(i); 11006b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int wa = widthOf(a); 11016b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int wb = widthOf(b); 11026b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang b.mAbsoluteX = a.mAbsoluteX + (wa - wa / 2) + wb / 2 11036b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang + getDefaultGapSize(i); 11046b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (mPopFromTop) { 11056b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang b.mCurrentY = -(mViewH / 2 + heightOf(b) / 2); 11066b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } else { 11076b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang b.mCurrentY = (mViewH / 2 + heightOf(b) / 2); 11086b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 11096b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 11106b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 11116b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang // Align to the next box 11126b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang for (int i = Math.min(-1, last - 1); i > first; i--) { 11136b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (from.get(i) != Integer.MAX_VALUE) continue; 11146b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang Box a = mBoxes.get(i + 1); 11156b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang Box b = mBoxes.get(i); 11166b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int wa = widthOf(a); 11176b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang int wb = widthOf(b); 11186b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang b.mAbsoluteX = a.mAbsoluteX - wa / 2 - (wb - wb / 2) 11196b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang - getDefaultGapSize(i); 11206b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (mPopFromTop) { 11216b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang b.mCurrentY = -(mViewH / 2 + heightOf(b) / 2); 11226b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } else { 11236b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang b.mCurrentY = (mViewH / 2 + heightOf(b) / 2); 11246b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 1125b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1126ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 1127b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // 7. recycle the gaps that are not used in the new array. 1128b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang k = -BOX_MAX; 1129b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang for (int i = -BOX_MAX; i < BOX_MAX; i++) { 1130b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mGaps.get(i) != null) continue; 1131b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang while (mTempGaps.get(k) == null) { 1132b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang k++; 1133b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1134b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mGaps.put(i, mTempGaps.get(k++)); 1135b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Box a = mBoxes.get(i); 1136b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Box b = mBoxes.get(i + 1); 1137b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int wa = widthOf(a); 1138b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int wb = widthOf(b); 1139b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (i >= first && i < last) { 1140b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int g = b.mAbsoluteX - a.mAbsoluteX - wb / 2 - (wa - wa / 2); 1141b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang initGap(i, g); 1142b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } else { 1143b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang initGap(i); 1144b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1145ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang } 1146ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 1147c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang // 8. calculate the new absolute X coordinates for those box before 1148c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang // first or after last. 1149c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang for (int i = first - 1; i >= -BOX_MAX; i--) { 1150c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang Box a = mBoxes.get(i + 1); 1151c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang Box b = mBoxes.get(i); 1152c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang int wa = widthOf(a); 1153c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang int wb = widthOf(b); 1154c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang Gap g = mGaps.get(i); 1155c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang b.mAbsoluteX = a.mAbsoluteX - wa / 2 - (wb - wb / 2) - g.mCurrentGap; 1156c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang } 1157c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang 1158c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang for (int i = last + 1; i <= BOX_MAX; i++) { 1159c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang Box a = mBoxes.get(i - 1); 1160c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang Box b = mBoxes.get(i); 1161c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang int wa = widthOf(a); 1162c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang int wb = widthOf(b); 1163c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang Gap g = mGaps.get(i - 1); 1164c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang b.mAbsoluteX = a.mAbsoluteX + (wa - wa / 2) + wb / 2 + g.mCurrentGap; 1165c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang } 1166c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang 1167c4791b7721a8417be5be33a67c8ade6e82b03a2cChih-Chung Chang // 9. offset the Platform position 1168b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int dx = mBoxes.get(0).mAbsoluteX - mPlatform.mCurrentX; 1169b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPlatform.mCurrentX += dx; 1170b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPlatform.mFromX += dx; 1171b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPlatform.mToX += dx; 1172b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPlatform.mFlingOffset += dx; 1173b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1174bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (mConstrained != constrained) { 1175bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mConstrained = constrained; 1176bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mPlatform.updateDefaultXY(); 1177bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang updateScaleAndGapLimit(); 1178bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 1179bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 1180b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang snapAndRedraw(); 1181b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1182b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1183b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1184b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Public utilities 1185b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1186b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1187b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public boolean isAtMinimalScale() { 1188b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Box b = mBoxes.get(0); 1189b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return isAlmostEqual(b.mCurrentScale, b.mScaleMin); 1190b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1191b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1192bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public boolean isCenter() { 1193bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang Box b = mBoxes.get(0); 1194bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang return mPlatform.mCurrentX == mPlatform.mDefaultX 1195bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang && b.mCurrentY == 0; 1196bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 1197bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 1198b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public int getImageWidth() { 1199b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Box b = mBoxes.get(0); 1200b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return b.mImageW; 1201b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1202b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1203b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public int getImageHeight() { 1204b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Box b = mBoxes.get(0); 1205b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return b.mImageH; 1206b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1207b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1208b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public float getImageScale() { 1209b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Box b = mBoxes.get(0); 1210b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return b.mCurrentScale; 1211b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1212b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1213b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public int getImageAtEdges() { 1214b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Box b = mBoxes.get(0); 1215b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Platform p = mPlatform; 1216b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang calculateStableBound(b.mCurrentScale); 1217b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int edges = 0; 1218b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (p.mCurrentX <= mBoundLeft) { 1219b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang edges |= IMAGE_AT_RIGHT_EDGE; 1220ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang } 1221b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (p.mCurrentX >= mBoundRight) { 1222b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang edges |= IMAGE_AT_LEFT_EDGE; 1223b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1224b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (b.mCurrentY <= mBoundTop) { 1225b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang edges |= IMAGE_AT_BOTTOM_EDGE; 1226b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1227b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (b.mCurrentY >= mBoundBottom) { 1228b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang edges |= IMAGE_AT_TOP_EDGE; 1229b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1230b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return edges; 1231b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1232b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 123317ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang public boolean isScrolling() { 123417ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang return mPlatform.mAnimationStartTime != NO_ANIMATION 123517ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang && mPlatform.mCurrentX != mPlatform.mToX; 123617ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang } 123717ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang 123817ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang public void stopScrolling() { 123917ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang if (mPlatform.mAnimationStartTime == NO_ANIMATION) return; 124095c2aeab0bf398b45d8a9c562fd110d1e3756139Angus Kong if (mFilmMode) mFilmScroller.forceFinished(true); 124117ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang mPlatform.mFromX = mPlatform.mToX = mPlatform.mCurrentX; 124217ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang } 124317ffedda6e3ed57b38afbb775594cf30d83fc652Chih-Chung Chang 1244ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang public float getFilmRatio() { 1245ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang return mFilmRatio.mCurrentRatio; 1246ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang } 1247ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang 12486b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public void setPopFromTop(boolean top) { 12496b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang mPopFromTop = top; 12506b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 12516b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 12526b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang public boolean hasDeletingBox() { 12536b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang for(int i = -BOX_MAX; i <= BOX_MAX; i++) { 12546b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (mBoxes.get(i).mAnimationKind == ANIM_KIND_DELETE) { 12556b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang return true; 12566b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 12576b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 12586b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang return false; 12596b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } 12606b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang 1261b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1262b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Private utilities 1263b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1264b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1265b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private float getMinimalScale(Box b) { 1266bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang float wFactor = 1.0f; 1267bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang float hFactor = 1.0f; 1268bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang int viewW, viewH; 1269bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 1270b56ff734d0117cd5813cd2328edc57c4630ff1c3Chih-Chung Chang if (!mFilmMode && mConstrained && !mConstrainedFrame.isEmpty() 1271b56ff734d0117cd5813cd2328edc57c4630ff1c3Chih-Chung Chang && b == mBoxes.get(0)) { 1272bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang viewW = mConstrainedFrame.width(); 1273bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang viewH = mConstrainedFrame.height(); 1274bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } else { 1275bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang viewW = mViewW; 1276bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang viewH = mViewH; 1277bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 1278bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 1279bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (mFilmMode) { 1280bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (mViewH > mViewW) { // portrait 1281bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang wFactor = FILM_MODE_PORTRAIT_WIDTH; 1282bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang hFactor = FILM_MODE_PORTRAIT_HEIGHT; 1283bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } else { // landscape 1284bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang wFactor = FILM_MODE_LANDSCAPE_WIDTH; 1285bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang hFactor = FILM_MODE_LANDSCAPE_HEIGHT; 1286bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 1287bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 1288bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 1289bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang float s = Math.min(wFactor * viewW / b.mImageW, 1290bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang hFactor * viewH / b.mImageH); 1291bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang return Math.min(SCALE_LIMIT, s); 1292b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1293ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 1294bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private float getMaximalScale(Box b) { 1295ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang if (mFilmMode) return getMinimalScale(b); 1296ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang if (mConstrained && !mConstrainedFrame.isEmpty()) return getMinimalScale(b); 1297ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang return SCALE_LIMIT; 1298b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1299b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1300b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static boolean isAlmostEqual(float a, float b) { 1301b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang float diff = a - b; 1302b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return (diff < 0 ? -diff : diff) < 0.02f; 1303ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang } 1304ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 1305bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // Calculates the stable region of mPlatform.mCurrentX and 1306bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // mBoxes.get(0).mCurrentY, where "stable" means 1307b3aab90bb37aa9cc60be32e05678ee55d6575ee8Chih-Chung Chang // 1308b3aab90bb37aa9cc60be32e05678ee55d6575ee8Chih-Chung Chang // (1) If the dimension of scaled image >= view dimension, we will not 1309b3aab90bb37aa9cc60be32e05678ee55d6575ee8Chih-Chung Chang // see black region outside the image (at that dimension). 1310b3aab90bb37aa9cc60be32e05678ee55d6575ee8Chih-Chung Chang // (2) If the dimension of scaled image < view dimension, we will center 1311b3aab90bb37aa9cc60be32e05678ee55d6575ee8Chih-Chung Chang // the scaled image. 1312b3aab90bb37aa9cc60be32e05678ee55d6575ee8Chih-Chung Chang // 1313b3aab90bb37aa9cc60be32e05678ee55d6575ee8Chih-Chung Chang // We might temporarily go out of this stable during user interaction, 1314b3aab90bb37aa9cc60be32e05678ee55d6575ee8Chih-Chung Chang // but will "snap back" after user stops interaction. 1315b3aab90bb37aa9cc60be32e05678ee55d6575ee8Chih-Chung Chang // 1316b3aab90bb37aa9cc60be32e05678ee55d6575ee8Chih-Chung Chang // The results are stored in mBound{Left/Right/Top/Bottom}. 1317b3aab90bb37aa9cc60be32e05678ee55d6575ee8Chih-Chung Chang // 13188f568da373699781beb11cfa46a46c5871288353Chih-Chung Chang // An extra parameter "horizontalSlack" (which has the value of 0 usually) 13198f568da373699781beb11cfa46a46c5871288353Chih-Chung Chang // is used to extend the stable region by some pixels on each side 13208f568da373699781beb11cfa46a46c5871288353Chih-Chung Chang // horizontally. 1321b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void calculateStableBound(float scale, int horizontalSlack) { 1322b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Box b = mBoxes.get(0); 13238f568da373699781beb11cfa46a46c5871288353Chih-Chung Chang 1324b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // The width and height of the box in number of view pixels 1325b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int w = widthOf(b, scale); 1326b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int h = heightOf(b, scale); 1327b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1328b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // When the edge of the view is aligned with the edge of the box 1329bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mBoundLeft = (mViewW + 1) / 2 - (w + 1) / 2 - horizontalSlack; 1330bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mBoundRight = w / 2 - mViewW / 2 + horizontalSlack; 1331bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mBoundTop = (mViewH + 1) / 2 - (h + 1) / 2; 1332bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mBoundBottom = h / 2 - mViewH / 2; 1333b3aab90bb37aa9cc60be32e05678ee55d6575ee8Chih-Chung Chang 1334b3aab90bb37aa9cc60be32e05678ee55d6575ee8Chih-Chung Chang // If the scaled height is smaller than the view height, 1335b3aab90bb37aa9cc60be32e05678ee55d6575ee8Chih-Chung Chang // force it to be in the center. 1336b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (viewTallerThanScaledImage(scale)) { 1337bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mBoundTop = mBoundBottom = 0; 1338b3aab90bb37aa9cc60be32e05678ee55d6575ee8Chih-Chung Chang } 1339b3aab90bb37aa9cc60be32e05678ee55d6575ee8Chih-Chung Chang 1340b3aab90bb37aa9cc60be32e05678ee55d6575ee8Chih-Chung Chang // Same for width 13412ce3c3bfe08fff5aee58007cc8ba8f4a50861ae2Yuli Huang if (viewWiderThanScaledImage(scale)) { 1342bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mBoundLeft = mBoundRight = mPlatform.mDefaultX; 1343b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1344b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1345b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1346b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private void calculateStableBound(float scale) { 1347b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang calculateStableBound(scale, 0); 1348b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1349b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1350b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private boolean viewTallerThanScaledImage(float scale) { 1351b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return mViewH >= heightOf(mBoxes.get(0), scale); 13522ce3c3bfe08fff5aee58007cc8ba8f4a50861ae2Yuli Huang } 13532ce3c3bfe08fff5aee58007cc8ba8f4a50861ae2Yuli Huang 13542ce3c3bfe08fff5aee58007cc8ba8f4a50861ae2Yuli Huang private boolean viewWiderThanScaledImage(float scale) { 1355b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return mViewW >= widthOf(mBoxes.get(0), scale); 13562ce3c3bfe08fff5aee58007cc8ba8f4a50861ae2Yuli Huang } 13572ce3c3bfe08fff5aee58007cc8ba8f4a50861ae2Yuli Huang 1358b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private float getTargetScale(Box b) { 1359192b7f1ddf08e7bfa0c65dbf61edb81ebb5a0998Chih-Chung Chang return b.mAnimationStartTime == NO_ANIMATION 1360192b7f1ddf08e7bfa0c65dbf61edb81ebb5a0998Chih-Chung Chang ? b.mCurrentScale : b.mToScale; 1361ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang } 1362ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 1363b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1364b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Animatable: an thing which can do animation. 1365b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1366b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private abstract static class Animatable { 1367b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public long mAnimationStartTime; 1368b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public int mAnimationKind; 1369b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public int mAnimationDuration; 1370b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 13718b930828c7a33d668876972c22a515e9163592f7Pin Ting // This should be overridden in subclass to change the animation values 1372b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // give the progress value in [0, 1]. 1373b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang protected abstract boolean interpolate(float progress); 1374b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public abstract boolean startSnapback(); 1375b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1376b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Returns true if the animation values changes, so things need to be 1377b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // redrawn. 1378b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public boolean advanceAnimation() { 1379b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mAnimationStartTime == NO_ANIMATION) { 1380b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return false; 1381b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1382b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mAnimationStartTime == LAST_ANIMATION) { 1383b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mAnimationStartTime = NO_ANIMATION; 1384b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return startSnapback(); 1385b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1386b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1387b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang float progress; 1388b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mAnimationDuration == 0) { 1389b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang progress = 1; 1390b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } else { 1391b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang long now = AnimationTime.get(); 1392b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang progress = 1393b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang (float) (now - mAnimationStartTime) / mAnimationDuration; 1394b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1395b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1396b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (progress >= 1) { 1397b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang progress = 1; 1398b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } else { 1399b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang progress = applyInterpolationCurve(mAnimationKind, progress); 1400b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1401ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 1402b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang boolean done = interpolate(progress); 1403ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 1404b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (done) { 1405b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mAnimationStartTime = LAST_ANIMATION; 1406b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1407ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 1408b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return true; 1409ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang } 1410ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 1411b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private static float applyInterpolationCurve(int kind, float progress) { 1412b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang float f = 1 - progress; 1413b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang switch (kind) { 1414b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang case ANIM_KIND_SCROLL: 1415b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang case ANIM_KIND_FLING: 14166b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang case ANIM_KIND_FLING_X: 14176b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang case ANIM_KIND_DELETE: 14182c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang case ANIM_KIND_CAPTURE: 1419b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang progress = 1 - f; // linear 1420b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang break; 142102ef48574ef7099ebaa0386bd6fd676bd2fd5489Bobby Georgescu case ANIM_KIND_OPENING: 1422b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang case ANIM_KIND_SCALE: 1423b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang progress = 1 - f * f; // quadratic 1424b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang break; 1425b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang case ANIM_KIND_SNAPBACK: 1426b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang case ANIM_KIND_ZOOM: 1427b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang case ANIM_KIND_SLIDE: 1428b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang progress = 1 - f * f * f * f * f; // x^5 1429b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang break; 1430b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1431b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return progress; 1432b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1433ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang } 1434ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 1435b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1436bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // Platform: captures the global X/Y movement. 1437b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1438b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private class Platform extends Animatable { 1439bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public int mCurrentX, mFromX, mToX, mDefaultX; 1440bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public int mCurrentY, mFromY, mToY, mDefaultY; 1441b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public int mFlingOffset; 1442b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1443b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 1444b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public boolean startSnapback() { 1445b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mAnimationStartTime != NO_ANIMATION) return false; 1446b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mAnimationKind == ANIM_KIND_SCROLL 14476b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang && mListener.isHoldingDown()) return false; 1448192b7f1ddf08e7bfa0c65dbf61edb81ebb5a0998Chih-Chung Chang if (mInScale) return false; 1449b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1450b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Box b = mBoxes.get(0); 1451b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang float scaleMin = mExtraScalingRange ? 1452b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang b.mScaleMin * SCALE_MIN_EXTRA : b.mScaleMin; 1453b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang float scaleMax = mExtraScalingRange ? 1454b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang b.mScaleMax * SCALE_MAX_EXTRA : b.mScaleMax; 1455b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang float scale = Utils.clamp(b.mCurrentScale, scaleMin, scaleMax); 1456b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int x = mCurrentX; 1457bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang int y = mDefaultY; 1458b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mFilmMode) { 14599b270f4f2e20fb0f0455529c2e20990173a75470Bobby Georgescu x = mDefaultX; 1460b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } else { 1461b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang calculateStableBound(scale, HORIZONTAL_SLACK); 1462192b7f1ddf08e7bfa0c65dbf61edb81ebb5a0998Chih-Chung Chang // If the picture is zoomed-in, we want to keep the focus point 1463192b7f1ddf08e7bfa0c65dbf61edb81ebb5a0998Chih-Chung Chang // stay in the same position on screen, so we need to adjust 1464192b7f1ddf08e7bfa0c65dbf61edb81ebb5a0998Chih-Chung Chang // target mCurrentX (which is the center of the focused 1465192b7f1ddf08e7bfa0c65dbf61edb81ebb5a0998Chih-Chung Chang // box). The position of the focus point on screen (relative the 1466192b7f1ddf08e7bfa0c65dbf61edb81ebb5a0998Chih-Chung Chang // the center of the view) is: 1467192b7f1ddf08e7bfa0c65dbf61edb81ebb5a0998Chih-Chung Chang // 1468192b7f1ddf08e7bfa0c65dbf61edb81ebb5a0998Chih-Chung Chang // mCurrentX + scale * mFocusX = mCurrentX' + scale' * mFocusX 1469192b7f1ddf08e7bfa0c65dbf61edb81ebb5a0998Chih-Chung Chang // => mCurrentX' = mCurrentX + (scale - scale') * mFocusX 1470192b7f1ddf08e7bfa0c65dbf61edb81ebb5a0998Chih-Chung Chang // 1471192b7f1ddf08e7bfa0c65dbf61edb81ebb5a0998Chih-Chung Chang if (!viewWiderThanScaledImage(scale)) { 1472192b7f1ddf08e7bfa0c65dbf61edb81ebb5a0998Chih-Chung Chang float scaleDiff = b.mCurrentScale - scale; 1473192b7f1ddf08e7bfa0c65dbf61edb81ebb5a0998Chih-Chung Chang x += (int) (mFocusX * scaleDiff + 0.5f); 1474192b7f1ddf08e7bfa0c65dbf61edb81ebb5a0998Chih-Chung Chang } 1475b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang x = Utils.clamp(x, mBoundLeft, mBoundRight); 1476b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1477bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (mCurrentX != x || mCurrentY != y) { 1478bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang return doAnimation(x, y, ANIM_KIND_SNAPBACK); 1479b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1480b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return false; 1481b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1482b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1483bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // The updateDefaultXY() should be called whenever these variables 1484bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // changes: (1) mConstrained (2) mConstrainedFrame (3) mViewW/H (4) 1485bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // mFilmMode 1486bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang public void updateDefaultXY() { 1487bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // We don't check mFilmMode and return 0 for mDefaultX. Because 1488bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // otherwise if we decide to leave film mode because we are 1489bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // centered, we will immediately back into film mode because we find 1490bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang // we are not centered. 1491bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (mConstrained && !mConstrainedFrame.isEmpty()) { 1492bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mDefaultX = mConstrainedFrame.centerX() - mViewW / 2; 1493bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mDefaultY = mFilmMode ? 0 : 1494bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mConstrainedFrame.centerY() - mViewH / 2; 1495bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } else { 1496bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mDefaultX = 0; 1497bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mDefaultY = 0; 1498bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 1499bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 1500bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang 1501b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Starts an animation for the platform. 1502bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang private boolean doAnimation(int targetX, int targetY, int kind) { 1503bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (mCurrentX == targetX && mCurrentY == targetY) return false; 1504b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mAnimationKind = kind; 1505b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mFromX = mCurrentX; 1506bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mFromY = mCurrentY; 1507b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mToX = targetX; 1508bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mToY = targetY; 1509b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mAnimationStartTime = AnimationTime.startTime(); 1510b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mAnimationDuration = ANIM_TIME[kind]; 1511b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mFlingOffset = 0; 1512b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang advanceAnimation(); 1513b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return true; 1514b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1515b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1516b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 1517b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang protected boolean interpolate(float progress) { 1518b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mAnimationKind == ANIM_KIND_FLING) { 15196b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang return interpolateFlingPage(progress); 15206b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang } else if (mAnimationKind == ANIM_KIND_FLING_X) { 15216b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang return interpolateFlingFilm(progress); 1522b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } else { 1523b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return interpolateLinear(progress); 1524b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1525b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1526b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1527b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private boolean interpolateFlingFilm(float progress) { 1528b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mFilmScroller.computeScrollOffset(); 1529b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mCurrentX = mFilmScroller.getCurrX() + mFlingOffset; 1530b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1531b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int dir = EdgeView.INVALID_DIRECTION; 1532bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (mCurrentX < mDefaultX) { 1533fb1a15559bb2a0a1c8a41efd3e0420a2a2d70590Chih-Chung Chang if (!mHasNext) { 1534b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang dir = EdgeView.RIGHT; 1535b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1536bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } else if (mCurrentX > mDefaultX) { 1537fb1a15559bb2a0a1c8a41efd3e0420a2a2d70590Chih-Chung Chang if (!mHasPrev) { 1538b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang dir = EdgeView.LEFT; 1539b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1540b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1541b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (dir != EdgeView.INVALID_DIRECTION) { 1542b27df4650459068b409924493bbadaf25bb7e191Bobby Georgescu // TODO: restore this onAbsorb call 1543b27df4650459068b409924493bbadaf25bb7e191Bobby Georgescu //int v = (int) (mFilmScroller.getCurrVelocity() + 0.5f); 1544b27df4650459068b409924493bbadaf25bb7e191Bobby Georgescu //mListener.onAbsorb(v, dir); 1545b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mFilmScroller.forceFinished(true); 1546bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mCurrentX = mDefaultX; 1547b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1548b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return mFilmScroller.isFinished(); 1549b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1550b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1551b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private boolean interpolateFlingPage(float progress) { 1552b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPageScroller.computeScrollOffset(progress); 1553b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang Box b = mBoxes.get(0); 1554b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang calculateStableBound(b.mCurrentScale); 1555b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1556b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int oldX = mCurrentX; 1557b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mCurrentX = mPageScroller.getCurrX(); 1558b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1559b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Check if we hit the edges; show edge effects if we do. 1560b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (oldX > mBoundLeft && mCurrentX == mBoundLeft) { 1561b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int v = (int) (-mPageScroller.getCurrVelocityX() + 0.5f); 1562b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mListener.onAbsorb(v, EdgeView.RIGHT); 1563b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } else if (oldX < mBoundRight && mCurrentX == mBoundRight) { 1564b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int v = (int) (mPageScroller.getCurrVelocityX() + 0.5f); 1565b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mListener.onAbsorb(v, EdgeView.LEFT); 1566b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1567b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1568b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return progress >= 1; 1569b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1570b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1571b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private boolean interpolateLinear(float progress) { 1572b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Other animations 1573b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (progress >= 1) { 1574b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mCurrentX = mToX; 1575bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mCurrentY = mToY; 1576b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return true; 1577b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } else { 15782c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (mAnimationKind == ANIM_KIND_CAPTURE) { 15792c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang progress = CaptureAnimation.calculateSlide(progress); 1580bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang } 1581bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mCurrentX = (int) (mFromX + progress * (mToX - mFromX)); 1582bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang mCurrentY = (int) (mFromY + progress * (mToY - mFromY)); 1583bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang if (mAnimationKind == ANIM_KIND_CAPTURE) { 15842c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang return false; 15852c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } else { 1586bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang return (mCurrentX == mToX && mCurrentY == mToY); 15872c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 1588b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1589b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1590ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang } 1591532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang 1592b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1593b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Box: represents a rectangular area which shows a picture. 1594b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1595b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private class Box extends Animatable { 1596b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Size of the bitmap 1597b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public int mImageW, mImageH; 1598b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1599b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // This is true if we assume the image size is the same as view size 1600b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // until we know the actual size of image. This is also used to 1601b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // determine if there is an image ready to show. 1602b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public boolean mUseViewSize; 1603b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1604b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // The minimum and maximum scale we allow for this box. 1605b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public float mScaleMin, mScaleMax; 1606b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1607b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // The X/Y value indicates where the center of the box is on the view 1608b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // coordinate. We always keep the mCurrent{X,Y,Scale} sync with the 1609b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // actual values used currently. Note that the X values are implicitly 1610b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // defined by Platform and Gaps. 1611b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public int mCurrentY, mFromY, mToY; 1612b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public float mCurrentScale, mFromScale, mToScale; 1613b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1614b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // The absolute X coordinate of the center of the box. This is only used 1615b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // during moveBox(). 1616b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public int mAbsoluteX; 1617b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1618b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 1619b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public boolean startSnapback() { 1620b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mAnimationStartTime != NO_ANIMATION) return false; 1621b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mAnimationKind == ANIM_KIND_SCROLL 16226b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang && mListener.isHoldingDown()) return false; 16236b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang if (mAnimationKind == ANIM_KIND_DELETE 16246b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang && mListener.isHoldingDelete()) return false; 1625b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mInScale && this == mBoxes.get(0)) return false; 1626b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1627192b7f1ddf08e7bfa0c65dbf61edb81ebb5a0998Chih-Chung Chang int y = mCurrentY; 1628b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang float scale; 1629b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1630b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (this == mBoxes.get(0)) { 1631b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang float scaleMin = mExtraScalingRange ? 1632b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mScaleMin * SCALE_MIN_EXTRA : mScaleMin; 1633b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang float scaleMax = mExtraScalingRange ? 1634b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mScaleMax * SCALE_MAX_EXTRA : mScaleMax; 1635b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang scale = Utils.clamp(mCurrentScale, scaleMin, scaleMax); 1636b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mFilmMode) { 1637bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang y = 0; 1638b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } else { 1639b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang calculateStableBound(scale, HORIZONTAL_SLACK); 1640192b7f1ddf08e7bfa0c65dbf61edb81ebb5a0998Chih-Chung Chang // If the picture is zoomed-in, we want to keep the focus 1641192b7f1ddf08e7bfa0c65dbf61edb81ebb5a0998Chih-Chung Chang // point stay in the same position on screen. See the 1642192b7f1ddf08e7bfa0c65dbf61edb81ebb5a0998Chih-Chung Chang // comment in Platform.startSnapback for details. 1643192b7f1ddf08e7bfa0c65dbf61edb81ebb5a0998Chih-Chung Chang if (!viewTallerThanScaledImage(scale)) { 1644192b7f1ddf08e7bfa0c65dbf61edb81ebb5a0998Chih-Chung Chang float scaleDiff = mCurrentScale - scale; 1645192b7f1ddf08e7bfa0c65dbf61edb81ebb5a0998Chih-Chung Chang y += (int) (mFocusY * scaleDiff + 0.5f); 1646192b7f1ddf08e7bfa0c65dbf61edb81ebb5a0998Chih-Chung Chang } 1647192b7f1ddf08e7bfa0c65dbf61edb81ebb5a0998Chih-Chung Chang y = Utils.clamp(y, mBoundTop, mBoundBottom); 1648b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1649b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } else { 1650bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang y = 0; 1651b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang scale = mScaleMin; 1652b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1653b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1654b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mCurrentY != y || mCurrentScale != scale) { 1655b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return doAnimation(y, scale, ANIM_KIND_SNAPBACK); 1656b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1657b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return false; 16582ce3c3bfe08fff5aee58007cc8ba8f4a50861ae2Yuli Huang } 1659b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1660b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private boolean doAnimation(int targetY, float targetScale, int kind) { 1661192b7f1ddf08e7bfa0c65dbf61edb81ebb5a0998Chih-Chung Chang targetScale = clampScale(targetScale); 1662b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 16632c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (mCurrentY == targetY && mCurrentScale == targetScale 16642c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang && kind != ANIM_KIND_CAPTURE) { 1665b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return false; 1666b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1667b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1668b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Now starts an animation for the box. 1669b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mAnimationKind = kind; 1670b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mFromY = mCurrentY; 1671b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mFromScale = mCurrentScale; 1672b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mToY = targetY; 1673b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mToScale = targetScale; 1674b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mAnimationStartTime = AnimationTime.startTime(); 1675b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mAnimationDuration = ANIM_TIME[kind]; 1676b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang advanceAnimation(); 1677b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return true; 16782ce3c3bfe08fff5aee58007cc8ba8f4a50861ae2Yuli Huang } 1679b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1680192b7f1ddf08e7bfa0c65dbf61edb81ebb5a0998Chih-Chung Chang // Clamps the input scale to the range that doAnimation() can reach. 1681192b7f1ddf08e7bfa0c65dbf61edb81ebb5a0998Chih-Chung Chang public float clampScale(float s) { 1682192b7f1ddf08e7bfa0c65dbf61edb81ebb5a0998Chih-Chung Chang return Utils.clamp(s, 1683192b7f1ddf08e7bfa0c65dbf61edb81ebb5a0998Chih-Chung Chang SCALE_MIN_EXTRA * mScaleMin, 1684192b7f1ddf08e7bfa0c65dbf61edb81ebb5a0998Chih-Chung Chang SCALE_MAX_EXTRA * mScaleMax); 1685192b7f1ddf08e7bfa0c65dbf61edb81ebb5a0998Chih-Chung Chang } 1686192b7f1ddf08e7bfa0c65dbf61edb81ebb5a0998Chih-Chung Chang 1687b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 1688b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang protected boolean interpolate(float progress) { 1689b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mAnimationKind == ANIM_KIND_FLING) { 1690b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return interpolateFlingPage(progress); 1691b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } else { 1692b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return interpolateLinear(progress); 1693b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 16942ce3c3bfe08fff5aee58007cc8ba8f4a50861ae2Yuli Huang } 1695b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1696b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private boolean interpolateFlingPage(float progress) { 1697b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mPageScroller.computeScrollOffset(progress); 1698b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang calculateStableBound(mCurrentScale); 1699b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1700b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int oldY = mCurrentY; 1701b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mCurrentY = mPageScroller.getCurrY(); 1702b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1703b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Check if we hit the edges; show edge effects if we do. 1704b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (oldY > mBoundTop && mCurrentY == mBoundTop) { 1705b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int v = (int) (-mPageScroller.getCurrVelocityY() + 0.5f); 1706b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mListener.onAbsorb(v, EdgeView.BOTTOM); 1707b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } else if (oldY < mBoundBottom && mCurrentY == mBoundBottom) { 1708b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang int v = (int) (mPageScroller.getCurrVelocityY() + 0.5f); 1709b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mListener.onAbsorb(v, EdgeView.TOP); 1710b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1711b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1712b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return progress >= 1; 1713b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1714b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1715b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private boolean interpolateLinear(float progress) { 1716b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (progress >= 1) { 1717b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mCurrentY = mToY; 1718b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mCurrentScale = mToScale; 1719b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return true; 1720b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } else { 1721b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mCurrentY = (int) (mFromY + progress * (mToY - mFromY)); 1722b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mCurrentScale = mFromScale + progress * (mToScale - mFromScale); 17232c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (mAnimationKind == ANIM_KIND_CAPTURE) { 17242c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang float f = CaptureAnimation.calculateScale(progress); 17252c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mCurrentScale *= f; 17262c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang return false; 17272c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } else { 17282c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang return (mCurrentY == mToY && mCurrentScale == mToScale); 17292c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 1730b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1731b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1732b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1733b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1734b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1735b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Gap: represents a rectangular area which is between two boxes. 1736b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1737b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang private class Gap extends Animatable { 1738b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // The default gap size between two boxes. The value may vary for 1739b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // different image size of the boxes and for different modes (page or 1740b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // film). 1741b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public int mDefaultSize; 1742b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1743b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // The gap size between the two boxes. 1744b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public int mCurrentGap, mFromGap, mToGap; 1745b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1746b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 1747b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang public boolean startSnapback() { 1748b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (mAnimationStartTime != NO_ANIMATION) return false; 17492c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang return doAnimation(mDefaultSize, ANIM_KIND_SNAPBACK); 1750b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1751b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1752b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang // Starts an animation for a gap. 17532c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang public boolean doAnimation(int targetSize, int kind) { 17542c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (mCurrentGap == targetSize && kind != ANIM_KIND_CAPTURE) { 17552c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang return false; 17562c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 17572c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mAnimationKind = kind; 1758b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mFromGap = mCurrentGap; 1759b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mToGap = targetSize; 1760b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mAnimationStartTime = AnimationTime.startTime(); 1761b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mAnimationDuration = ANIM_TIME[mAnimationKind]; 1762b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang advanceAnimation(); 1763b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return true; 1764b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 1765b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang 1766b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang @Override 1767b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang protected boolean interpolate(float progress) { 1768b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang if (progress >= 1) { 1769b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mCurrentGap = mToGap; 1770b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang return true; 1771b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } else { 1772b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang mCurrentGap = (int) (mFromGap + progress * (mToGap - mFromGap)); 17732c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang if (mAnimationKind == ANIM_KIND_CAPTURE) { 17742c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang float f = CaptureAnimation.calculateScale(progress); 17752c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang mCurrentGap = (int) (mCurrentGap * f); 17762c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang return false; 17772c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } else { 17782c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang return (mCurrentGap == mToGap); 17792c6173822a612597c79be41b126367ddfbb5d518Chih-Chung Chang } 1780b7ec5534c7b539be2397c27cfa5e8b992974c12dChih-Chung Chang } 17812ce3c3bfe08fff5aee58007cc8ba8f4a50861ae2Yuli Huang } 1782532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang } 1783ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang 1784ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1785ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang // FilmRatio: represents the progress of film mode change. 1786ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang //////////////////////////////////////////////////////////////////////////// 1787ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang private class FilmRatio extends Animatable { 1788ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang // The film ratio: 1 means switching to film mode is complete, 0 means 1789ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang // switching to page mode is complete. 1790ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang public float mCurrentRatio, mFromRatio, mToRatio; 1791ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang 1792ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang @Override 1793ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang public boolean startSnapback() { 1794ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang float target = mFilmMode ? 1f : 0f; 1795ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang if (target == mToRatio) return false; 1796ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang return doAnimation(target, ANIM_KIND_SNAPBACK); 1797ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang } 1798ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang 1799ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang // Starts an animation for the film ratio. 1800ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang private boolean doAnimation(float targetRatio, int kind) { 1801ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang mAnimationKind = kind; 1802ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang mFromRatio = mCurrentRatio; 1803ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang mToRatio = targetRatio; 1804ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang mAnimationStartTime = AnimationTime.startTime(); 1805ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang mAnimationDuration = ANIM_TIME[mAnimationKind]; 1806ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang advanceAnimation(); 1807ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang return true; 1808ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang } 1809ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang 1810ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang @Override 1811ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang protected boolean interpolate(float progress) { 1812ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang if (progress >= 1) { 1813ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang mCurrentRatio = mToRatio; 1814ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang return true; 1815ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang } else { 1816ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang mCurrentRatio = mFromRatio + progress * (mToRatio - mFromRatio); 1817ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang return (mCurrentRatio == mToRatio); 1818ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang } 1819ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang } 1820ba12eae90b5b1a80ee002aa0df8c5c5189c4faa3Chih-Chung Chang } 1821ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang} 1822