149b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong/* 249b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong * Copyright (C) 2013 The Android Open Source Project 349b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong * 449b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong * Licensed under the Apache License, Version 2.0 (the "License"); 549b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong * you may not use this file except in compliance with the License. 649b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong * You may obtain a copy of the License at 749b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong * 849b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong * http://www.apache.org/licenses/LICENSE-2.0 949b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong * 1049b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong * Unless required by applicable law or agreed to in writing, software 1149b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong * distributed under the License is distributed on an "AS IS" BASIS, 1249b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1349b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong * See the License for the specific language governing permissions and 1449b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong * limitations under the License. 1549b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong */ 1649b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 1701054e922aa547b937a71131ad04c6bd15356240Angus Kongpackage com.android.camera.widget; 1849b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 1949b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kongimport android.animation.Animator; 20d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liuimport android.animation.AnimatorSet; 21e78541f2edf2f02660c34660114e76d53b32ab8bAngus Kongimport android.animation.TimeInterpolator; 2249b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kongimport android.animation.ValueAnimator; 2349b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kongimport android.content.Context; 2449b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kongimport android.graphics.Canvas; 25c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kongimport android.graphics.Point; 2649b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kongimport android.graphics.Rect; 27a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kongimport android.graphics.RectF; 288de13111cc4e62da3462ea321d18c7951282e0d0Doris Liuimport android.net.Uri; 29893ca79bdea899fe3f3ed700c22235cc5b460527Spike Spragueimport android.os.Bundle; 30b21215a1a59812592380f31891becedbdec7468bAngus Kongimport android.os.Handler; 31bcd1152e8214b1fb4a17963ffe8c292681c81688Sam Juddimport android.os.SystemClock; 3249b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kongimport android.util.AttributeSet; 333179f6a49516833761be5155c4e1244ac0aa17feDoris Liuimport android.util.DisplayMetrics; 3443bf03f6e7f9a71b7553e7282b5799798997caf7Sam Juddimport android.util.SparseArray; 3549b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kongimport android.view.MotionEvent; 3649b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kongimport android.view.View; 3749b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kongimport android.view.ViewGroup; 383f192ccf03d0d25521b96304c4464b4bad28150aSascha Haeberlingimport android.view.accessibility.AccessibilityNodeInfo; 3949b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kongimport android.view.animation.DecelerateInterpolator; 4049b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kongimport android.widget.Scroller; 4149b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 4288ef7664ba6a888fa5da8693091674e152b56192Sascha Haeberlingimport com.android.camera.CameraActivity; 438ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohdeimport com.android.camera.data.FilmstripItem; 448ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohdeimport com.android.camera.data.FilmstripItem.VideoClickedCallback; 452bca210e5fc8a77685775ffb403096167b017dceAngus Kongimport com.android.camera.debug.Log; 46628481532e1e58a0a26330d238e850aec5657bceAngus Kongimport com.android.camera.filmstrip.FilmstripController; 478ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohdeimport com.android.camera.filmstrip.FilmstripDataAdapter; 4801054e922aa547b937a71131ad04c6bd15356240Angus Kongimport com.android.camera.ui.FilmstripGestureRecognizer; 4901054e922aa547b937a71131ad04c6bd15356240Angus Kongimport com.android.camera.ui.ZoomView; 50c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kongimport com.android.camera.util.CameraUtil; 518e963a5a6016d246184ed65906f9d103e92b17e2Sascha Haeberlingimport com.android.camera2.R; 52f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling 53770c2b3e82326d6272b1d2f65a65e5330c951abbSascha Haeberlingimport java.lang.ref.WeakReference; 5443bf03f6e7f9a71b7553e7282b5799798997caf7Sam Juddimport java.util.ArrayDeque; 553f969c1735e2636bf22dfe44104d0e99924cca97Alan Newbergerimport java.util.Arrays; 5643bf03f6e7f9a71b7553e7282b5799798997caf7Sam Juddimport java.util.Queue; 573f969c1735e2636bf22dfe44104d0e99924cca97Alan Newberger 58b2510252fb020f3ccb88787c870930427377b9dfAngus Kongpublic class FilmstripView extends ViewGroup { 59770c2b3e82326d6272b1d2f65a65e5330c951abbSascha Haeberling /** 60770c2b3e82326d6272b1d2f65a65e5330c951abbSascha Haeberling * An action callback to be used for actions on the local media data items. 61770c2b3e82326d6272b1d2f65a65e5330c951abbSascha Haeberling */ 628ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde public static class PlayVideoIntent implements VideoClickedCallback { 638ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde private final WeakReference<CameraActivity> mActivity; 64770c2b3e82326d6272b1d2f65a65e5330c951abbSascha Haeberling 65770c2b3e82326d6272b1d2f65a65e5330c951abbSascha Haeberling /** 66770c2b3e82326d6272b1d2f65a65e5330c951abbSascha Haeberling * The given activity is used to start intents. It is wrapped in a weak 67770c2b3e82326d6272b1d2f65a65e5330c951abbSascha Haeberling * reference to prevent leaks. 68770c2b3e82326d6272b1d2f65a65e5330c951abbSascha Haeberling */ 698ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde public PlayVideoIntent(CameraActivity activity) { 708ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mActivity = new WeakReference<CameraActivity>(activity); 71770c2b3e82326d6272b1d2f65a65e5330c951abbSascha Haeberling } 72770c2b3e82326d6272b1d2f65a65e5330c951abbSascha Haeberling 73770c2b3e82326d6272b1d2f65a65e5330c951abbSascha Haeberling /** 74770c2b3e82326d6272b1d2f65a65e5330c951abbSascha Haeberling * Fires an intent to play the video with the given URI and title. 75770c2b3e82326d6272b1d2f65a65e5330c951abbSascha Haeberling */ 76770c2b3e82326d6272b1d2f65a65e5330c951abbSascha Haeberling @Override 77770c2b3e82326d6272b1d2f65a65e5330c951abbSascha Haeberling public void playVideo(Uri uri, String title) { 788ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde CameraActivity activity = mActivity.get(); 79770c2b3e82326d6272b1d2f65a65e5330c951abbSascha Haeberling if (activity != null) { 80770c2b3e82326d6272b1d2f65a65e5330c951abbSascha Haeberling CameraUtil.playVideo(activity, uri, title); 81770c2b3e82326d6272b1d2f65a65e5330c951abbSascha Haeberling } 82770c2b3e82326d6272b1d2f65a65e5330c951abbSascha Haeberling } 83770c2b3e82326d6272b1d2f65a65e5330c951abbSascha Haeberling } 84770c2b3e82326d6272b1d2f65a65e5330c951abbSascha Haeberling 85770c2b3e82326d6272b1d2f65a65e5330c951abbSascha Haeberling 862bca210e5fc8a77685775ffb403096167b017dceAngus Kong private static final Log.Tag TAG = new Log.Tag("FilmstripView"); 87af24d28f8938a05d2e3c40155e39cbc7ff4d64b7Angus Kong 8849b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong private static final int BUFFER_SIZE = 5; 898ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde private static final int BUFFER_CENTER = (BUFFER_SIZE - 1) / 2; 90734598c39e6a9d809982dae2907dc7d10e0b0e9fAngus Kong private static final int GEOMETRY_ADJUST_TIME_MS = 400; 918969a67c926608737f3e49f2d2240298372e8416Angus Kong private static final int SNAP_IN_CENTER_TIME_MS = 600; 92d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu private static final float FLING_COASTING_DURATION_S = 0.05f; 93121022cb590955e37f1264f77190ce4711159976Doris Liu private static final int ZOOM_ANIMATION_DURATION_MS = 200; 947d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong private static final int CAMERA_PREVIEW_SWIPE_THRESHOLD = 300; 9543596cd34e7020d6a0aafcdc31297237ad98496cAngus Kong private static final float FILM_STRIP_SCALE = 0.7f; 964ff5a1ab360577c6a7ec953f9197778c84c9d334Angus Kong private static final float FULL_SCREEN_SCALE = 1f; 97121022cb590955e37f1264f77190ce4711159976Doris Liu 98bcd1152e8214b1fb4a17963ffe8c292681c81688Sam Judd // The min velocity at which the user must have moved their finger in 99bcd1152e8214b1fb4a17963ffe8c292681c81688Sam Judd // pixels per millisecond to count a vertical gesture as a promote/demote 100bcd1152e8214b1fb4a17963ffe8c292681c81688Sam Judd // at short vertical distances. 101bcd1152e8214b1fb4a17963ffe8c292681c81688Sam Judd private static final float PROMOTE_VELOCITY = 3.5f; 102bcd1152e8214b1fb4a17963ffe8c292681c81688Sam Judd // The min distance relative to this view's height the user must have 103bcd1152e8214b1fb4a17963ffe8c292681c81688Sam Judd // moved their finger to count a vertical gesture as a promote/demote if 104bcd1152e8214b1fb4a17963ffe8c292681c81688Sam Judd // they moved their finger at least at PROMOTE_VELOCITY. 105bcd1152e8214b1fb4a17963ffe8c292681c81688Sam Judd private static final float VELOCITY_PROMOTE_HEIGHT_RATIO = 1/10f; 106bcd1152e8214b1fb4a17963ffe8c292681c81688Sam Judd // The min distance relative to this view's height the user must have 107bcd1152e8214b1fb4a17963ffe8c292681c81688Sam Judd // moved their finger to count a vertical gesture as a promote/demote if 108bcd1152e8214b1fb4a17963ffe8c292681c81688Sam Judd // they moved their finger at less than PROMOTE_VELOCITY. 109bcd1152e8214b1fb4a17963ffe8c292681c81688Sam Judd private static final float PROMOTE_HEIGHT_RATIO = 1/2f; 110bcd1152e8214b1fb4a17963ffe8c292681c81688Sam Judd 111121022cb590955e37f1264f77190ce4711159976Doris Liu private static final float TOLERANCE = 0.1f; 112fb57df15a87f95ce8b2f861e54d960602912e03cDoris Liu // Only check for intercepting touch events within first 500ms 113fb57df15a87f95ce8b2f861e54d960602912e03cDoris Liu private static final int SWIPE_TIME_OUT = 500; 114d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu private static final int DECELERATION_FACTOR = 4; 1159652134e6e1b312e348ed3565343741239907f11Alan Newberger private static final float MOUSE_SCROLL_FACTOR = 128f; 11649b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 11788ef7664ba6a888fa5da8693091674e152b56192Sascha Haeberling private CameraActivity mActivity; 1188ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde private VideoClickedCallback mVideoClickedCallback; 119166e36fb6e04d40a1bef0459ee6b96c9c736039bAngus Kong private FilmstripGestureRecognizer mGestureRecognizer; 120166e36fb6e04d40a1bef0459ee6b96c9c736039bAngus Kong private FilmstripGestureRecognizer.Listener mGestureListener; 1218ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde private FilmstripDataAdapter mDataAdapter; 122faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong private int mViewGapInPixel; 12349b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong private final Rect mDrawArea = new Rect(); 12449b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 12549b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong private float mScale; 1268ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde private FilmstripControllerImpl mController; 127af24d28f8938a05d2e3c40155e39cbc7ff4d64b7Angus Kong private int mCenterX = -1; 1288ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde private final ViewItem[] mViewItems = new ViewItem[BUFFER_SIZE]; 12949b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 13001054e922aa547b937a71131ad04c6bd15356240Angus Kong private FilmstripController.FilmstripListener mListener; 1318de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu private ZoomView mZoomView = null; 13287f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong 133fb57df15a87f95ce8b2f861e54d960602912e03cDoris Liu private MotionEvent mDown; 134fb57df15a87f95ce8b2f861e54d960602912e03cDoris Liu private boolean mCheckToIntercept = true; 135fb57df15a87f95ce8b2f861e54d960602912e03cDoris Liu private int mSlop; 136e78541f2edf2f02660c34660114e76d53b32ab8bAngus Kong private TimeInterpolator mViewAnimInterpolator; 137e78541f2edf2f02660c34660114e76d53b32ab8bAngus Kong 13847721fa8f2dc13cb565ae5629a417dc4ed298e81Angus Kong // This is true if and only if the user is scrolling, 13947721fa8f2dc13cb565ae5629a417dc4ed298e81Angus Kong private boolean mIsUserScrolling; 1408ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde private int mAdapterIndexUserIsScrollingOver; 1413179f6a49516833761be5155c4e1244ac0aa17feDoris Liu private float mOverScaleFactor = 1f; 14247721fa8f2dc13cb565ae5629a417dc4ed298e81Angus Kong 1434567160a43fa5787012bf0b618c216cf18ac0457Angus Kong private boolean mFullScreenUIHidden = false; 1448ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde private final SparseArray<Queue<View>> recycledViews = new SparseArray<>(); 14543bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd 146f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling /** 147f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling * A helper class to tract and calculate the view coordination. 148f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling */ 1498ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde private static class ViewItem { 15077d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde private static enum RenderSize { 15177d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde TINY, 15277d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde THUMBNAIL, 15377d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde FULL_RES 15477d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde } 15577d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde 15677d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde private final FilmstripView mFilmstrip; 15777d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde private final View mView; 15877d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde private final RectF mViewArea; 15977d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde 1608ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde private int mIndex; 161f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling /** The position of the left of the view in the whole filmstrip. */ 16249b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong private int mLeftPosition; 1638e29072ca69229a25dc4a856e3635d131613f4caAlan Newberger private FilmstripItem mData; 16477d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde private RenderSize mRenderSize; 1651f9db2dfe59c33228103c54523281501ef52c9baAngus Kong 1661f9db2dfe59c33228103c54523281501ef52c9baAngus Kong private ValueAnimator mTranslationXAnimator; 1671f9db2dfe59c33228103c54523281501ef52c9baAngus Kong private ValueAnimator mTranslationYAnimator; 1681f9db2dfe59c33228103c54523281501ef52c9baAngus Kong private ValueAnimator mAlphaAnimator; 169edbba628dc2e31057b304c6a431f44dbca125891Angus Kong 170e7263f7ea45cf31d3948984ba8514e03ef86627ePaul Rohde private boolean mLockAtFullOpacity; 171e7263f7ea45cf31d3948984ba8514e03ef86627ePaul Rohde 1724ff5a1ab360577c6a7ec953f9197778c84c9d334Angus Kong /** 1734ff5a1ab360577c6a7ec953f9197778c84c9d334Angus Kong * Constructor. 17488ef7664ba6a888fa5da8693091674e152b56192Sascha Haeberling * 1758ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde * @param index The index of the data from 1768ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde * {@link com.android.camera.filmstrip.FilmstripDataAdapter}. 1774ff5a1ab360577c6a7ec953f9197778c84c9d334Angus Kong * @param v The {@code View} representing the data. 1784ff5a1ab360577c6a7ec953f9197778c84c9d334Angus Kong */ 1798ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde public ViewItem(int index, View v, FilmstripItem data, FilmstripView filmstrip) { 18077d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde mFilmstrip = filmstrip; 18177d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde mView = v; 18277d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde mViewArea = new RectF(); 18377d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde 1848ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mIndex = index; 1851f9db2dfe59c33228103c54523281501ef52c9baAngus Kong mData = data; 18649b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong mLeftPosition = -1; 18777d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde mRenderSize = RenderSize.TINY; 188e7263f7ea45cf31d3948984ba8514e03ef86627ePaul Rohde mLockAtFullOpacity = false; 18977d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde 19077d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde mView.setPivotX(0f); 19177d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde mView.setPivotY(0f); 19249b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 19349b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 1945a0be52d3db2398cfe01d18adf779d9e443edf82Alan Newberger public FilmstripItem getData() { 1955a0be52d3db2398cfe01d18adf779d9e443edf82Alan Newberger return mData; 1965a0be52d3db2398cfe01d18adf779d9e443edf82Alan Newberger } 1975a0be52d3db2398cfe01d18adf779d9e443edf82Alan Newberger 1988e29072ca69229a25dc4a856e3635d131613f4caAlan Newberger public void setData(FilmstripItem item) { 1998e29072ca69229a25dc4a856e3635d131613f4caAlan Newberger mData = item; 20077d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde 20177d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde renderTiny(); 2028e29072ca69229a25dc4a856e3635d131613f4caAlan Newberger } 2038e29072ca69229a25dc4a856e3635d131613f4caAlan Newberger 20477d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde public void renderTiny() { 20577d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde if (mRenderSize != RenderSize.TINY) { 20677d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde mRenderSize = RenderSize.TINY; 20777d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde 20877d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde Log.i(TAG, "[ViewItem:" + mIndex + "] mData.renderTiny()"); 20977d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde mData.renderTiny(mView); 21077d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde } 211caca8c7b2e97bd76e4df1ea98c08acaa48b21557Andy Huibers } 212caca8c7b2e97bd76e4df1ea98c08acaa48b21557Andy Huibers 21377d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde public void renderThumbnail() { 21477d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde if (mRenderSize != RenderSize.THUMBNAIL) { 21577d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde mRenderSize = RenderSize.THUMBNAIL; 21677d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde 21777d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde Log.i(TAG, "[ViewItem:" + mIndex + "] mData.renderThumbnail()"); 21877d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde mData.renderThumbnail(mView); 21977d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde } 22077d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde } 22177d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde 22277d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde public void renderFullRes() { 22377d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde if (mRenderSize != RenderSize.FULL_RES) { 22477d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde mRenderSize = RenderSize.FULL_RES; 22577d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde 22677d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde Log.i(TAG, "[ViewItem:" + mIndex + "] mData.renderFullRes()"); 22777d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde mData.renderFullRes(mView); 22877d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde } 229caca8c7b2e97bd76e4df1ea98c08acaa48b21557Andy Huibers } 230caca8c7b2e97bd76e4df1ea98c08acaa48b21557Andy Huibers 231e7263f7ea45cf31d3948984ba8514e03ef86627ePaul Rohde public void lockAtFullOpacity() { 232e7263f7ea45cf31d3948984ba8514e03ef86627ePaul Rohde if (!mLockAtFullOpacity) { 233e7263f7ea45cf31d3948984ba8514e03ef86627ePaul Rohde mLockAtFullOpacity = true; 234e7263f7ea45cf31d3948984ba8514e03ef86627ePaul Rohde mView.setAlpha(1.0f); 235e7263f7ea45cf31d3948984ba8514e03ef86627ePaul Rohde } 236e7263f7ea45cf31d3948984ba8514e03ef86627ePaul Rohde } 237e7263f7ea45cf31d3948984ba8514e03ef86627ePaul Rohde 238e7263f7ea45cf31d3948984ba8514e03ef86627ePaul Rohde public void unlockOpacity() { 239e7263f7ea45cf31d3948984ba8514e03ef86627ePaul Rohde mLockAtFullOpacity = false; 240e7263f7ea45cf31d3948984ba8514e03ef86627ePaul Rohde } 241e7263f7ea45cf31d3948984ba8514e03ef86627ePaul Rohde 242280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling /** 2438ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde * Returns the index from 2448ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde * {@link com.android.camera.filmstrip.FilmstripDataAdapter}. 245280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling */ 2468ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde public int getAdapterIndex() { 2478ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde return mIndex; 24849b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 24949b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 250280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling /** 2518ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde * Sets the index used in the 2528ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde * {@link com.android.camera.filmstrip.FilmstripDataAdapter}. 253280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling */ 2548ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde public void setIndex(int index) { 2558ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mIndex = index; 25687f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong } 25787f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong 2584ff5a1ab360577c6a7ec953f9197778c84c9d334Angus Kong /** Sets the left position of the view in the whole filmstrip. */ 25949b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong public void setLeftPosition(int pos) { 26049b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong mLeftPosition = pos; 26149b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 26249b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 2634ff5a1ab360577c6a7ec953f9197778c84c9d334Angus Kong /** Returns the left position of the view in the whole filmstrip. */ 26449b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong public int getLeftPosition() { 26549b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong return mLeftPosition; 26649b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 26749b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 2684ff5a1ab360577c6a7ec953f9197778c84c9d334Angus Kong /** Returns the translation of Y regarding the view scale. */ 2691f9db2dfe59c33228103c54523281501ef52c9baAngus Kong public float getTranslationY() { 2708ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde return mView.getTranslationY() / mFilmstrip.mScale; 27187f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong } 27287f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong 2734ff5a1ab360577c6a7ec953f9197778c84c9d334Angus Kong /** Returns the translation of X regarding the view scale. */ 2741f9db2dfe59c33228103c54523281501ef52c9baAngus Kong public float getTranslationX() { 2758ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde return mView.getTranslationX() / mFilmstrip.mScale; 2761f9db2dfe59c33228103c54523281501ef52c9baAngus Kong } 2771f9db2dfe59c33228103c54523281501ef52c9baAngus Kong 2781f9db2dfe59c33228103c54523281501ef52c9baAngus Kong /** Sets the translation of Y regarding the view scale. */ 2791f9db2dfe59c33228103c54523281501ef52c9baAngus Kong public void setTranslationY(float transY) { 2808ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mView.setTranslationY(transY * mFilmstrip.mScale); 2811f9db2dfe59c33228103c54523281501ef52c9baAngus Kong } 2821f9db2dfe59c33228103c54523281501ef52c9baAngus Kong 2831f9db2dfe59c33228103c54523281501ef52c9baAngus Kong /** Sets the translation of X regarding the view scale. */ 2841f9db2dfe59c33228103c54523281501ef52c9baAngus Kong public void setTranslationX(float transX) { 2858ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mView.setTranslationX(transX * mFilmstrip.mScale); 2861f9db2dfe59c33228103c54523281501ef52c9baAngus Kong } 2871f9db2dfe59c33228103c54523281501ef52c9baAngus Kong 2881f9db2dfe59c33228103c54523281501ef52c9baAngus Kong /** Forwarding of {@link android.view.View#setAlpha(float)}. */ 2891f9db2dfe59c33228103c54523281501ef52c9baAngus Kong public void setAlpha(float alpha) { 290e7263f7ea45cf31d3948984ba8514e03ef86627ePaul Rohde if (!mLockAtFullOpacity) { 291e7263f7ea45cf31d3948984ba8514e03ef86627ePaul Rohde mView.setAlpha(alpha); 292e7263f7ea45cf31d3948984ba8514e03ef86627ePaul Rohde } 2931f9db2dfe59c33228103c54523281501ef52c9baAngus Kong } 2941f9db2dfe59c33228103c54523281501ef52c9baAngus Kong 2951f9db2dfe59c33228103c54523281501ef52c9baAngus Kong /** Forwarding of {@link android.view.View#getAlpha()}. */ 2961f9db2dfe59c33228103c54523281501ef52c9baAngus Kong public float getAlpha() { 2971f9db2dfe59c33228103c54523281501ef52c9baAngus Kong return mView.getAlpha(); 2981f9db2dfe59c33228103c54523281501ef52c9baAngus Kong } 2991f9db2dfe59c33228103c54523281501ef52c9baAngus Kong 3001f9db2dfe59c33228103c54523281501ef52c9baAngus Kong /** Forwarding of {@link android.view.View#getMeasuredWidth()}. */ 3011f9db2dfe59c33228103c54523281501ef52c9baAngus Kong public int getMeasuredWidth() { 3021f9db2dfe59c33228103c54523281501ef52c9baAngus Kong return mView.getMeasuredWidth(); 30349b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 30449b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 3058de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu /** 3061f9db2dfe59c33228103c54523281501ef52c9baAngus Kong * Animates the X translation of the view. Note: the animated value is 3071f9db2dfe59c33228103c54523281501ef52c9baAngus Kong * not set directly by {@link android.view.View#setTranslationX(float)} 3081f9db2dfe59c33228103c54523281501ef52c9baAngus Kong * because the value might be changed during in {@code onLayout()}. 3091f9db2dfe59c33228103c54523281501ef52c9baAngus Kong * The animated value of X translation is specially handled in {@code 3101f9db2dfe59c33228103c54523281501ef52c9baAngus Kong * layoutIn()}. 3118de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu * 3121f9db2dfe59c33228103c54523281501ef52c9baAngus Kong * @param targetX The final value. 3131f9db2dfe59c33228103c54523281501ef52c9baAngus Kong * @param duration_ms The duration of the animation. 3141f9db2dfe59c33228103c54523281501ef52c9baAngus Kong * @param interpolator Time interpolator. 3158de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu */ 3161f9db2dfe59c33228103c54523281501ef52c9baAngus Kong public void animateTranslationX( 3171f9db2dfe59c33228103c54523281501ef52c9baAngus Kong float targetX, long duration_ms, TimeInterpolator interpolator) { 3181f9db2dfe59c33228103c54523281501ef52c9baAngus Kong if (mTranslationXAnimator == null) { 3191f9db2dfe59c33228103c54523281501ef52c9baAngus Kong mTranslationXAnimator = new ValueAnimator(); 3201f9db2dfe59c33228103c54523281501ef52c9baAngus Kong mTranslationXAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 3211f9db2dfe59c33228103c54523281501ef52c9baAngus Kong @Override 3221f9db2dfe59c33228103c54523281501ef52c9baAngus Kong public void onAnimationUpdate(ValueAnimator valueAnimator) { 3231f9db2dfe59c33228103c54523281501ef52c9baAngus Kong // We invalidate the filmstrip view instead of setting the 3241f9db2dfe59c33228103c54523281501ef52c9baAngus Kong // translation X because the translation X of the view is 3251f9db2dfe59c33228103c54523281501ef52c9baAngus Kong // touched in onLayout(). See the documentation of 3261f9db2dfe59c33228103c54523281501ef52c9baAngus Kong // animateTranslationX(). 3278ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mFilmstrip.invalidate(); 3281f9db2dfe59c33228103c54523281501ef52c9baAngus Kong } 3291f9db2dfe59c33228103c54523281501ef52c9baAngus Kong }); 3301f9db2dfe59c33228103c54523281501ef52c9baAngus Kong } 3311f9db2dfe59c33228103c54523281501ef52c9baAngus Kong runAnimation(mTranslationXAnimator, getTranslationX(), targetX, duration_ms, 3321f9db2dfe59c33228103c54523281501ef52c9baAngus Kong interpolator); 3338de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu } 3348de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu 3358de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu /** 3361f9db2dfe59c33228103c54523281501ef52c9baAngus Kong * Animates the Y translation of the view. 3378de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu * 3381f9db2dfe59c33228103c54523281501ef52c9baAngus Kong * @param targetY The final value. 3391f9db2dfe59c33228103c54523281501ef52c9baAngus Kong * @param duration_ms The duration of the animation. 3401f9db2dfe59c33228103c54523281501ef52c9baAngus Kong * @param interpolator Time interpolator. 3418de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu */ 3421f9db2dfe59c33228103c54523281501ef52c9baAngus Kong public void animateTranslationY( 3431f9db2dfe59c33228103c54523281501ef52c9baAngus Kong float targetY, long duration_ms, TimeInterpolator interpolator) { 3441f9db2dfe59c33228103c54523281501ef52c9baAngus Kong if (mTranslationYAnimator == null) { 3451f9db2dfe59c33228103c54523281501ef52c9baAngus Kong mTranslationYAnimator = new ValueAnimator(); 3461f9db2dfe59c33228103c54523281501ef52c9baAngus Kong mTranslationYAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 3471f9db2dfe59c33228103c54523281501ef52c9baAngus Kong @Override 3481f9db2dfe59c33228103c54523281501ef52c9baAngus Kong public void onAnimationUpdate(ValueAnimator valueAnimator) { 3491f9db2dfe59c33228103c54523281501ef52c9baAngus Kong setTranslationY((Float) valueAnimator.getAnimatedValue()); 3501f9db2dfe59c33228103c54523281501ef52c9baAngus Kong } 3511f9db2dfe59c33228103c54523281501ef52c9baAngus Kong }); 3521f9db2dfe59c33228103c54523281501ef52c9baAngus Kong } 3531f9db2dfe59c33228103c54523281501ef52c9baAngus Kong runAnimation(mTranslationYAnimator, getTranslationY(), targetY, duration_ms, 3541f9db2dfe59c33228103c54523281501ef52c9baAngus Kong interpolator); 3558de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu } 3568de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu 3571f9db2dfe59c33228103c54523281501ef52c9baAngus Kong /** 3581f9db2dfe59c33228103c54523281501ef52c9baAngus Kong * Animates the alpha value of the view. 3591f9db2dfe59c33228103c54523281501ef52c9baAngus Kong * 3601f9db2dfe59c33228103c54523281501ef52c9baAngus Kong * @param targetAlpha The final value. 3611f9db2dfe59c33228103c54523281501ef52c9baAngus Kong * @param duration_ms The duration of the animation. 3621f9db2dfe59c33228103c54523281501ef52c9baAngus Kong * @param interpolator Time interpolator. 3631f9db2dfe59c33228103c54523281501ef52c9baAngus Kong */ 3641f9db2dfe59c33228103c54523281501ef52c9baAngus Kong public void animateAlpha(float targetAlpha, long duration_ms, 3651f9db2dfe59c33228103c54523281501ef52c9baAngus Kong TimeInterpolator interpolator) { 3661f9db2dfe59c33228103c54523281501ef52c9baAngus Kong if (mAlphaAnimator == null) { 3671f9db2dfe59c33228103c54523281501ef52c9baAngus Kong mAlphaAnimator = new ValueAnimator(); 3681f9db2dfe59c33228103c54523281501ef52c9baAngus Kong mAlphaAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 3691f9db2dfe59c33228103c54523281501ef52c9baAngus Kong @Override 3701f9db2dfe59c33228103c54523281501ef52c9baAngus Kong public void onAnimationUpdate(ValueAnimator valueAnimator) { 3711f9db2dfe59c33228103c54523281501ef52c9baAngus Kong ViewItem.this.setAlpha((Float) valueAnimator.getAnimatedValue()); 3721f9db2dfe59c33228103c54523281501ef52c9baAngus Kong } 3731f9db2dfe59c33228103c54523281501ef52c9baAngus Kong }); 3741f9db2dfe59c33228103c54523281501ef52c9baAngus Kong } 3751f9db2dfe59c33228103c54523281501ef52c9baAngus Kong runAnimation(mAlphaAnimator, getAlpha(), targetAlpha, duration_ms, interpolator); 37687f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong } 37787f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong 3781f9db2dfe59c33228103c54523281501ef52c9baAngus Kong private void runAnimation(final ValueAnimator animator, final float startValue, 3791f9db2dfe59c33228103c54523281501ef52c9baAngus Kong final float targetValue, final long duration_ms, 3801f9db2dfe59c33228103c54523281501ef52c9baAngus Kong final TimeInterpolator interpolator) { 3811f9db2dfe59c33228103c54523281501ef52c9baAngus Kong if (startValue == targetValue) { 3821f9db2dfe59c33228103c54523281501ef52c9baAngus Kong return; 3831f9db2dfe59c33228103c54523281501ef52c9baAngus Kong } 3841f9db2dfe59c33228103c54523281501ef52c9baAngus Kong animator.setInterpolator(interpolator); 3851f9db2dfe59c33228103c54523281501ef52c9baAngus Kong animator.setDuration(duration_ms); 3861f9db2dfe59c33228103c54523281501ef52c9baAngus Kong animator.setFloatValues(startValue, targetValue); 3871f9db2dfe59c33228103c54523281501ef52c9baAngus Kong animator.start(); 38849b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 38949b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 3901f9db2dfe59c33228103c54523281501ef52c9baAngus Kong /** Adjusts the translation of X regarding the view scale. */ 3911f9db2dfe59c33228103c54523281501ef52c9baAngus Kong public void translateXScaledBy(float transX) { 3928ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde setTranslationX(getTranslationX() + transX * mFilmstrip.mScale); 393edbba628dc2e31057b304c6a431f44dbca125891Angus Kong } 394edbba628dc2e31057b304c6a431f44dbca125891Angus Kong 3951f9db2dfe59c33228103c54523281501ef52c9baAngus Kong /** 3961f9db2dfe59c33228103c54523281501ef52c9baAngus Kong * Forwarding of {@link android.view.View#getHitRect(android.graphics.Rect)}. 3971f9db2dfe59c33228103c54523281501ef52c9baAngus Kong */ 3981f9db2dfe59c33228103c54523281501ef52c9baAngus Kong public void getHitRect(Rect rect) { 3991f9db2dfe59c33228103c54523281501ef52c9baAngus Kong mView.getHitRect(rect); 4009f02c87cfb5039a72f516ea5edc0378c45ac5779Angus Kong } 4019f02c87cfb5039a72f516ea5edc0378c45ac5779Angus Kong 40249b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong public int getCenterX() { 4037d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong return mLeftPosition + mView.getMeasuredWidth() / 2; 40449b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 40549b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 4061f9db2dfe59c33228103c54523281501ef52c9baAngus Kong /** Forwarding of {@link android.view.View#getVisibility()}. */ 4071f9db2dfe59c33228103c54523281501ef52c9baAngus Kong public int getVisibility() { 4081f9db2dfe59c33228103c54523281501ef52c9baAngus Kong return mView.getVisibility(); 4091f9db2dfe59c33228103c54523281501ef52c9baAngus Kong } 4101f9db2dfe59c33228103c54523281501ef52c9baAngus Kong 4111f9db2dfe59c33228103c54523281501ef52c9baAngus Kong /** Forwarding of {@link android.view.View#setVisibility(int)}. */ 4121f9db2dfe59c33228103c54523281501ef52c9baAngus Kong public void setVisibility(int visibility) { 4131f9db2dfe59c33228103c54523281501ef52c9baAngus Kong mView.setVisibility(visibility); 4141f9db2dfe59c33228103c54523281501ef52c9baAngus Kong } 4151f9db2dfe59c33228103c54523281501ef52c9baAngus Kong 4161f9db2dfe59c33228103c54523281501ef52c9baAngus Kong /** 4171f9db2dfe59c33228103c54523281501ef52c9baAngus Kong * Adds the view of the data to the view hierarchy if necessary. 4181f9db2dfe59c33228103c54523281501ef52c9baAngus Kong */ 4191f9db2dfe59c33228103c54523281501ef52c9baAngus Kong public void addViewToHierarchy() { 4208ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (mFilmstrip.indexOfChild(mView) < 0) { 4218ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mFilmstrip.addView(mView); 4221f9db2dfe59c33228103c54523281501ef52c9baAngus Kong } 4238670da6b3631e82d864e55d36a1ccaf9b2c7a8ceSascha Haeberling 424ec980898dd0dc712a3d6373c06a13f8646a0eebcAlan Newberger // all new views added should not display until layout positions 425ec980898dd0dc712a3d6373c06a13f8646a0eebcAlan Newberger // them and sets them visible 426ec980898dd0dc712a3d6373c06a13f8646a0eebcAlan Newberger setVisibility(View.INVISIBLE); 4278670da6b3631e82d864e55d36a1ccaf9b2c7a8ceSascha Haeberling setAlpha(1f); 4288670da6b3631e82d864e55d36a1ccaf9b2c7a8ceSascha Haeberling setTranslationX(0); 4298670da6b3631e82d864e55d36a1ccaf9b2c7a8ceSascha Haeberling setTranslationY(0); 4301f9db2dfe59c33228103c54523281501ef52c9baAngus Kong } 4311f9db2dfe59c33228103c54523281501ef52c9baAngus Kong 4321f9db2dfe59c33228103c54523281501ef52c9baAngus Kong /** 4335a0be52d3db2398cfe01d18adf779d9e443edf82Alan Newberger * Removes from the hierarchy. 4341f9db2dfe59c33228103c54523281501ef52c9baAngus Kong */ 4355a0be52d3db2398cfe01d18adf779d9e443edf82Alan Newberger public void removeViewFromHierarchy() { 4365a0be52d3db2398cfe01d18adf779d9e443edf82Alan Newberger mFilmstrip.removeView(mView); 4375a0be52d3db2398cfe01d18adf779d9e443edf82Alan Newberger mData.recycle(mView); 4385a0be52d3db2398cfe01d18adf779d9e443edf82Alan Newberger mFilmstrip.recycleView(mView, mIndex); 4391f9db2dfe59c33228103c54523281501ef52c9baAngus Kong } 4401f9db2dfe59c33228103c54523281501ef52c9baAngus Kong 4411f9db2dfe59c33228103c54523281501ef52c9baAngus Kong /** 4421f9db2dfe59c33228103c54523281501ef52c9baAngus Kong * Brings the view to front by 4431f9db2dfe59c33228103c54523281501ef52c9baAngus Kong * {@link #bringChildToFront(android.view.View)} 4441f9db2dfe59c33228103c54523281501ef52c9baAngus Kong */ 4451f9db2dfe59c33228103c54523281501ef52c9baAngus Kong public void bringViewToFront() { 4468ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mFilmstrip.bringChildToFront(mView); 44749b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 44849b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 4498de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu /** 4508de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu * The visual x position of this view, in pixels. 4518de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu */ 4528de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu public float getX() { 4538de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu return mView.getX(); 4548de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu } 4558de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu 4568de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu /** 4578de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu * The visual y position of this view, in pixels. 4588de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu */ 4598de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu public float getY() { 4608de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu return mView.getY(); 4618de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu } 4628de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu 4631f9db2dfe59c33228103c54523281501ef52c9baAngus Kong /** 4641f9db2dfe59c33228103c54523281501ef52c9baAngus Kong * Forwarding of {@link android.view.View#measure(int, int)}. 4651f9db2dfe59c33228103c54523281501ef52c9baAngus Kong */ 4661f9db2dfe59c33228103c54523281501ef52c9baAngus Kong public void measure(int widthSpec, int heightSpec) { 4671f9db2dfe59c33228103c54523281501ef52c9baAngus Kong mView.measure(widthSpec, heightSpec); 4681f9db2dfe59c33228103c54523281501ef52c9baAngus Kong } 4691f9db2dfe59c33228103c54523281501ef52c9baAngus Kong 47049b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong private void layoutAt(int left, int top) { 47149b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong mView.layout(left, top, left + mView.getMeasuredWidth(), 47249b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong top + mView.getMeasuredHeight()); 47349b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 47449b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 4754ff5a1ab360577c6a7ec953f9197778c84c9d334Angus Kong /** 4768de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu * The bounding rect of the view. 4778de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu */ 4788de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu public RectF getViewRect() { 4798de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu RectF r = new RectF(); 4808de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu r.left = mView.getX(); 4818de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu r.top = mView.getY(); 4828de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu r.right = r.left + mView.getWidth() * mView.getScaleX(); 4838de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu r.bottom = r.top + mView.getHeight() * mView.getScaleY(); 4848de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu return r; 4858de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu } 4868de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu 487ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague private View getView() { 488ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague return mView; 489ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague } 490ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague 4918de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu /** 49288ef7664ba6a888fa5da8693091674e152b56192Sascha Haeberling * Layouts the view in the area assuming the center of the area is at a 49388ef7664ba6a888fa5da8693091674e152b56192Sascha Haeberling * specific point of the whole filmstrip. 4944ff5a1ab360577c6a7ec953f9197778c84c9d334Angus Kong * 4954ff5a1ab360577c6a7ec953f9197778c84c9d334Angus Kong * @param drawArea The area when filmstrip will show in. 4964ff5a1ab360577c6a7ec953f9197778c84c9d334Angus Kong * @param refCenter The absolute X coordination in the whole filmstrip 49788ef7664ba6a888fa5da8693091674e152b56192Sascha Haeberling * of the center of {@code drawArea}. 4981f9db2dfe59c33228103c54523281501ef52c9baAngus Kong * @param scale The scale of the view on the filmstrip. 4994ff5a1ab360577c6a7ec953f9197778c84c9d334Angus Kong */ 5001f9db2dfe59c33228103c54523281501ef52c9baAngus Kong public void layoutWithTranslationX(Rect drawArea, int refCenter, float scale) { 5011f9db2dfe59c33228103c54523281501ef52c9baAngus Kong final float translationX = 5021f9db2dfe59c33228103c54523281501ef52c9baAngus Kong ((mTranslationXAnimator != null && mTranslationXAnimator.isRunning()) ? 5031f9db2dfe59c33228103c54523281501ef52c9baAngus Kong (Float) mTranslationXAnimator.getAnimatedValue() : 0); 5041f9db2dfe59c33228103c54523281501ef52c9baAngus Kong int left = 5051f9db2dfe59c33228103c54523281501ef52c9baAngus Kong (int) (drawArea.centerX() + (mLeftPosition - refCenter + translationX) * scale); 50687f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong int top = (int) (drawArea.centerY() - (mView.getMeasuredHeight() / 2) * scale); 50749b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong layoutAt(left, top); 50849b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong mView.setScaleX(scale); 50949b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong mView.setScaleY(scale); 510a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong 511a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong // update mViewArea for touch detection. 512a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong int l = mView.getLeft(); 513a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong int t = mView.getTop(); 514a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong mViewArea.set(l, t, 515f1582c9c075e9cd5790b4bbe1101c94a45ac15d2Angus Kong l + mView.getMeasuredWidth() * scale, 516f1582c9c075e9cd5790b4bbe1101c94a45ac15d2Angus Kong t + mView.getMeasuredHeight() * scale); 517a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong } 518a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong 5194ff5a1ab360577c6a7ec953f9197778c84c9d334Angus Kong /** Returns true if the point is in the view. */ 520a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong public boolean areaContains(float x, float y) { 521a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong return mViewArea.contains(x, y); 52249b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 5238969a67c926608737f3e49f2d2240298372e8416Angus Kong 5248de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu /** 5258de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu * Return the width of the view. 5268de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu */ 5278de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu public int getWidth() { 5288de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu return mView.getWidth(); 5298de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu } 5308de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu 53129d9b3cd08a7b31b8ccecf4792d5ae981faa205cSam Judd /** 53229d9b3cd08a7b31b8ccecf4792d5ae981faa205cSam Judd * Returns the position of the left edge of the view area content is drawn in. 53329d9b3cd08a7b31b8ccecf4792d5ae981faa205cSam Judd */ 53429d9b3cd08a7b31b8ccecf4792d5ae981faa205cSam Judd public int getDrawAreaLeft() { 53529d9b3cd08a7b31b8ccecf4792d5ae981faa205cSam Judd return Math.round(mViewArea.left); 53629d9b3cd08a7b31b8ccecf4792d5ae981faa205cSam Judd } 53729d9b3cd08a7b31b8ccecf4792d5ae981faa205cSam Judd 538121022cb590955e37f1264f77190ce4711159976Doris Liu /** 539280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling * Apply a scale factor (i.e. {@code postScale}) on top of current scale at 540280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling * pivot point ({@code focusX}, {@code focusY}). Visually it should be the 541121022cb590955e37f1264f77190ce4711159976Doris Liu * same as post concatenating current view's matrix with specified scale. 542121022cb590955e37f1264f77190ce4711159976Doris Liu */ 543121022cb590955e37f1264f77190ce4711159976Doris Liu void postScale(float focusX, float focusY, float postScale, int viewportWidth, 544280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling int viewportHeight) { 5451f9db2dfe59c33228103c54523281501ef52c9baAngus Kong float transX = mView.getTranslationX(); 5461f9db2dfe59c33228103c54523281501ef52c9baAngus Kong float transY = mView.getTranslationY(); 547121022cb590955e37f1264f77190ce4711159976Doris Liu // Pivot point is top left of the view, so we need to translate 548121022cb590955e37f1264f77190ce4711159976Doris Liu // to scale around focus point 549121022cb590955e37f1264f77190ce4711159976Doris Liu transX -= (focusX - getX()) * (postScale - 1f); 550121022cb590955e37f1264f77190ce4711159976Doris Liu transY -= (focusY - getY()) * (postScale - 1f); 551121022cb590955e37f1264f77190ce4711159976Doris Liu float scaleX = mView.getScaleX() * postScale; 552121022cb590955e37f1264f77190ce4711159976Doris Liu float scaleY = mView.getScaleY() * postScale; 553121022cb590955e37f1264f77190ce4711159976Doris Liu updateTransform(transX, transY, scaleX, scaleY, viewportWidth, 554121022cb590955e37f1264f77190ce4711159976Doris Liu viewportHeight); 555121022cb590955e37f1264f77190ce4711159976Doris Liu } 5568de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu 5578de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu void updateTransform(float transX, float transY, float scaleX, float scaleY, 558280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling int viewportWidth, int viewportHeight) { 559121022cb590955e37f1264f77190ce4711159976Doris Liu float left = transX + mView.getLeft(); 560121022cb590955e37f1264f77190ce4711159976Doris Liu float top = transY + mView.getTop(); 561121022cb590955e37f1264f77190ce4711159976Doris Liu RectF r = ZoomView.adjustToFitInBounds(new RectF(left, top, 562121022cb590955e37f1264f77190ce4711159976Doris Liu left + mView.getWidth() * scaleX, 563121022cb590955e37f1264f77190ce4711159976Doris Liu top + mView.getHeight() * scaleY), 5648de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu viewportWidth, viewportHeight); 5658de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu mView.setScaleX(scaleX); 5668de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu mView.setScaleY(scaleY); 5678de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu transX = r.left - mView.getLeft(); 5688de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu transY = r.top - mView.getTop(); 5698de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu mView.setTranslationX(transX); 5708de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu mView.setTranslationY(transY); 5718de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu } 5728de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu 573f9ddb6034e560684e4d3ddd460ef9dff345e4e91Doris Liu void resetTransform() { 574f9ddb6034e560684e4d3ddd460ef9dff345e4e91Doris Liu mView.setScaleX(FULL_SCREEN_SCALE); 575f9ddb6034e560684e4d3ddd460ef9dff345e4e91Doris Liu mView.setScaleY(FULL_SCREEN_SCALE); 576f9ddb6034e560684e4d3ddd460ef9dff345e4e91Doris Liu mView.setTranslationX(0f); 577f9ddb6034e560684e4d3ddd460ef9dff345e4e91Doris Liu mView.setTranslationY(0f); 578f9ddb6034e560684e4d3ddd460ef9dff345e4e91Doris Liu } 579f1582c9c075e9cd5790b4bbe1101c94a45ac15d2Angus Kong 580f1582c9c075e9cd5790b4bbe1101c94a45ac15d2Angus Kong @Override 581f1582c9c075e9cd5790b4bbe1101c94a45ac15d2Angus Kong public String toString() { 5828ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde return "AdapterIndex = " + mIndex + "\n\t left = " + mLeftPosition 583f1582c9c075e9cd5790b4bbe1101c94a45ac15d2Angus Kong + "\n\t viewArea = " + mViewArea 584f1582c9c075e9cd5790b4bbe1101c94a45ac15d2Angus Kong + "\n\t centerX = " + getCenterX() 585f1582c9c075e9cd5790b4bbe1101c94a45ac15d2Angus Kong + "\n\t view MeasuredSize = " 586f1582c9c075e9cd5790b4bbe1101c94a45ac15d2Angus Kong + mView.getMeasuredWidth() + ',' + mView.getMeasuredHeight() 587f1582c9c075e9cd5790b4bbe1101c94a45ac15d2Angus Kong + "\n\t view Size = " + mView.getWidth() + ',' + mView.getHeight() 588f1582c9c075e9cd5790b4bbe1101c94a45ac15d2Angus Kong + "\n\t view scale = " + mView.getScaleX(); 589f1582c9c075e9cd5790b4bbe1101c94a45ac15d2Angus Kong } 59049b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 59149b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 592628481532e1e58a0a26330d238e850aec5657bceAngus Kong /** Constructor. */ 593628481532e1e58a0a26330d238e850aec5657bceAngus Kong public FilmstripView(Context context) { 59449b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong super(context); 59588ef7664ba6a888fa5da8693091674e152b56192Sascha Haeberling init((CameraActivity) context); 59649b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 59749b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 5988e5e4eedb25a4589342660b928935acca4375fc7Angus Kong /** Constructor. */ 599628481532e1e58a0a26330d238e850aec5657bceAngus Kong public FilmstripView(Context context, AttributeSet attrs) { 60049b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong super(context, attrs); 60188ef7664ba6a888fa5da8693091674e152b56192Sascha Haeberling init((CameraActivity) context); 60249b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 60349b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 6048e5e4eedb25a4589342660b928935acca4375fc7Angus Kong /** Constructor. */ 605628481532e1e58a0a26330d238e850aec5657bceAngus Kong public FilmstripView(Context context, AttributeSet attrs, int defStyle) { 60649b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong super(context, attrs, defStyle); 60788ef7664ba6a888fa5da8693091674e152b56192Sascha Haeberling init((CameraActivity) context); 60849b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 60949b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 61088ef7664ba6a888fa5da8693091674e152b56192Sascha Haeberling private void init(CameraActivity cameraActivity) { 61149b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong setWillNotDraw(false); 61288ef7664ba6a888fa5da8693091674e152b56192Sascha Haeberling mActivity = cameraActivity; 6138ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mVideoClickedCallback = new PlayVideoIntent(mActivity); 61449b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong mScale = 1.0f; 6158ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mAdapterIndexUserIsScrollingOver = 0; 6168ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mController = new FilmstripControllerImpl(); 617a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong mViewAnimInterpolator = new DecelerateInterpolator(); 6188de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu mZoomView = new ZoomView(cameraActivity); 6198de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu mZoomView.setVisibility(GONE); 6208de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu addView(mZoomView); 6218de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu 6228ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mGestureListener = new FilmstripGestures(); 62349b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong mGestureRecognizer = 624166e36fb6e04d40a1bef0459ee6b96c9c736039bAngus Kong new FilmstripGestureRecognizer(cameraActivity, mGestureListener); 625fb57df15a87f95ce8b2f861e54d960602912e03cDoris Liu mSlop = (int) getContext().getResources().getDimension(R.dimen.pie_touch_slop); 6263179f6a49516833761be5155c4e1244ac0aa17feDoris Liu DisplayMetrics metrics = new DisplayMetrics(); 6273179f6a49516833761be5155c4e1244ac0aa17feDoris Liu mActivity.getWindowManager().getDefaultDisplay().getMetrics(metrics); 6283179f6a49516833761be5155c4e1244ac0aa17feDoris Liu // Allow over scaling because on high density screens, pixels are too 6293179f6a49516833761be5155c4e1244ac0aa17feDoris Liu // tiny to clearly see the details at 1:1 zoom. We should not scale 6303179f6a49516833761be5155c4e1244ac0aa17feDoris Liu // beyond what 1:1 would look like on a medium density screen, as 6313179f6a49516833761be5155c4e1244ac0aa17feDoris Liu // scaling beyond that would only yield blur. 632caca8c7b2e97bd76e4df1ea98c08acaa48b21557Andy Huibers mOverScaleFactor = (float) metrics.densityDpi / (float) DisplayMetrics.DENSITY_HIGH; 6333179f6a49516833761be5155c4e1244ac0aa17feDoris Liu if (mOverScaleFactor < 1f) { 6343179f6a49516833761be5155c4e1244ac0aa17feDoris Liu mOverScaleFactor = 1f; 6353179f6a49516833761be5155c4e1244ac0aa17feDoris Liu } 6365c92c9ec5e21a57646d6eca4360c0f6bb141a237Spike Sprague 637ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague setAccessibilityDelegate(new AccessibilityDelegate() { 638ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague @Override 639ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { 640ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague super.onInitializeAccessibilityNodeInfo(host, info); 641ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague 642ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague info.setClassName(FilmstripView.class.getName()); 643ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague info.setScrollable(true); 644ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD); 645ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD); 646ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague } 647ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague 648ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague @Override 649ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague public boolean performAccessibilityAction(View host, int action, Bundle args) { 650ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague if (!mController.isScrolling()) { 651ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague switch (action) { 652ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: { 653ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague mController.goToNextItem(); 654ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague return true; 655ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague } 656ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: { 657ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague boolean wentToPrevious = mController.goToPreviousItem(); 658ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague if (!wentToPrevious) { 659ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague // at beginning of filmstrip, hide and go back to preview 660ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague mActivity.getCameraAppUI().hideFilmstrip(); 661ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague } 662ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague return true; 663ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague } 664ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { 665ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague // Prevent the view group itself from being selected. 666ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague // Instead, select the item in the center 6678ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde final ViewItem currentItem = mViewItems[BUFFER_CENTER]; 668ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague currentItem.getView().performAccessibilityAction(action, args); 669ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague return true; 670ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague } 671ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague } 672ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague } 673ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague return super.performAccessibilityAction(host, action, args); 674ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague } 675ae5fa1499ab1d6d1d421228859d13ac45ad1d437Spike Sprague }); 67649b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 67749b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 6788ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde private void recycleView(View view, int index) { 6795a0be52d3db2398cfe01d18adf779d9e443edf82Alan Newberger Log.v(TAG, "recycleView"); 680b7d0a227fb0f842135dbc92a7e15c571f0e1a946Spike Sprague final int viewType = (Integer) view.getTag(R.id.mediadata_tag_viewtype); 681bb3b39b13a7097a55e585e8d6197057500847708Spike Sprague if (viewType > 0) { 682bb3b39b13a7097a55e585e8d6197057500847708Spike Sprague Queue<View> recycledViewsForType = recycledViews.get(viewType); 683bb3b39b13a7097a55e585e8d6197057500847708Spike Sprague if (recycledViewsForType == null) { 684bb3b39b13a7097a55e585e8d6197057500847708Spike Sprague recycledViewsForType = new ArrayDeque<View>(); 685bb3b39b13a7097a55e585e8d6197057500847708Spike Sprague recycledViews.put(viewType, recycledViewsForType); 686bb3b39b13a7097a55e585e8d6197057500847708Spike Sprague } 687bb3b39b13a7097a55e585e8d6197057500847708Spike Sprague recycledViewsForType.offer(view); 68843bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd } 68943bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd } 69043bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd 6918ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde private View getRecycledView(int index) { 6928ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde final int viewType = mDataAdapter.getItemViewType(index); 69343bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd Queue<View> recycledViewsForType = recycledViews.get(viewType); 6948ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde View view = null; 69543bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd if (recycledViewsForType != null) { 6968ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde view = recycledViewsForType.poll(); 69743bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd } 6988ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (view != null) { 6998ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde view.setVisibility(View.GONE); 700987ee64612e2510004fdf08536746c87234d01c1Paul Rohde } 7015a0be52d3db2398cfe01d18adf779d9e443edf82Alan Newberger Log.v(TAG, "getRecycledView, recycled=" + (view != null)); 7028ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde return view; 70343bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd } 70443bf03f6e7f9a71b7553e7282b5799798997caf7Sam Judd 7058e5e4eedb25a4589342660b928935acca4375fc7Angus Kong /** 7068e5e4eedb25a4589342660b928935acca4375fc7Angus Kong * Returns the controller. 7078e5e4eedb25a4589342660b928935acca4375fc7Angus Kong * 7088e5e4eedb25a4589342660b928935acca4375fc7Angus Kong * @return The {@code Controller}. 7098e5e4eedb25a4589342660b928935acca4375fc7Angus Kong */ 710628481532e1e58a0a26330d238e850aec5657bceAngus Kong public FilmstripController getController() { 7116d23f4c77fde7ddf70e0edd48f46cc22b7f7320eAngus Kong return mController; 7126d23f4c77fde7ddf70e0edd48f46cc22b7f7320eAngus Kong } 7136d23f4c77fde7ddf70e0edd48f46cc22b7f7320eAngus Kong 71429d9b3cd08a7b31b8ccecf4792d5ae981faa205cSam Judd /** 71529d9b3cd08a7b31b8ccecf4792d5ae981faa205cSam Judd * Returns the draw area width of the current item. 71629d9b3cd08a7b31b8ccecf4792d5ae981faa205cSam Judd */ 71729d9b3cd08a7b31b8ccecf4792d5ae981faa205cSam Judd public int getCurrentItemLeft() { 7188ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde return mViewItems[BUFFER_CENTER].getDrawAreaLeft(); 71929d9b3cd08a7b31b8ccecf4792d5ae981faa205cSam Judd } 72029d9b3cd08a7b31b8ccecf4792d5ae981faa205cSam Judd 72101054e922aa547b937a71131ad04c6bd15356240Angus Kong private void setListener(FilmstripController.FilmstripListener l) { 72287f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong mListener = l; 72387f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong } 72487f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong 725628481532e1e58a0a26330d238e850aec5657bceAngus Kong private void setViewGap(int viewGap) { 726faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong mViewGapInPixel = viewGap; 727e78541f2edf2f02660c34660114e76d53b32ab8bAngus Kong } 728e78541f2edf2f02660c34660114e76d53b32ab8bAngus Kong 72917e669d695ef2a38d28d5ba2512937836293e9caAngus Kong /** 730c8924b2ec3788ca6d0f0af5ca749e5fe7be125ceAndy Huibers * Called after current item or zoom level has changed. 731c8924b2ec3788ca6d0f0af5ca749e5fe7be125ceAndy Huibers */ 732c8924b2ec3788ca6d0f0af5ca749e5fe7be125ceAndy Huibers public void zoomAtIndexChanged() { 7338ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (mViewItems[BUFFER_CENTER] == null) { 734c17a56643186dee671bf6e7dec54cd558a7ecb2fSascha Haeberling return; 735c17a56643186dee671bf6e7dec54cd558a7ecb2fSascha Haeberling } 7368ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde int index = mViewItems[BUFFER_CENTER].getAdapterIndex(); 7378ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mListener.onZoomAtIndexChanged(index, mScale); 738c8924b2ec3788ca6d0f0af5ca749e5fe7be125ceAndy Huibers } 739c8924b2ec3788ca6d0f0af5ca749e5fe7be125ceAndy Huibers 740c8924b2ec3788ca6d0f0af5ca749e5fe7be125ceAndy Huibers /** 74117e669d695ef2a38d28d5ba2512937836293e9caAngus Kong * Checks if the data is at the center. 74217e669d695ef2a38d28d5ba2512937836293e9caAngus Kong * 7438ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde * @param index The index of the item in the data adapter to check. 74417e669d695ef2a38d28d5ba2512937836293e9caAngus Kong * @return {@code True} if the data is currently at the center. 74517e669d695ef2a38d28d5ba2512937836293e9caAngus Kong */ 7468ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde private boolean isItemAtIndexCentered(int index) { 7478ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (mViewItems[BUFFER_CENTER] == null) { 7483d0b691b8f7a844093e8de9267ffa2ce16d0c5a9Angus Kong return false; 7493d0b691b8f7a844093e8de9267ffa2ce16d0c5a9Angus Kong } 7508ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (mViewItems[BUFFER_CENTER].getAdapterIndex() == index 751ec2fb473c094f8dfd1cc0cf5205d470e412d3919Angus Kong && isCurrentItemCentered()) { 75249b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong return true; 75349b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 75449b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong return false; 75549b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 75649b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 757653c43be6e58be54cf2ac3c8efb2d65ac20bd03bAngus Kong private void measureViewItem(ViewItem item, int boundWidth, int boundHeight) { 7588ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde int index = item.getAdapterIndex(); 7598ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde FilmstripItem imageData = mDataAdapter.getFilmstripItemAt(index); 76001054e922aa547b937a71131ad04c6bd15356240Angus Kong if (imageData == null) { 761c14b6ba434575b7d795a8cd681821f86a39bc371Paul Rohde Log.w(TAG, "measureViewItem() - Trying to measure a null item!"); 762f9ef1ae9d31977c106eefc7ab1a74158bcdcfd39Erin Dahlgren return; 763f9ef1ae9d31977c106eefc7ab1a74158bcdcfd39Erin Dahlgren } 764f9ef1ae9d31977c106eefc7ab1a74158bcdcfd39Erin Dahlgren 7658ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde Point dim = CameraUtil.resizeToFill( 76651cafa0a35546a42c573357aa7a031a79cf9ba1bAlan Newberger imageData.getDimensions().getWidth(), 76751cafa0a35546a42c573357aa7a031a79cf9ba1bAlan Newberger imageData.getDimensions().getHeight(), 76851cafa0a35546a42c573357aa7a031a79cf9ba1bAlan Newberger imageData.getOrientation(), 7698ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde boundWidth, 7708ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde boundHeight); 771653c43be6e58be54cf2ac3c8efb2d65ac20bd03bAngus Kong 772c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong item.measure(MeasureSpec.makeMeasureSpec(dim.x, MeasureSpec.EXACTLY), 773c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong MeasureSpec.makeMeasureSpec(dim.y, MeasureSpec.EXACTLY)); 774653c43be6e58be54cf2ac3c8efb2d65ac20bd03bAngus Kong } 775653c43be6e58be54cf2ac3c8efb2d65ac20bd03bAngus Kong 77649b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong @Override 77749b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 77849b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong super.onMeasure(widthMeasureSpec, heightMeasureSpec); 77949b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 78049b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong int boundWidth = MeasureSpec.getSize(widthMeasureSpec); 78149b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong int boundHeight = MeasureSpec.getSize(heightMeasureSpec); 782b477b42906a3f8b299ddaeede3940e6344fb6825Angus Kong if (boundWidth == 0 || boundHeight == 0) { 783b477b42906a3f8b299ddaeede3940e6344fb6825Angus Kong // Either width or height is unknown, can't measure children yet. 784b477b42906a3f8b299ddaeede3940e6344fb6825Angus Kong return; 785b477b42906a3f8b299ddaeede3940e6344fb6825Angus Kong } 786b477b42906a3f8b299ddaeede3940e6344fb6825Angus Kong 7878ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde for (ViewItem item : mViewItems) { 788653c43be6e58be54cf2ac3c8efb2d65ac20bd03bAngus Kong if (item != null) { 789653c43be6e58be54cf2ac3c8efb2d65ac20bd03bAngus Kong measureViewItem(item, boundWidth, boundHeight); 79088ef7664ba6a888fa5da8693091674e152b56192Sascha Haeberling } 79149b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 7927d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong clampCenterX(); 7938de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu // Measure zoom view 794c02b13af4c44fe23d4a563d3c2df1ca50e44affcAngus Kong mZoomView.measure(MeasureSpec.makeMeasureSpec(widthMeasureSpec, MeasureSpec.EXACTLY), 795c02b13af4c44fe23d4a563d3c2df1ca50e44affcAngus Kong MeasureSpec.makeMeasureSpec(heightMeasureSpec, MeasureSpec.EXACTLY)); 79649b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 79749b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 7988ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde private int findTheNearestView(int viewX) { 79949b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong int nearest = 0; 8008969a67c926608737f3e49f2d2240298372e8416Angus Kong // Find the first non-null ViewItem. 801f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling while (nearest < BUFFER_SIZE 8028ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde && (mViewItems[nearest] == null || mViewItems[nearest].getLeftPosition() == -1)) { 803f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling nearest++; 804f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling } 8058969a67c926608737f3e49f2d2240298372e8416Angus Kong // No existing available ViewItem 806f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling if (nearest == BUFFER_SIZE) { 807f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling return -1; 808f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling } 8093044d8c577432d6e9721fc8b26ac2afbbaf21266Erin Dahlgren 8108ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde int min = Math.abs(viewX - mViewItems[nearest].getCenterX()); 81149b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 8128ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde for (int i = nearest + 1; i < BUFFER_SIZE && mViewItems[i] != null; i++) { 813f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling // Not measured yet. 8148ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (mViewItems[i].getLeftPosition() == -1) { 815f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling continue; 8163f192ccf03d0d25521b96304c4464b4bad28150aSascha Haeberling } 81749b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 8188ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde int centerX = mViewItems[i].getCenterX(); 8198ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde int dist = Math.abs(viewX - centerX); 82049b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong if (dist < min) { 82149b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong min = dist; 8228ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde nearest = i; 82349b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 82449b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 82549b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong return nearest; 82649b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 82749b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 8288ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde private ViewItem buildViewItemAt(int index) { 829281624c713fb29d4be690fc980d2001efcf20dafAlan Newberger if (mActivity.isDestroyed()) { 830281624c713fb29d4be690fc980d2001efcf20dafAlan Newberger // Loading item data is call from multiple AsyncTasks and the 8318ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde // activity may be finished when buildViewItemAt is called. 832281624c713fb29d4be690fc980d2001efcf20dafAlan Newberger Log.d(TAG, "Activity destroyed, don't load data"); 833281624c713fb29d4be690fc980d2001efcf20dafAlan Newberger return null; 834281624c713fb29d4be690fc980d2001efcf20dafAlan Newberger } 8358ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde FilmstripItem data = mDataAdapter.getFilmstripItemAt(index); 836f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling if (data == null) { 837f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling return null; 838f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling } 839caca8c7b2e97bd76e4df1ea98c08acaa48b21557Andy Huibers 840a62ed04fc1af31c1fdfa0e9ac9cc0acfec1b1f12Alan Newberger // Always scale by fixed filmstrip scale, since we only show items when 841a62ed04fc1af31c1fdfa0e9ac9cc0acfec1b1f12Alan Newberger // in filmstrip. Preloading images with a different scale and bounds 842a62ed04fc1af31c1fdfa0e9ac9cc0acfec1b1f12Alan Newberger // interferes with caching. 84377d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde int width = Math.round(FULL_SCREEN_SCALE * getWidth()); 84477d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde int height = Math.round(FULL_SCREEN_SCALE * getHeight()); 84577d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde 846a62ed04fc1af31c1fdfa0e9ac9cc0acfec1b1f12Alan Newberger Log.v(TAG, "suggesting item bounds: " + width + "x" + height); 8474021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd mDataAdapter.suggestViewSizeBound(width, height); 8484021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd 8498ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde View recycled = getRecycledView(index); 85077d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde View v = mDataAdapter.getView(recycled, index, mVideoClickedCallback); 851f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling if (v == null) { 852f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling return null; 853f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling } 8548ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde ViewItem item = new ViewItem(index, v, data, this); 8551f9db2dfe59c33228103c54523281501ef52c9baAngus Kong item.addViewToHierarchy(); 8568969a67c926608737f3e49f2d2240298372e8416Angus Kong return item; 85749b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 85849b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 85977d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde private void renderFullRes(int bufferIndex) { 8608ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde ViewItem item = mViewItems[bufferIndex]; 86177d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde if (item == null) { 862caca8c7b2e97bd76e4df1ea98c08acaa48b21557Andy Huibers return; 8638ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde } 86477d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde 86577d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde item.renderFullRes(); 86677d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde } 86777d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde 86877d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde private void renderThumbnail(int bufferIndex) { 86977d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde ViewItem item = mViewItems[bufferIndex]; 87077d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde if (item == null) { 87177d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde return; 87277d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde } 87377d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde 87477d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde item.renderThumbnail(); 875caca8c7b2e97bd76e4df1ea98c08acaa48b21557Andy Huibers } 876caca8c7b2e97bd76e4df1ea98c08acaa48b21557Andy Huibers 87777d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde private void renderAllThumbnails() { 8788ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde for(int i = 0; i < BUFFER_SIZE; i++) { 87977d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde renderThumbnail(i); 8808ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde } 8818ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde } 8828ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde 8838ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde private void removeItem(int bufferIndex) { 8848ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (bufferIndex >= mViewItems.length || mViewItems[bufferIndex] == null) { 885f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling return; 886f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling } 8878ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde FilmstripItem data = mDataAdapter.getFilmstripItemAt( 8888ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mViewItems[bufferIndex].getAdapterIndex()); 889f9ef1ae9d31977c106eefc7ab1a74158bcdcfd39Erin Dahlgren if (data == null) { 890c14b6ba434575b7d795a8cd681821f86a39bc371Paul Rohde Log.w(TAG, "removeItem() - Trying to remove a null item!"); 891f9ef1ae9d31977c106eefc7ab1a74158bcdcfd39Erin Dahlgren return; 892f9ef1ae9d31977c106eefc7ab1a74158bcdcfd39Erin Dahlgren } 8935a0be52d3db2398cfe01d18adf779d9e443edf82Alan Newberger mViewItems[bufferIndex].removeViewFromHierarchy(); 8948ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mViewItems[bufferIndex] = null; 895750e8ec8af168afd318d47082b326b95f1cca517Angus Kong } 896750e8ec8af168afd318d47082b326b95f1cca517Angus Kong 897f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling /** 898f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling * We try to keep the one closest to the center of the screen at position 8998ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde * BUFFER_CENTER. 900f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling */ 90149b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong private void stepIfNeeded() { 902628481532e1e58a0a26330d238e850aec5657bceAngus Kong if (!inFilmstrip() && !inFullScreen()) { 903f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling // The good timing to step to the next view is when everything is 90437f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberling // not in transition. 905a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong return; 906a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong } 9078ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde final int nearestBufferIndex = findTheNearestView(mCenterX); 9088ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde // if the nearest view is the current view, or there is no nearest 9098ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde // view, then we do not need to adjust the view buffers. 9108ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (nearestBufferIndex == -1 || nearestBufferIndex == BUFFER_CENTER) { 911f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling return; 91253aedc0ee671c2d11341a66c444bbb6cdc97b150Angus Kong } 9138ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde int prevIndex = (mViewItems[BUFFER_CENTER] == null ? -1 : 9148ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mViewItems[BUFFER_CENTER].getAdapterIndex()); 9158ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde final int adjust = nearestBufferIndex - BUFFER_CENTER; 91649b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong if (adjust > 0) { 9178ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde // Remove from beginning of the buffer. 91849b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong for (int k = 0; k < adjust; k++) { 9198969a67c926608737f3e49f2d2240298372e8416Angus Kong removeItem(k); 92049b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 9218ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde // Shift items inside the buffer 92249b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong for (int k = 0; k + adjust < BUFFER_SIZE; k++) { 9238ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mViewItems[k] = mViewItems[k + adjust]; 92449b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 9258ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde // Fill the end with new items. 92649b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong for (int k = BUFFER_SIZE - adjust; k < BUFFER_SIZE; k++) { 9278ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mViewItems[k] = null; 9288ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (mViewItems[k - 1] != null) { 9298ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mViewItems[k] = buildViewItemAt(mViewItems[k - 1].getAdapterIndex() + 1); 930750e8ec8af168afd318d47082b326b95f1cca517Angus Kong } 93149b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 93253aedc0ee671c2d11341a66c444bbb6cdc97b150Angus Kong adjustChildZOrder(); 93349b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } else { 9348ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde // Remove from the end of the buffer 93549b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong for (int k = BUFFER_SIZE - 1; k >= BUFFER_SIZE + adjust; k--) { 9368969a67c926608737f3e49f2d2240298372e8416Angus Kong removeItem(k); 93749b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 9388ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde // Shift items inside the buffer 93949b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong for (int k = BUFFER_SIZE - 1; k + adjust >= 0; k--) { 9408ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mViewItems[k] = mViewItems[k + adjust]; 94149b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 9428ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde // Fill the beginning with new items. 94349b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong for (int k = -1 - adjust; k >= 0; k--) { 9448ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mViewItems[k] = null; 9458ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (mViewItems[k + 1] != null) { 9468ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mViewItems[k] = buildViewItemAt(mViewItems[k + 1].getAdapterIndex() - 1); 947750e8ec8af168afd318d47082b326b95f1cca517Angus Kong } 94849b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 94949b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 95053aedc0ee671c2d11341a66c444bbb6cdc97b150Angus Kong invalidate(); 95137f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberling if (mListener != null) { 9528ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mListener.onDataFocusChanged(prevIndex, mViewItems[BUFFER_CENTER] 9538ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde .getAdapterIndex()); 9548ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde final int firstVisible = mViewItems[BUFFER_CENTER].getAdapterIndex() - 2; 955de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd final int visibleItemCount = firstVisible + BUFFER_SIZE; 956de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd final int totalItemCount = mDataAdapter.getTotalNumber(); 957de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd mListener.onScroll(firstVisible, visibleItemCount, totalItemCount); 95837f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberling } 959c8924b2ec3788ca6d0f0af5ca749e5fe7be125ceAndy Huibers zoomAtIndexChanged(); 96049b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 96149b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 9627d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong /** 963280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling * Check the bounds of {@code mCenterX}. Always call this function after: 1. 964280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling * Any changes to {@code mCenterX}. 2. Any size change of the view items. 9651f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong * 9661f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong * @return Whether clamp happened. 9677d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong */ 9681f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong private boolean clampCenterX() { 9698ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde ViewItem currentItem = mViewItems[BUFFER_CENTER]; 9708ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (currentItem == null) { 9711f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong return false; 972f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling } 97349b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 9745fbe134c3cf1f7c2c82ccef223cab7eb43cd92f1Angus Kong boolean stopScroll = false; 97586f1d1f3664c909d1d949951056c7bb1e9627324Alan Newberger if (currentItem.getAdapterIndex() == 0 && mCenterX < currentItem.getCenterX()) { 97686f1d1f3664c909d1d949951056c7bb1e9627324Alan Newberger // Stop at the first ViewItem. 9777d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong stopScroll = true; 97886f1d1f3664c909d1d949951056c7bb1e9627324Alan Newberger } else if (currentItem.getAdapterIndex() == mDataAdapter.getTotalNumber() - 1 9798ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde && mCenterX > currentItem.getCenterX()) { 9805fbe134c3cf1f7c2c82ccef223cab7eb43cd92f1Angus Kong // Stop at the end. 9815fbe134c3cf1f7c2c82ccef223cab7eb43cd92f1Angus Kong stopScroll = true; 9825fbe134c3cf1f7c2c82ccef223cab7eb43cd92f1Angus Kong } 9835fbe134c3cf1f7c2c82ccef223cab7eb43cd92f1Angus Kong 9847d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong if (stopScroll) { 9858ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mCenterX = currentItem.getCenterX(); 98649b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 9873044d8c577432d6e9721fc8b26ac2afbbaf21266Erin Dahlgren 9881f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong return stopScroll; 98949b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 99049b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 99153aedc0ee671c2d11341a66c444bbb6cdc97b150Angus Kong /** 9928ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde * Reorders the child views to be consistent with their index. This method 993280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling * should be called after adding/removing views. 99453aedc0ee671c2d11341a66c444bbb6cdc97b150Angus Kong */ 995a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong private void adjustChildZOrder() { 996a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong for (int i = BUFFER_SIZE - 1; i >= 0; i--) { 9978ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (mViewItems[i] == null) { 998f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling continue; 9993f192ccf03d0d25521b96304c4464b4bad28150aSascha Haeberling } 10008ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mViewItems[i].bringViewToFront(); 1001a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong } 1002d70b22919f8d212bf11abd6e6724b3a395ef02c1Alan Newberger // ZoomView is a special case to always be in the front. 1003563a289f1aed4dd7bf760959851ff6ad72c7627fAngus Kong bringChildToFront(mZoomView); 1004a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong } 1005a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong 1006f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling /** 10078ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde * Returns the index of the current item, or -1 if there is no data. 1008c02b13af4c44fe23d4a563d3c2df1ca50e44affcAngus Kong */ 10098ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde private int getCurrentItemAdapterIndex() { 10108ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde ViewItem current = mViewItems[BUFFER_CENTER]; 1011f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling if (current == null) { 1012f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling return -1; 1013f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling } 10148ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde return current.getAdapterIndex(); 1015f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling } 1016f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling 1017f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling /** 1018280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling * Keep the current item in the center. This functions does not check if the 1019280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling * current item is null. 10207d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong */ 10218ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde private void scrollCurrentItemToCenter() { 10228ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde final ViewItem currItem = mViewItems[BUFFER_CENTER]; 1023ec2fb473c094f8dfd1cc0cf5205d470e412d3919Angus Kong if (currItem == null) { 1024ec2fb473c094f8dfd1cc0cf5205d470e412d3919Angus Kong return; 1025ec2fb473c094f8dfd1cc0cf5205d470e412d3919Angus Kong } 1026ec2fb473c094f8dfd1cc0cf5205d470e412d3919Angus Kong final int currentViewCenter = currItem.getCenterX(); 10277d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong if (mController.isScrolling() || mIsUserScrolling 1028ec2fb473c094f8dfd1cc0cf5205d470e412d3919Angus Kong || isCurrentItemCentered()) { 10298d3552d334196a09e20c83a5296f0b373041032cPaul Rohde Log.d(TAG, "[fling] mController.isScrolling() - " + mController.isScrolling()); 103047721fa8f2dc13cb565ae5629a417dc4ed298e81Angus Kong return; 103147721fa8f2dc13cb565ae5629a417dc4ed298e81Angus Kong } 10327d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong 10337d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong int snapInTime = (int) (SNAP_IN_CENTER_TIME_MS 10347d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong * ((float) Math.abs(mCenterX - currentViewCenter)) 1035280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling / mDrawArea.width()); 10368ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde 1037c14b6ba434575b7d795a8cd681821f86a39bc371Paul Rohde Log.d(TAG, "[fling] Scroll to center."); 10387d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong mController.scrollToPosition(currentViewCenter, 10398ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde snapInTime, false); 104047721fa8f2dc13cb565ae5629a417dc4ed298e81Angus Kong } 104147721fa8f2dc13cb565ae5629a417dc4ed298e81Angus Kong 104280af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong /** 104380af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong * Translates the {@link ViewItem} on the left of the current one to match 104480af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong * the full-screen layout. In full-screen, we show only one {@link ViewItem} 104580af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong * which occupies the whole screen. The other left ones are put on the left 1046d028dd4908e68c7d4d0e7438efa74fa2c67e5f2aAngus Kong * side in full scales. Does nothing if there's no next item. 104780af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong * 10488ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde * @param index The index of the current one to be translated. 104980af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong * @param drawAreaWidth The width of the current draw area. 105080af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong * @param scaleFraction A {@code float} between 0 and 1. 0 if the current 10511f9db2dfe59c33228103c54523281501ef52c9baAngus Kong * scale is {@code FILM_STRIP_SCALE}. 1 if the current scale is 10521f9db2dfe59c33228103c54523281501ef52c9baAngus Kong * {@code FULL_SCREEN_SCALE}. 105380af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong */ 105480af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong private void translateLeftViewItem( 10558ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde int index, int drawAreaWidth, float scaleFraction) { 10568ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (index < 0 || index > BUFFER_SIZE - 1) { 1057c14b6ba434575b7d795a8cd681821f86a39bc371Paul Rohde Log.w(TAG, "translateLeftViewItem() - Index out of bound!"); 105880af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong return; 105980af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong } 106080af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong 10618ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde final ViewItem curr = mViewItems[index]; 10628ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde final ViewItem next = mViewItems[index + 1]; 106380af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong if (curr == null || next == null) { 1064c14b6ba434575b7d795a8cd681821f86a39bc371Paul Rohde Log.w(TAG, "translateLeftViewItem() - Invalid view item (curr or next == null). curr = " 10658ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde + index); 106680af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong return; 106780af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong } 106880af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong 106980af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong final int currCenterX = curr.getCenterX(); 107080af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong final int nextCenterX = next.getCenterX(); 107180af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong final int translate = (int) ((nextCenterX - drawAreaWidth 1072280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling - currCenterX) * scaleFraction); 107380af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong 10741f9db2dfe59c33228103c54523281501ef52c9baAngus Kong curr.layoutWithTranslationX(mDrawArea, mCenterX, mScale); 10751f9db2dfe59c33228103c54523281501ef52c9baAngus Kong curr.setAlpha(1f); 10764021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd curr.setVisibility(VISIBLE); 107780af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong 107880af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong if (inFullScreen()) { 10798ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde curr.setTranslationX(translate * (mCenterX - currCenterX) / 10808ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde (nextCenterX - currCenterX)); 108180af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong } else { 10821f9db2dfe59c33228103c54523281501ef52c9baAngus Kong curr.setTranslationX(translate); 108380af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong } 108480af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong } 108580af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong 108680af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong /** 108780af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong * Fade out the {@link ViewItem} on the right of the current one in 1088d028dd4908e68c7d4d0e7438efa74fa2c67e5f2aAngus Kong * full-screen layout. Does nothing if there's no previous item. 108980af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong * 10908ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde * @param bufferIndex The index of the item in the buffer to fade. 109180af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong */ 10928ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde private void fadeAndScaleRightViewItem(int bufferIndex) { 10938ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (bufferIndex < 1 || bufferIndex > BUFFER_SIZE) { 1094c14b6ba434575b7d795a8cd681821f86a39bc371Paul Rohde Log.w(TAG, "fadeAndScaleRightViewItem() - bufferIndex out of bound!"); 109580af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong return; 109680af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong } 109780af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong 10988ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde final ViewItem item = mViewItems[bufferIndex]; 10998ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde final ViewItem previousItem = mViewItems[bufferIndex - 1]; 11008ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (item == null || previousItem == null) { 1101c14b6ba434575b7d795a8cd681821f86a39bc371Paul Rohde Log.w(TAG, "fadeAndScaleRightViewItem() - Invalid view item (curr or prev == null)." 1102c14b6ba434575b7d795a8cd681821f86a39bc371Paul Rohde + "curr = " + bufferIndex); 110380af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong return; 110480af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong } 110580af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong 11068ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (bufferIndex > BUFFER_CENTER + 1) { 11078ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde // Every item not right next to the BUFFER_CENTER is invisible. 11088ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde item.setVisibility(INVISIBLE); 110980af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong return; 111080af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong } 11118ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde final int prevCenterX = previousItem.getCenterX(); 111280af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong if (mCenterX <= prevCenterX) { 111380af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong // Shortcut. If the position is at the center of the previous one, 111480af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong // set to invisible too. 11158ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde item.setVisibility(INVISIBLE); 111680af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong return; 111780af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong } 11188ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde final int currCenterX = item.getCenterX(); 111980af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong final float fadeDownFraction = 112080af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong ((float) mCenterX - prevCenterX) / (currCenterX - prevCenterX); 11218ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde item.layoutWithTranslationX(mDrawArea, currCenterX, 11228ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde FILM_STRIP_SCALE + (1f - FILM_STRIP_SCALE) * fadeDownFraction); 1123e7263f7ea45cf31d3948984ba8514e03ef86627ePaul Rohde 11248ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde item.setAlpha(fadeDownFraction); 11258ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde item.setTranslationX(0); 11268ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde item.setVisibility(VISIBLE); 112780af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong } 112880af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong 1129f1582c9c075e9cd5790b4bbe1101c94a45ac15d2Angus Kong private void layoutViewItems(boolean layoutChanged) { 11308ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (mViewItems[BUFFER_CENTER] == null || 11315fbe134c3cf1f7c2c82ccef223cab7eb43cd92f1Angus Kong mDrawArea.width() == 0 || 11325fbe134c3cf1f7c2c82ccef223cab7eb43cd92f1Angus Kong mDrawArea.height() == 0) { 11333d0b691b8f7a844093e8de9267ffa2ce16d0c5a9Angus Kong return; 11343d0b691b8f7a844093e8de9267ffa2ce16d0c5a9Angus Kong } 113549b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 1136f1582c9c075e9cd5790b4bbe1101c94a45ac15d2Angus Kong // If the layout changed, we need to adjust the current position so 1137f1582c9c075e9cd5790b4bbe1101c94a45ac15d2Angus Kong // that if an item is centered before the change, it's still centered. 1138f1582c9c075e9cd5790b4bbe1101c94a45ac15d2Angus Kong if (layoutChanged) { 11398ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mViewItems[BUFFER_CENTER].setLeftPosition( 11408ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mCenterX - mViewItems[BUFFER_CENTER].getMeasuredWidth() / 2); 114149b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 114249b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 11434567160a43fa5787012bf0b618c216cf18ac0457Angus Kong if (inZoomView()) { 11447d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong return; 11457d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong } 11464ff5a1ab360577c6a7ec953f9197778c84c9d334Angus Kong /** 11474ff5a1ab360577c6a7ec953f9197778c84c9d334Angus Kong * Transformed scale fraction between 0 and 1. 0 if the scale is 114888ef7664ba6a888fa5da8693091674e152b56192Sascha Haeberling * {@link FILM_STRIP_SCALE}. 1 if the scale is {@link FULL_SCREEN_SCALE} 114988ef7664ba6a888fa5da8693091674e152b56192Sascha Haeberling * . 11504ff5a1ab360577c6a7ec953f9197778c84c9d334Angus Kong */ 115180af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong final float scaleFraction = mViewAnimInterpolator.getInterpolation( 11524ff5a1ab360577c6a7ec953f9197778c84c9d334Angus Kong (mScale - FILM_STRIP_SCALE) / (FULL_SCREEN_SCALE - FILM_STRIP_SCALE)); 1153faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong final int fullScreenWidth = mDrawArea.width() + mViewGapInPixel; 1154a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong 1155280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling // Decide the position for all view items on the left and the right 1156280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling // first. 1157d028dd4908e68c7d4d0e7438efa74fa2c67e5f2aAngus Kong 1158d028dd4908e68c7d4d0e7438efa74fa2c67e5f2aAngus Kong // Left items. 11598ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde for (int i = BUFFER_CENTER - 1; i >= 0; i--) { 11608ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde final ViewItem curr = mViewItems[i]; 1161d028dd4908e68c7d4d0e7438efa74fa2c67e5f2aAngus Kong if (curr == null) { 1162d028dd4908e68c7d4d0e7438efa74fa2c67e5f2aAngus Kong break; 1163d028dd4908e68c7d4d0e7438efa74fa2c67e5f2aAngus Kong } 1164d028dd4908e68c7d4d0e7438efa74fa2c67e5f2aAngus Kong 1165d028dd4908e68c7d4d0e7438efa74fa2c67e5f2aAngus Kong // First, layout relatively to the next one. 11668ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde final int currLeft = mViewItems[i + 1].getLeftPosition() 11671f9db2dfe59c33228103c54523281501ef52c9baAngus Kong - curr.getMeasuredWidth() - mViewGapInPixel; 1168d028dd4908e68c7d4d0e7438efa74fa2c67e5f2aAngus Kong curr.setLeftPosition(currLeft); 1169d028dd4908e68c7d4d0e7438efa74fa2c67e5f2aAngus Kong } 1170d028dd4908e68c7d4d0e7438efa74fa2c67e5f2aAngus Kong // Right items. 11718ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde for (int i = BUFFER_CENTER + 1; i < BUFFER_SIZE; i++) { 11728ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde final ViewItem curr = mViewItems[i]; 1173d028dd4908e68c7d4d0e7438efa74fa2c67e5f2aAngus Kong if (curr == null) { 1174d028dd4908e68c7d4d0e7438efa74fa2c67e5f2aAngus Kong break; 1175d028dd4908e68c7d4d0e7438efa74fa2c67e5f2aAngus Kong } 1176d028dd4908e68c7d4d0e7438efa74fa2c67e5f2aAngus Kong 1177d028dd4908e68c7d4d0e7438efa74fa2c67e5f2aAngus Kong // First, layout relatively to the previous one. 11788ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde final ViewItem prev = mViewItems[i - 1]; 1179da568b23002859e9672271bb135808303c2e07cbAngus Kong final int currLeft = 11801f9db2dfe59c33228103c54523281501ef52c9baAngus Kong prev.getLeftPosition() + prev.getMeasuredWidth() 1181faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong + mViewGapInPixel; 1182d028dd4908e68c7d4d0e7438efa74fa2c67e5f2aAngus Kong curr.setLeftPosition(currLeft); 1183d028dd4908e68c7d4d0e7438efa74fa2c67e5f2aAngus Kong } 1184d028dd4908e68c7d4d0e7438efa74fa2c67e5f2aAngus Kong 118586f1d1f3664c909d1d949951056c7bb1e9627324Alan Newberger if (scaleFraction == 1f) { 11868ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde final ViewItem currItem = mViewItems[BUFFER_CENTER]; 1187d028dd4908e68c7d4d0e7438efa74fa2c67e5f2aAngus Kong final int currCenterX = currItem.getCenterX(); 1188d028dd4908e68c7d4d0e7438efa74fa2c67e5f2aAngus Kong if (mCenterX < currCenterX) { 1189d028dd4908e68c7d4d0e7438efa74fa2c67e5f2aAngus Kong // In full-screen and mCenterX is on the left of the center, 1190d028dd4908e68c7d4d0e7438efa74fa2c67e5f2aAngus Kong // we draw the current one to "fade down". 11918ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde fadeAndScaleRightViewItem(BUFFER_CENTER); 1192280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling } else if (mCenterX > currCenterX) { 1193d028dd4908e68c7d4d0e7438efa74fa2c67e5f2aAngus Kong // In full-screen and mCenterX is on the right of the center, 1194d028dd4908e68c7d4d0e7438efa74fa2c67e5f2aAngus Kong // we draw the current one translated. 11958ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde translateLeftViewItem(BUFFER_CENTER, fullScreenWidth, scaleFraction); 1196563a289f1aed4dd7bf760959851ff6ad72c7627fAngus Kong } else { 11971f9db2dfe59c33228103c54523281501ef52c9baAngus Kong currItem.layoutWithTranslationX(mDrawArea, mCenterX, mScale); 11981f9db2dfe59c33228103c54523281501ef52c9baAngus Kong currItem.setTranslationX(0f); 11991f9db2dfe59c33228103c54523281501ef52c9baAngus Kong currItem.setAlpha(1f); 1200563a289f1aed4dd7bf760959851ff6ad72c7627fAngus Kong } 1201025136bb4639d84b2a5a7b95367fabcc92b86415Angus Kong } else { 12028ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde final ViewItem currItem = mViewItems[BUFFER_CENTER]; 1203ec980898dd0dc712a3d6373c06a13f8646a0eebcAlan Newberger currItem.setVisibility(View.VISIBLE); 1204280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling // The normal filmstrip has no translation for the current item. If 1205280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling // it has translation before, gradually set it to zero. 12061f9db2dfe59c33228103c54523281501ef52c9baAngus Kong currItem.setTranslationX(currItem.getTranslationX() * scaleFraction); 12071f9db2dfe59c33228103c54523281501ef52c9baAngus Kong currItem.layoutWithTranslationX(mDrawArea, mCenterX, mScale); 12088ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (mViewItems[BUFFER_CENTER - 1] == null) { 12091f9db2dfe59c33228103c54523281501ef52c9baAngus Kong currItem.setAlpha(1f); 1210d028dd4908e68c7d4d0e7438efa74fa2c67e5f2aAngus Kong } else { 1211d028dd4908e68c7d4d0e7438efa74fa2c67e5f2aAngus Kong final int currCenterX = currItem.getCenterX(); 12128ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde final int prevCenterX = mViewItems[BUFFER_CENTER - 1].getCenterX(); 1213d028dd4908e68c7d4d0e7438efa74fa2c67e5f2aAngus Kong final float fadeDownFraction = 1214d028dd4908e68c7d4d0e7438efa74fa2c67e5f2aAngus Kong ((float) mCenterX - prevCenterX) / (currCenterX - prevCenterX); 12151f9db2dfe59c33228103c54523281501ef52c9baAngus Kong currItem.setAlpha( 1216d028dd4908e68c7d4d0e7438efa74fa2c67e5f2aAngus Kong (1 - fadeDownFraction) * (1 - scaleFraction) + fadeDownFraction); 1217d028dd4908e68c7d4d0e7438efa74fa2c67e5f2aAngus Kong } 1218025136bb4639d84b2a5a7b95367fabcc92b86415Angus Kong } 1219025136bb4639d84b2a5a7b95367fabcc92b86415Angus Kong 1220025136bb4639d84b2a5a7b95367fabcc92b86415Angus Kong // Layout the rest dependent on the current scale. 1221025136bb4639d84b2a5a7b95367fabcc92b86415Angus Kong 1222d028dd4908e68c7d4d0e7438efa74fa2c67e5f2aAngus Kong // Items on the left 12238ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde for (int i = BUFFER_CENTER - 1; i >= 0; i--) { 12248ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde final ViewItem curr = mViewItems[i]; 1225f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling if (curr == null) { 122680af7dd871547d03ee9ff5023cbec00b1d8677eeAngus Kong break; 1227f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling } 12288ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde translateLeftViewItem(i, fullScreenWidth, scaleFraction); 122949b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 123049b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 1231d028dd4908e68c7d4d0e7438efa74fa2c67e5f2aAngus Kong // Items on the right 12328ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde for (int i = BUFFER_CENTER + 1; i < BUFFER_SIZE; i++) { 12338ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde final ViewItem curr = mViewItems[i]; 1234f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling if (curr == null) { 1235d028dd4908e68c7d4d0e7438efa74fa2c67e5f2aAngus Kong break; 1236f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling } 1237a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong 12381f9db2dfe59c33228103c54523281501ef52c9baAngus Kong curr.layoutWithTranslationX(mDrawArea, mCenterX, mScale); 1239da568b23002859e9672271bb135808303c2e07cbAngus Kong 12404ff5a1ab360577c6a7ec953f9197778c84c9d334Angus Kong if (scaleFraction == 1) { 1241025136bb4639d84b2a5a7b95367fabcc92b86415Angus Kong // It's in full-screen mode. 12428ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde fadeAndScaleRightViewItem(i); 1243a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong } else { 124434ac66e6d0bb849fb24a6255328390aba204abe3Alan Newberger boolean isVisible = (curr.getVisibility() == VISIBLE); 124534ac66e6d0bb849fb24a6255328390aba204abe3Alan Newberger boolean setToVisible = !isVisible; 12469351e87558b7cb6cbc21d817a585ef769567e347Spike Sprague 12478ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (i == BUFFER_CENTER + 1) { 124834ac66e6d0bb849fb24a6255328390aba204abe3Alan Newberger // right hand neighbor needs to fade based on scale of 124934ac66e6d0bb849fb24a6255328390aba204abe3Alan Newberger // center 12501f9db2dfe59c33228103c54523281501ef52c9baAngus Kong curr.setAlpha(1f - scaleFraction); 1251a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong } else { 12524ff5a1ab360577c6a7ec953f9197778c84c9d334Angus Kong if (scaleFraction == 0f) { 12531f9db2dfe59c33228103c54523281501ef52c9baAngus Kong curr.setAlpha(1f); 12544ff5a1ab360577c6a7ec953f9197778c84c9d334Angus Kong } else { 125534ac66e6d0bb849fb24a6255328390aba204abe3Alan Newberger // further right items should not display when center 125634ac66e6d0bb849fb24a6255328390aba204abe3Alan Newberger // is being scaled 12579351e87558b7cb6cbc21d817a585ef769567e347Spike Sprague setToVisible = false; 125834ac66e6d0bb849fb24a6255328390aba204abe3Alan Newberger if (isVisible) { 125934ac66e6d0bb849fb24a6255328390aba204abe3Alan Newberger curr.setVisibility(INVISIBLE); 126034ac66e6d0bb849fb24a6255328390aba204abe3Alan Newberger } 12614ff5a1ab360577c6a7ec953f9197778c84c9d334Angus Kong } 1262a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong } 12639351e87558b7cb6cbc21d817a585ef769567e347Spike Sprague 126434ac66e6d0bb849fb24a6255328390aba204abe3Alan Newberger if (setToVisible && !isVisible) { 12659351e87558b7cb6cbc21d817a585ef769567e347Spike Sprague curr.setVisibility(VISIBLE); 12669351e87558b7cb6cbc21d817a585ef769567e347Spike Sprague } 12679351e87558b7cb6cbc21d817a585ef769567e347Spike Sprague 12688ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde curr.setTranslationX((mViewItems[BUFFER_CENTER].getLeftPosition() - 12698ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde curr.getLeftPosition()) * scaleFraction); 127049b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 127149b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 127249b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 127349b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong stepIfNeeded(); 12747d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong } 1275aa2a243bdc91b809dbfe01a9933b02e6b95d983fAngus Kong 12767d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong @Override 12777d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong public void onDraw(Canvas c) { 1278f1582c9c075e9cd5790b4bbe1101c94a45ac15d2Angus Kong // TODO: remove layoutViewItems() here. 1279f1582c9c075e9cd5790b4bbe1101c94a45ac15d2Angus Kong layoutViewItems(false); 12807d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong super.onDraw(c); 128149b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 128249b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 128349b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong @Override 128449b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong protected void onLayout(boolean changed, int l, int t, int r, int b) { 12857539e49296b993be37709f45385a6286618d464dAngus Kong mDrawArea.left = 0; 12867539e49296b993be37709f45385a6286618d464dAngus Kong mDrawArea.top = 0; 12877539e49296b993be37709f45385a6286618d464dAngus Kong mDrawArea.right = r - l; 12887539e49296b993be37709f45385a6286618d464dAngus Kong mDrawArea.bottom = b - t; 1289563a289f1aed4dd7bf760959851ff6ad72c7627fAngus Kong mZoomView.layout(mDrawArea.left, mDrawArea.top, mDrawArea.right, mDrawArea.bottom); 12907d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong // TODO: Need a more robust solution to decide when to re-layout 1291280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling // If in the middle of zooming, only re-layout when the layout has 1292280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling // changed. 12934567160a43fa5787012bf0b618c216cf18ac0457Angus Kong if (!inZoomView() || changed) { 1294121022cb590955e37f1264f77190ce4711159976Doris Liu resetZoomView(); 1295f1582c9c075e9cd5790b4bbe1101c94a45ac15d2Angus Kong layoutViewItems(changed); 1296121022cb590955e37f1264f77190ce4711159976Doris Liu } 129749b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 129849b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 1299f9ddb6034e560684e4d3ddd460ef9dff345e4e91Doris Liu /** 1300280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling * Clears the translation and scale that has been set on the view, cancels 1301280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling * any loading request for image partial decoding, and hides zoom view. This 1302280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling * is needed for when there is a layout change (e.g. when users re-enter the 1303280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling * app, or rotate the device, etc). 1304f9ddb6034e560684e4d3ddd460ef9dff345e4e91Doris Liu */ 1305f9ddb6034e560684e4d3ddd460ef9dff345e4e91Doris Liu private void resetZoomView() { 13064567160a43fa5787012bf0b618c216cf18ac0457Angus Kong if (!inZoomView()) { 1307f9ddb6034e560684e4d3ddd460ef9dff345e4e91Doris Liu return; 1308f9ddb6034e560684e4d3ddd460ef9dff345e4e91Doris Liu } 13098ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde ViewItem current = mViewItems[BUFFER_CENTER]; 1310f9ddb6034e560684e4d3ddd460ef9dff345e4e91Doris Liu if (current == null) { 1311f9ddb6034e560684e4d3ddd460ef9dff345e4e91Doris Liu return; 1312f9ddb6034e560684e4d3ddd460ef9dff345e4e91Doris Liu } 1313f9ddb6034e560684e4d3ddd460ef9dff345e4e91Doris Liu mScale = FULL_SCREEN_SCALE; 1314d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu mController.cancelZoomAnimation(); 1315d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu mController.cancelFlingAnimation(); 1316f9ddb6034e560684e4d3ddd460ef9dff345e4e91Doris Liu current.resetTransform(); 1317f9ddb6034e560684e4d3ddd460ef9dff345e4e91Doris Liu mController.cancelLoadingZoomedImage(); 1318f9ddb6034e560684e4d3ddd460ef9dff345e4e91Doris Liu mZoomView.setVisibility(GONE); 131903b75411538c60021799ccc7acc8ed4798253b6dDoris Liu mController.setSurroundingViewsVisible(true); 1320f9ddb6034e560684e4d3ddd460ef9dff345e4e91Doris Liu } 1321f9ddb6034e560684e4d3ddd460ef9dff345e4e91Doris Liu 1322b0288ec84e06b83923180a04e1b546724fcfd258Doris Liu private void hideZoomView() { 13234567160a43fa5787012bf0b618c216cf18ac0457Angus Kong if (inZoomView()) { 1324b0288ec84e06b83923180a04e1b546724fcfd258Doris Liu mController.cancelLoadingZoomedImage(); 1325b0288ec84e06b83923180a04e1b546724fcfd258Doris Liu mZoomView.setVisibility(GONE); 1326b0288ec84e06b83923180a04e1b546724fcfd258Doris Liu } 1327b0288ec84e06b83923180a04e1b546724fcfd258Doris Liu } 1328b0288ec84e06b83923180a04e1b546724fcfd258Doris Liu 1329edbba628dc2e31057b304c6a431f44dbca125891Angus Kong private void slideViewBack(ViewItem item) { 1330ec2fb473c094f8dfd1cc0cf5205d470e412d3919Angus Kong item.animateTranslationX(0, GEOMETRY_ADJUST_TIME_MS, mViewAnimInterpolator); 13311f9db2dfe59c33228103c54523281501ef52c9baAngus Kong item.animateTranslationY(0, GEOMETRY_ADJUST_TIME_MS, mViewAnimInterpolator); 13321f9db2dfe59c33228103c54523281501ef52c9baAngus Kong item.animateAlpha(1f, GEOMETRY_ADJUST_TIME_MS, mViewAnimInterpolator); 133387f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong } 133487f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong 13358ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde private void animateItemRemoval(int index) { 1336c6953a4de0005456cd50bbbb0acb27162c9b3c8dAngus Kong if (mScale > FULL_SCREEN_SCALE) { 1337c6953a4de0005456cd50bbbb0acb27162c9b3c8dAngus Kong resetZoomView(); 1338c6953a4de0005456cd50bbbb0acb27162c9b3c8dAngus Kong } 13398ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde int removeAtBufferIndex = findItemInBufferByAdapterIndex(index); 1340c31569ce211414f6db2447cc84ca71115f916b6fAngus Kong 13418ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde // adjust the buffer to be consistent 1342c31569ce211414f6db2447cc84ca71115f916b6fAngus Kong for (int i = 0; i < BUFFER_SIZE; i++) { 13438ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (mViewItems[i] == null || mViewItems[i].getAdapterIndex() <= index) { 1344f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling continue; 1345f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling } 13468ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mViewItems[i].setIndex(mViewItems[i].getAdapterIndex() - 1); 1347c31569ce211414f6db2447cc84ca71115f916b6fAngus Kong } 13488ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (removeAtBufferIndex == -1) { 1349f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling return; 1350f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling } 1351c31569ce211414f6db2447cc84ca71115f916b6fAngus Kong 13528ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde final ViewItem removedItem = mViewItems[removeAtBufferIndex]; 13531f9db2dfe59c33228103c54523281501ef52c9baAngus Kong final int offsetX = removedItem.getMeasuredWidth() + mViewGapInPixel; 135487f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong 13558ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde for (int i = removeAtBufferIndex + 1; i < BUFFER_SIZE; i++) { 13568ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (mViewItems[i] != null) { 13578ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mViewItems[i].setLeftPosition(mViewItems[i].getLeftPosition() - offsetX); 135887f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong } 135987f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong } 136087f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong 13618ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (removeAtBufferIndex >= BUFFER_CENTER 13628ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde && mViewItems[removeAtBufferIndex].getAdapterIndex() < mDataAdapter.getTotalNumber()) { 13638969a67c926608737f3e49f2d2240298372e8416Angus Kong // Fill the removed item by left shift when the current one or 1364f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling // anyone on the right is removed, and there's more data on the 1365f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling // right available. 13668ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde for (int i = removeAtBufferIndex; i < BUFFER_SIZE - 1; i++) { 13678ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mViewItems[i] = mViewItems[i + 1]; 136887f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong } 136987f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong 137087f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong // pull data out from the DataAdapter for the last one. 137187f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong int curr = BUFFER_SIZE - 1; 137287f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong int prev = curr - 1; 13738ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (mViewItems[prev] != null) { 13748ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mViewItems[curr] = buildViewItemAt(mViewItems[prev].getAdapterIndex() + 1); 137587f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong } 13769f02c87cfb5039a72f516ea5edc0378c45ac5779Angus Kong 1377aa2a243bdc91b809dbfe01a9933b02e6b95d983fAngus Kong // The animation part. 1378aa2a243bdc91b809dbfe01a9933b02e6b95d983fAngus Kong if (inFullScreen()) { 13798ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mViewItems[BUFFER_CENTER].setVisibility(VISIBLE); 13808ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde ViewItem nextItem = mViewItems[BUFFER_CENTER + 1]; 1381aa2a243bdc91b809dbfe01a9933b02e6b95d983fAngus Kong if (nextItem != null) { 13821f9db2dfe59c33228103c54523281501ef52c9baAngus Kong nextItem.setVisibility(INVISIBLE); 1383aa2a243bdc91b809dbfe01a9933b02e6b95d983fAngus Kong } 1384aa2a243bdc91b809dbfe01a9933b02e6b95d983fAngus Kong } 1385aa2a243bdc91b809dbfe01a9933b02e6b95d983fAngus Kong 13860980fe89b2c0d2d8f75cb43a5fe06c00b8c8901eAngus Kong // Translate the views to their original places. 13878ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde for (int i = removeAtBufferIndex; i < BUFFER_SIZE; i++) { 13888ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (mViewItems[i] != null) { 13898ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mViewItems[i].setTranslationX(offsetX); 13909f02c87cfb5039a72f516ea5edc0378c45ac5779Angus Kong } 13919f02c87cfb5039a72f516ea5edc0378c45ac5779Angus Kong } 13929f02c87cfb5039a72f516ea5edc0378c45ac5779Angus Kong 13939f02c87cfb5039a72f516ea5edc0378c45ac5779Angus Kong // The end of the filmstrip might have been changed. 1394af24d28f8938a05d2e3c40155e39cbc7ff4d64b7Angus Kong // The mCenterX might be out of the bound. 13958ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde ViewItem currItem = mViewItems[BUFFER_CENTER]; 13968ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (currItem!=null) { 13978ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (currItem.getAdapterIndex() == mDataAdapter.getTotalNumber() - 1 13989efa64a16a691e6aeb56dc844aa00c8ea057ef99I-Jong Lin && mCenterX > currItem.getCenterX()) { 13999efa64a16a691e6aeb56dc844aa00c8ea057ef99I-Jong Lin int adjustDiff = currItem.getCenterX() - mCenterX; 14009efa64a16a691e6aeb56dc844aa00c8ea057ef99I-Jong Lin mCenterX = currItem.getCenterX(); 14019efa64a16a691e6aeb56dc844aa00c8ea057ef99I-Jong Lin for (int i = 0; i < BUFFER_SIZE; i++) { 14028ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (mViewItems[i] != null) { 14038ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mViewItems[i].translateXScaledBy(adjustDiff); 14049efa64a16a691e6aeb56dc844aa00c8ea057ef99I-Jong Lin } 14059f02c87cfb5039a72f516ea5edc0378c45ac5779Angus Kong } 14069f02c87cfb5039a72f516ea5edc0378c45ac5779Angus Kong } 14079efa64a16a691e6aeb56dc844aa00c8ea057ef99I-Jong Lin } else { 14089efa64a16a691e6aeb56dc844aa00c8ea057ef99I-Jong Lin // CurrItem should NOT be NULL, but if is, at least don't crash. 14099efa64a16a691e6aeb56dc844aa00c8ea057ef99I-Jong Lin Log.w(TAG,"Caught invalid update in removal animation."); 14109f02c87cfb5039a72f516ea5edc0378c45ac5779Angus Kong } 141187f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong } else { 141287f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong // fill the removed place by right shift 1413af24d28f8938a05d2e3c40155e39cbc7ff4d64b7Angus Kong mCenterX -= offsetX; 14149f02c87cfb5039a72f516ea5edc0378c45ac5779Angus Kong 14158ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde for (int i = removeAtBufferIndex; i > 0; i--) { 14168ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mViewItems[i] = mViewItems[i - 1]; 141787f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong } 141887f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong 141987f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong // pull data out from the DataAdapter for the first one. 142087f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong int curr = 0; 142187f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong int next = curr + 1; 14228ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (mViewItems[next] != null) { 14238ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mViewItems[curr] = buildViewItemAt(mViewItems[next].getAdapterIndex() - 1); 14248ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde 142587f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong } 14260980fe89b2c0d2d8f75cb43a5fe06c00b8c8901eAngus Kong 14270980fe89b2c0d2d8f75cb43a5fe06c00b8c8901eAngus Kong // Translate the views to their original places. 14288ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde for (int i = removeAtBufferIndex; i >= 0; i--) { 14298ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (mViewItems[i] != null) { 14308ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mViewItems[i].setTranslationX(-offsetX); 14310980fe89b2c0d2d8f75cb43a5fe06c00b8c8901eAngus Kong } 14320980fe89b2c0d2d8f75cb43a5fe06c00b8c8901eAngus Kong } 143387f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong } 143487f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong 14351f9db2dfe59c33228103c54523281501ef52c9baAngus Kong int transY = getHeight() / 8; 14361f9db2dfe59c33228103c54523281501ef52c9baAngus Kong if (removedItem.getTranslationY() < 0) { 14371f9db2dfe59c33228103c54523281501ef52c9baAngus Kong transY = -transY; 14381f9db2dfe59c33228103c54523281501ef52c9baAngus Kong } 14391f9db2dfe59c33228103c54523281501ef52c9baAngus Kong removedItem.animateTranslationY(removedItem.getTranslationY() + transY, 14401f9db2dfe59c33228103c54523281501ef52c9baAngus Kong GEOMETRY_ADJUST_TIME_MS, mViewAnimInterpolator); 14411f9db2dfe59c33228103c54523281501ef52c9baAngus Kong removedItem.animateAlpha(0f, GEOMETRY_ADJUST_TIME_MS, mViewAnimInterpolator); 14421f9db2dfe59c33228103c54523281501ef52c9baAngus Kong postDelayed(new Runnable() { 14431f9db2dfe59c33228103c54523281501ef52c9baAngus Kong @Override 14441f9db2dfe59c33228103c54523281501ef52c9baAngus Kong public void run() { 14455a0be52d3db2398cfe01d18adf779d9e443edf82Alan Newberger removedItem.removeViewFromHierarchy(); 14461f9db2dfe59c33228103c54523281501ef52c9baAngus Kong } 14471f9db2dfe59c33228103c54523281501ef52c9baAngus Kong }, GEOMETRY_ADJUST_TIME_MS); 14481f9db2dfe59c33228103c54523281501ef52c9baAngus Kong 14491f9db2dfe59c33228103c54523281501ef52c9baAngus Kong adjustChildZOrder(); 14501f9db2dfe59c33228103c54523281501ef52c9baAngus Kong invalidate(); 14511f9db2dfe59c33228103c54523281501ef52c9baAngus Kong 14529f02c87cfb5039a72f516ea5edc0378c45ac5779Angus Kong // Now, slide every one back. 14538ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (mViewItems[BUFFER_CENTER] == null) { 14541f9db2dfe59c33228103c54523281501ef52c9baAngus Kong return; 14551f9db2dfe59c33228103c54523281501ef52c9baAngus Kong } 14569f02c87cfb5039a72f516ea5edc0378c45ac5779Angus Kong for (int i = 0; i < BUFFER_SIZE; i++) { 14578ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (mViewItems[i] != null 14588ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde && mViewItems[i].getTranslationX() != 0f) { 14598ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde slideViewBack(mViewItems[i]); 14609f02c87cfb5039a72f516ea5edc0378c45ac5779Angus Kong } 14619f02c87cfb5039a72f516ea5edc0378c45ac5779Angus Kong } 146287f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong } 146387f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong 1464e78541f2edf2f02660c34660114e76d53b32ab8bAngus Kong // returns -1 on failure. 14658ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde private int findItemInBufferByAdapterIndex(int index) { 1466e78541f2edf2f02660c34660114e76d53b32ab8bAngus Kong for (int i = 0; i < BUFFER_SIZE; i++) { 14678ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (mViewItems[i] != null 14688ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde && mViewItems[i].getAdapterIndex() == index) { 1469f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling return i; 1470f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling } 1471e78541f2edf2f02660c34660114e76d53b32ab8bAngus Kong } 1472e78541f2edf2f02660c34660114e76d53b32ab8bAngus Kong return -1; 1473e78541f2edf2f02660c34660114e76d53b32ab8bAngus Kong } 1474e78541f2edf2f02660c34660114e76d53b32ab8bAngus Kong 14758ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde private void updateInsertion(int index) { 14768ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde int bufferIndex = findItemInBufferByAdapterIndex(index); 14778ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (bufferIndex == -1) { 14788969a67c926608737f3e49f2d2240298372e8416Angus Kong // Not in the current item buffers. Check if it's inserted 1479e78541f2edf2f02660c34660114e76d53b32ab8bAngus Kong // at the end. 14808ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (index == mDataAdapter.getTotalNumber() - 1) { 14818ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde int prev = findItemInBufferByAdapterIndex(index - 1); 1482e78541f2edf2f02660c34660114e76d53b32ab8bAngus Kong if (prev >= 0 && prev < BUFFER_SIZE - 1) { 1483e78541f2edf2f02660c34660114e76d53b32ab8bAngus Kong // The previous data is in the buffer and we still 1484e78541f2edf2f02660c34660114e76d53b32ab8bAngus Kong // have room for the inserted data. 14858ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde bufferIndex = prev + 1; 1486e78541f2edf2f02660c34660114e76d53b32ab8bAngus Kong } 1487e78541f2edf2f02660c34660114e76d53b32ab8bAngus Kong } 1488e78541f2edf2f02660c34660114e76d53b32ab8bAngus Kong } 1489e78541f2edf2f02660c34660114e76d53b32ab8bAngus Kong 14908ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde // adjust the indexes to be consistent 1491e78541f2edf2f02660c34660114e76d53b32ab8bAngus Kong for (int i = 0; i < BUFFER_SIZE; i++) { 14928ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (mViewItems[i] == null || mViewItems[i].getAdapterIndex() < index) { 1493f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling continue; 1494f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling } 14958ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mViewItems[i].setIndex(mViewItems[i].getAdapterIndex() + 1); 1496e78541f2edf2f02660c34660114e76d53b32ab8bAngus Kong } 14978ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (bufferIndex == -1) { 1498f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling return; 1499f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling } 1500e78541f2edf2f02660c34660114e76d53b32ab8bAngus Kong 15018ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde final FilmstripItem data = mDataAdapter.getFilmstripItemAt(index); 1502c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong Point dim = CameraUtil 15038ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde .resizeToFill( 150451cafa0a35546a42c573357aa7a031a79cf9ba1bAlan Newberger data.getDimensions().getWidth(), 150551cafa0a35546a42c573357aa7a031a79cf9ba1bAlan Newberger data.getDimensions().getHeight(), 150651cafa0a35546a42c573357aa7a031a79cf9ba1bAlan Newberger data.getOrientation(), 15078ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde getMeasuredWidth(), 15088ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde getMeasuredHeight()); 1509c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong final int offsetX = dim.x + mViewGapInPixel; 15108ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde ViewItem viewItem = buildViewItemAt(index); 151161c5f9f86b5fd8937fac3d082398086bac0d8db6Alan Newberger if (viewItem == null) { 151261c5f9f86b5fd8937fac3d082398086bac0d8db6Alan Newberger Log.w(TAG, "unable to build inserted item from data"); 151361c5f9f86b5fd8937fac3d082398086bac0d8db6Alan Newberger return; 151461c5f9f86b5fd8937fac3d082398086bac0d8db6Alan Newberger } 1515e78541f2edf2f02660c34660114e76d53b32ab8bAngus Kong 15168ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (bufferIndex >= BUFFER_CENTER) { 15178ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (bufferIndex == BUFFER_CENTER) { 15188ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde viewItem.setLeftPosition(mViewItems[BUFFER_CENTER].getLeftPosition()); 1519e78541f2edf2f02660c34660114e76d53b32ab8bAngus Kong } 1520e78541f2edf2f02660c34660114e76d53b32ab8bAngus Kong // Shift right to make rooms for newly inserted item. 15218969a67c926608737f3e49f2d2240298372e8416Angus Kong removeItem(BUFFER_SIZE - 1); 15228ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde for (int i = BUFFER_SIZE - 1; i > bufferIndex; i--) { 15238ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mViewItems[i] = mViewItems[i - 1]; 15248ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (mViewItems[i] != null) { 15258ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mViewItems[i].setTranslationX(-offsetX); 15268ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde slideViewBack(mViewItems[i]); 1527e78541f2edf2f02660c34660114e76d53b32ab8bAngus Kong } 1528e78541f2edf2f02660c34660114e76d53b32ab8bAngus Kong } 1529e78541f2edf2f02660c34660114e76d53b32ab8bAngus Kong } else { 1530f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling // Shift left. Put the inserted data on the left instead of the 1531f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling // found position. 15328ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde --bufferIndex; 15338ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (bufferIndex < 0) { 1534f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling return; 1535f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling } 15368969a67c926608737f3e49f2d2240298372e8416Angus Kong removeItem(0); 15378ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde for (int i = 1; i <= bufferIndex; i++) { 15388ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (mViewItems[i] != null) { 15398ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mViewItems[i].setTranslationX(offsetX); 15408ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde slideViewBack(mViewItems[i]); 15418ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mViewItems[i - 1] = mViewItems[i]; 1542e78541f2edf2f02660c34660114e76d53b32ab8bAngus Kong } 1543e78541f2edf2f02660c34660114e76d53b32ab8bAngus Kong } 1544e78541f2edf2f02660c34660114e76d53b32ab8bAngus Kong } 1545e78541f2edf2f02660c34660114e76d53b32ab8bAngus Kong 15468ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mViewItems[bufferIndex] = viewItem; 154777d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde renderThumbnail(bufferIndex); 15481f9db2dfe59c33228103c54523281501ef52c9baAngus Kong viewItem.setAlpha(0f); 15491f9db2dfe59c33228103c54523281501ef52c9baAngus Kong viewItem.setTranslationY(getHeight() / 8); 15501f9db2dfe59c33228103c54523281501ef52c9baAngus Kong slideViewBack(viewItem); 155153aedc0ee671c2d11341a66c444bbb6cdc97b150Angus Kong adjustChildZOrder(); 1552c14b6ba434575b7d795a8cd681821f86a39bc371Paul Rohde 1553e78541f2edf2f02660c34660114e76d53b32ab8bAngus Kong invalidate(); 1554e78541f2edf2f02660c34660114e76d53b32ab8bAngus Kong } 1555e78541f2edf2f02660c34660114e76d53b32ab8bAngus Kong 15568ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde private void setDataAdapter(FilmstripDataAdapter adapter) { 155749b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong mDataAdapter = adapter; 15583f192ccf03d0d25521b96304c4464b4bad28150aSascha Haeberling int maxEdge = (int) (Math.max(this.getHeight(), this.getWidth()) 15594021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd * FILM_STRIP_SCALE); 15604021c896985d9ba43db0199f259ce4b8bfc0dc88Sam Judd mDataAdapter.suggestViewSizeBound(maxEdge, maxEdge); 15618ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mDataAdapter.setListener(new FilmstripDataAdapter.Listener() { 156249b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong @Override 15638ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde public void onFilmstripItemLoaded() { 156449b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong reload(); 156549b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 156649b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 156749b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong @Override 15688ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde public void onFilmstripItemUpdated(FilmstripDataAdapter.UpdateReporter reporter) { 156949b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong update(reporter); 157049b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 157149b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 157249b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong @Override 15738ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde public void onFilmstripItemInserted(int index, FilmstripItem item) { 15748ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (mViewItems[BUFFER_CENTER] == null) { 1575e78541f2edf2f02660c34660114e76d53b32ab8bAngus Kong // empty now, simply do a reload. 1576e78541f2edf2f02660c34660114e76d53b32ab8bAngus Kong reload(); 1577faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong } else { 15788ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde updateInsertion(index); 1579faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong } 1580faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong if (mListener != null) { 15818ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mListener.onDataFocusChanged(index, getCurrentItemAdapterIndex()); 1582e78541f2edf2f02660c34660114e76d53b32ab8bAngus Kong } 1583c14b6ba434575b7d795a8cd681821f86a39bc371Paul Rohde Log.d(TAG, "onFilmstripItemInserted()"); 158477d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde renderAllThumbnails(); 158549b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 158649b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 158749b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong @Override 15888ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde public void onFilmstripItemRemoved(int index, FilmstripItem item) { 15898ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde animateItemRemoval(index); 1590faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong if (mListener != null) { 15918ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mListener.onDataFocusChanged(index, getCurrentItemAdapterIndex()); 1592faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong } 1593c14b6ba434575b7d795a8cd681821f86a39bc371Paul Rohde Log.d(TAG, "onFilmstripItemRemoved()"); 159477d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde renderAllThumbnails(); 159549b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 159649b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong }); 159749b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 159849b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 1599628481532e1e58a0a26330d238e850aec5657bceAngus Kong private boolean inFilmstrip() { 1600a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong return (mScale == FILM_STRIP_SCALE); 1601a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong } 1602a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong 1603628481532e1e58a0a26330d238e850aec5657bceAngus Kong private boolean inFullScreen() { 16044ff5a1ab360577c6a7ec953f9197778c84c9d334Angus Kong return (mScale == FULL_SCREEN_SCALE); 1605a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong } 1606a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong 16074567160a43fa5787012bf0b618c216cf18ac0457Angus Kong private boolean inZoomView() { 16084567160a43fa5787012bf0b618c216cf18ac0457Angus Kong return (mScale > FULL_SCREEN_SCALE); 16094567160a43fa5787012bf0b618c216cf18ac0457Angus Kong } 16104567160a43fa5787012bf0b618c216cf18ac0457Angus Kong 161149b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong @Override 161249b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong public boolean onInterceptTouchEvent(MotionEvent ev) { 16137e9e4b7bdf371afd37f43a331cef1672fac1a230Angus Kong if (mController.isScrolling()) { 1614f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling return true; 1615f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling } 1616a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong 1617fb57df15a87f95ce8b2f861e54d960602912e03cDoris Liu if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) { 1618fb57df15a87f95ce8b2f861e54d960602912e03cDoris Liu mCheckToIntercept = true; 1619fb57df15a87f95ce8b2f861e54d960602912e03cDoris Liu mDown = MotionEvent.obtain(ev); 1620fb57df15a87f95ce8b2f861e54d960602912e03cDoris Liu return false; 1621fb57df15a87f95ce8b2f861e54d960602912e03cDoris Liu } else if (ev.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN) { 1622fb57df15a87f95ce8b2f861e54d960602912e03cDoris Liu // Do not intercept touch once child is in zoom mode 1623fb57df15a87f95ce8b2f861e54d960602912e03cDoris Liu mCheckToIntercept = false; 1624fb57df15a87f95ce8b2f861e54d960602912e03cDoris Liu return false; 1625fb57df15a87f95ce8b2f861e54d960602912e03cDoris Liu } else { 1626f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling if (!mCheckToIntercept) { 1627f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling return false; 1628f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling } 1629f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling if (ev.getEventTime() - ev.getDownTime() > SWIPE_TIME_OUT) { 1630f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling return false; 1631f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling } 1632fb57df15a87f95ce8b2f861e54d960602912e03cDoris Liu int deltaX = (int) (ev.getX() - mDown.getX()); 1633fb57df15a87f95ce8b2f861e54d960602912e03cDoris Liu int deltaY = (int) (ev.getY() - mDown.getY()); 1634fb57df15a87f95ce8b2f861e54d960602912e03cDoris Liu if (ev.getActionMasked() == MotionEvent.ACTION_MOVE 1635fb57df15a87f95ce8b2f861e54d960602912e03cDoris Liu && deltaX < mSlop * (-1)) { 1636fb57df15a87f95ce8b2f861e54d960602912e03cDoris Liu // intercept left swipe 1637fb57df15a87f95ce8b2f861e54d960602912e03cDoris Liu if (Math.abs(deltaX) >= Math.abs(deltaY) * 2) { 1638fb57df15a87f95ce8b2f861e54d960602912e03cDoris Liu return true; 1639fb57df15a87f95ce8b2f861e54d960602912e03cDoris Liu } 1640fb57df15a87f95ce8b2f861e54d960602912e03cDoris Liu } 1641fb57df15a87f95ce8b2f861e54d960602912e03cDoris Liu } 1642fb57df15a87f95ce8b2f861e54d960602912e03cDoris Liu return false; 164349b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 164449b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 164549b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong @Override 164649b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong public boolean onTouchEvent(MotionEvent ev) { 1647166e36fb6e04d40a1bef0459ee6b96c9c736039bAngus Kong return mGestureRecognizer.onTouchEvent(ev); 1648166e36fb6e04d40a1bef0459ee6b96c9c736039bAngus Kong } 1649166e36fb6e04d40a1bef0459ee6b96c9c736039bAngus Kong 16509652134e6e1b312e348ed3565343741239907f11Alan Newberger @Override 16519652134e6e1b312e348ed3565343741239907f11Alan Newberger public boolean onGenericMotionEvent(MotionEvent ev) { 16529652134e6e1b312e348ed3565343741239907f11Alan Newberger mGestureRecognizer.onGenericMotionEvent(ev); 16539652134e6e1b312e348ed3565343741239907f11Alan Newberger return true; 16549652134e6e1b312e348ed3565343741239907f11Alan Newberger } 16559652134e6e1b312e348ed3565343741239907f11Alan Newberger 1656166e36fb6e04d40a1bef0459ee6b96c9c736039bAngus Kong FilmstripGestureRecognizer.Listener getGestureListener() { 1657166e36fb6e04d40a1bef0459ee6b96c9c736039bAngus Kong return mGestureListener; 165849b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 165949b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 16608ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde private void updateViewItem(int bufferIndex) { 16618ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde ViewItem item = mViewItems[bufferIndex]; 16628969a67c926608737f3e49f2d2240298372e8416Angus Kong if (item == null) { 1663c14b6ba434575b7d795a8cd681821f86a39bc371Paul Rohde Log.w(TAG, "updateViewItem() - Trying to update an null item!"); 16648969a67c926608737f3e49f2d2240298372e8416Angus Kong return; 16658969a67c926608737f3e49f2d2240298372e8416Angus Kong } 16668969a67c926608737f3e49f2d2240298372e8416Angus Kong 16678e29072ca69229a25dc4a856e3635d131613f4caAlan Newberger int adapterIndex = item.getAdapterIndex(); 16688e29072ca69229a25dc4a856e3635d131613f4caAlan Newberger FilmstripItem filmstripItem = mDataAdapter.getFilmstripItemAt(adapterIndex); 16698e29072ca69229a25dc4a856e3635d131613f4caAlan Newberger if (filmstripItem == null) { 16708e29072ca69229a25dc4a856e3635d131613f4caAlan Newberger Log.w(TAG, "updateViewItem() - Trying to update item with null FilmstripItem!"); 16718969a67c926608737f3e49f2d2240298372e8416Angus Kong return; 16728969a67c926608737f3e49f2d2240298372e8416Angus Kong } 16738e29072ca69229a25dc4a856e3635d131613f4caAlan Newberger 16745a0be52d3db2398cfe01d18adf779d9e443edf82Alan Newberger FilmstripItem oldFilmstripItem = item.getData(); 16755a0be52d3db2398cfe01d18adf779d9e443edf82Alan Newberger 16768e29072ca69229a25dc4a856e3635d131613f4caAlan Newberger // In case the underlying data item is changed (commonly from 16778e29072ca69229a25dc4a856e3635d131613f4caAlan Newberger // SessionItem to PhotoItem for an image requiring processing), set the 16788e29072ca69229a25dc4a856e3635d131613f4caAlan Newberger // new FilmstripItem on the ViewItem 16795a0be52d3db2398cfe01d18adf779d9e443edf82Alan Newberger if (!filmstripItem.equals(oldFilmstripItem)) { 16805a0be52d3db2398cfe01d18adf779d9e443edf82Alan Newberger oldFilmstripItem.recycle(item.getView()); 16815a0be52d3db2398cfe01d18adf779d9e443edf82Alan Newberger item.setData(filmstripItem); 16825a0be52d3db2398cfe01d18adf779d9e443edf82Alan Newberger Log.v(TAG, "updateViewItem() - recycling old data item and setting new"); 16835a0be52d3db2398cfe01d18adf779d9e443edf82Alan Newberger } else { 16845a0be52d3db2398cfe01d18adf779d9e443edf82Alan Newberger Log.v(TAG, "updateViewItem() - updating data with the same item"); 16855a0be52d3db2398cfe01d18adf779d9e443edf82Alan Newberger } 16868e29072ca69229a25dc4a856e3635d131613f4caAlan Newberger 16878e29072ca69229a25dc4a856e3635d131613f4caAlan Newberger // In case state changed from a new FilmStripItem or the existing one, 16888e29072ca69229a25dc4a856e3635d131613f4caAlan Newberger // redraw the View contents. We call getView here as it will refill the 16898e29072ca69229a25dc4a856e3635d131613f4caAlan Newberger // view contents, but it is not clear as we are not using the documented 16908e29072ca69229a25dc4a856e3635d131613f4caAlan Newberger // method intent to get a View, we know that this always uses the view 16918e29072ca69229a25dc4a856e3635d131613f4caAlan Newberger // passed in to populate it. 16928e29072ca69229a25dc4a856e3635d131613f4caAlan Newberger // TODO: refactor 'getView' to more explicitly just update view contents 16938e29072ca69229a25dc4a856e3635d131613f4caAlan Newberger mDataAdapter.getView(item.getView(), adapterIndex, mVideoClickedCallback); 16948e29072ca69229a25dc4a856e3635d131613f4caAlan Newberger 1695d1d28254c1413b4d7725df7d7b38e2a1f2f42e28Angus Kong mZoomView.resetDecoder(); 16963044d8c577432d6e9721fc8b26ac2afbbaf21266Erin Dahlgren 16973044d8c577432d6e9721fc8b26ac2afbbaf21266Erin Dahlgren boolean stopScroll = clampCenterX(); 16983044d8c577432d6e9721fc8b26ac2afbbaf21266Erin Dahlgren if (stopScroll) { 16991f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong mController.stopScrolling(true); 17001f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong } 17018ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde 1702c14b6ba434575b7d795a8cd681821f86a39bc371Paul Rohde Log.d(TAG, "updateViewItem(bufferIndex: " + bufferIndex + ")"); 1703c14b6ba434575b7d795a8cd681821f86a39bc371Paul Rohde Log.d(TAG, "updateViewItem() - mIsUserScrolling: " + mIsUserScrolling); 17048d3552d334196a09e20c83a5296f0b373041032cPaul Rohde Log.d(TAG, "updateViewItem() - mController.isScrolling() - " + mController.isScrolling()); 1705c14b6ba434575b7d795a8cd681821f86a39bc371Paul Rohde 17068d3552d334196a09e20c83a5296f0b373041032cPaul Rohde // Relying on only isScrolling or isUserScrolling independently 17078d3552d334196a09e20c83a5296f0b373041032cPaul Rohde // is unreliable. Load the full resolution if either value 17088d3552d334196a09e20c83a5296f0b373041032cPaul Rohde // reports that the item is not scrolling. 17098d3552d334196a09e20c83a5296f0b373041032cPaul Rohde if (!mController.isScrolling() || !mIsUserScrolling) { 171077d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde renderThumbnail(bufferIndex); 1711c14b6ba434575b7d795a8cd681821f86a39bc371Paul Rohde } 17128ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde 171353aedc0ee671c2d11341a66c444bbb6cdc97b150Angus Kong adjustChildZOrder(); 171453aedc0ee671c2d11341a66c444bbb6cdc97b150Angus Kong invalidate(); 17158a2350a3d557465b53445685db0f9ac838cf90c5Angus Kong if (mListener != null) { 17168e29072ca69229a25dc4a856e3635d131613f4caAlan Newberger mListener.onDataUpdated(adapterIndex); 17178a2350a3d557465b53445685db0f9ac838cf90c5Angus Kong } 171849b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 171949b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 1720f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling /** Some of the data is changed. */ 17218ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde private void update(FilmstripDataAdapter.UpdateReporter reporter) { 172249b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong // No data yet. 17238ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (mViewItems[BUFFER_CENTER] == null) { 172449b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong reload(); 172549b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong return; 172649b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 172749b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 172849b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong // Check the current one. 17298ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde ViewItem curr = mViewItems[BUFFER_CENTER]; 17308ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde int index = curr.getAdapterIndex(); 17318ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (reporter.isDataRemoved(index)) { 173249b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong reload(); 173349b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong return; 173449b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 17358ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (reporter.isDataUpdated(index)) { 17368ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde updateViewItem(BUFFER_CENTER); 17378ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde final FilmstripItem data = mDataAdapter.getFilmstripItemAt(index); 1738a5d6b243d3d742cf9dd2ffdac88d386abacd123aAngus Kong if (!mIsUserScrolling && !mController.isScrolling()) { 1739a5d6b243d3d742cf9dd2ffdac88d386abacd123aAngus Kong // If there is no scrolling at all, adjust mCenterX to place 1740a5d6b243d3d742cf9dd2ffdac88d386abacd123aAngus Kong // the current item at the center. 17418ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde Point dim = CameraUtil.resizeToFill( 174251cafa0a35546a42c573357aa7a031a79cf9ba1bAlan Newberger data.getDimensions().getWidth(), 174351cafa0a35546a42c573357aa7a031a79cf9ba1bAlan Newberger data.getDimensions().getHeight(), 174451cafa0a35546a42c573357aa7a031a79cf9ba1bAlan Newberger data.getOrientation(), 17458ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde getMeasuredWidth(), 17468ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde getMeasuredHeight()); 1747c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong mCenterX = curr.getLeftPosition() + dim.x / 2; 1748a5d6b243d3d742cf9dd2ffdac88d386abacd123aAngus Kong } 174949b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 175049b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 175149b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong // Check left 17528ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde for (int i = BUFFER_CENTER - 1; i >= 0; i--) { 17538ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde curr = mViewItems[i]; 175449b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong if (curr != null) { 17558ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde index = curr.getAdapterIndex(); 17568ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (reporter.isDataRemoved(index) || reporter.isDataUpdated(index)) { 17578969a67c926608737f3e49f2d2240298372e8416Angus Kong updateViewItem(i); 175849b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 17598ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde 176049b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } else { 17618ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde ViewItem next = mViewItems[i + 1]; 176287f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong if (next != null) { 17638ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mViewItems[i] = buildViewItemAt(next.getAdapterIndex() - 1); 176487f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong } 176549b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 176649b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 176749b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 176849b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong // Check right 17698ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde for (int i = BUFFER_CENTER + 1; i < BUFFER_SIZE; i++) { 17708ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde curr = mViewItems[i]; 177149b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong if (curr != null) { 17728ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde index = curr.getAdapterIndex(); 17738ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (reporter.isDataRemoved(index) || reporter.isDataUpdated(index)) { 17748969a67c926608737f3e49f2d2240298372e8416Angus Kong updateViewItem(i); 177549b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 177649b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } else { 17778ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde ViewItem prev = mViewItems[i - 1]; 177887f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong if (prev != null) { 17798ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mViewItems[i] = buildViewItemAt(prev.getAdapterIndex() + 1); 178087f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong } 178149b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 178249b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 178353aedc0ee671c2d11341a66c444bbb6cdc97b150Angus Kong adjustChildZOrder(); 1784b7a52a4caafd270dbb6aaa41f890a516359e44b8Erin Dahlgren // Request a layout to find the measured width/height of the view first. 17858969a67c926608737f3e49f2d2240298372e8416Angus Kong requestLayout(); 178649b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 178749b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 1788f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling /** 1789f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling * The whole data might be totally different. Flush all and load from the 17903f969c1735e2636bf22dfe44104d0e99924cca97Alan Newberger * start. Filmstrip will be centered on the first item, i.e. the camera 17913f969c1735e2636bf22dfe44104d0e99924cca97Alan Newberger * preview. 1792f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling */ 179349b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong private void reload() { 17947d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong mController.stopScrolling(true); 17957d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong mController.stopScale(); 17968ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mAdapterIndexUserIsScrollingOver = 0; 179756e44af257d65d730f04d1e90c87f5674abd7f26ztenghui 1798faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong int prevId = -1; 17998ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (mViewItems[BUFFER_CENTER] != null) { 18008ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde prevId = mViewItems[BUFFER_CENTER].getAdapterIndex(); 18017d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong } 180256e44af257d65d730f04d1e90c87f5674abd7f26ztenghui 18038ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde // Remove all views from the mViewItems buffer, except the camera view. 18048ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde for (int i = 0; i < mViewItems.length; i++) { 18058ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (mViewItems[i] == null) { 18063f969c1735e2636bf22dfe44104d0e99924cca97Alan Newberger continue; 18073f969c1735e2636bf22dfe44104d0e99924cca97Alan Newberger } 18085a0be52d3db2398cfe01d18adf779d9e443edf82Alan Newberger mViewItems[i].removeViewFromHierarchy(); 18093f969c1735e2636bf22dfe44104d0e99924cca97Alan Newberger } 18103f969c1735e2636bf22dfe44104d0e99924cca97Alan Newberger 18113f969c1735e2636bf22dfe44104d0e99924cca97Alan Newberger // Clear out the mViewItems and rebuild with camera in the center. 18128ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde Arrays.fill(mViewItems, null); 181349b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong int dataNumber = mDataAdapter.getTotalNumber(); 1814f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling if (dataNumber == 0) { 1815f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling return; 1816f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling } 181749b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 18188ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mViewItems[BUFFER_CENTER] = buildViewItemAt(0); 18198ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (mViewItems[BUFFER_CENTER] == null) { 18203d0b691b8f7a844093e8de9267ffa2ce16d0c5a9Angus Kong return; 18213d0b691b8f7a844093e8de9267ffa2ce16d0c5a9Angus Kong } 18228ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mViewItems[BUFFER_CENTER].setLeftPosition(0); 18238ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde for (int i = BUFFER_CENTER + 1; i < BUFFER_SIZE; i++) { 18248ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mViewItems[i] = buildViewItemAt(mViewItems[i - 1].getAdapterIndex() + 1); 18258ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (mViewItems[i] == null) { 18263f969c1735e2636bf22dfe44104d0e99924cca97Alan Newberger break; 182749b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 182849b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 18293f969c1735e2636bf22dfe44104d0e99924cca97Alan Newberger 18308ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde // Ensure that the views in mViewItems will layout the first in the 18313f969c1735e2636bf22dfe44104d0e99924cca97Alan Newberger // center of the display upon a reload. 18323f969c1735e2636bf22dfe44104d0e99924cca97Alan Newberger mCenterX = -1; 1833166e36fb6e04d40a1bef0459ee6b96c9c736039bAngus Kong mScale = FILM_STRIP_SCALE; 18343f969c1735e2636bf22dfe44104d0e99924cca97Alan Newberger 183553aedc0ee671c2d11341a66c444bbb6cdc97b150Angus Kong adjustChildZOrder(); 18368ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde 1837c14b6ba434575b7d795a8cd681821f86a39bc371Paul Rohde Log.d(TAG, "reload() - Ensure all items are loaded at max size."); 183877d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde renderAllThumbnails(); 18397d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong invalidate(); 1840742cd5b18e1899bee1d430b61891238c0f3502b6Doris Liu 18417d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong if (mListener != null) { 1842c02b13af4c44fe23d4a563d3c2df1ca50e44affcAngus Kong mListener.onDataReloaded(); 18438ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mListener.onDataFocusChanged(prevId, mViewItems[BUFFER_CENTER].getAdapterIndex()); 18447d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong } 184549b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 184649b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 18478ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde private void promoteData(int index) { 184887f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong if (mListener != null) { 18498ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mListener.onFocusedDataPromoted(index); 185087f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong } 185187f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong } 185287f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong 18538ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde private void demoteData(int index) { 185487f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong if (mListener != null) { 18558ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mListener.onFocusedDataDemoted(index); 185687f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong } 185787f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong } 185887f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong 1859faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong private void onEnterFilmstrip() { 1860c14b6ba434575b7d795a8cd681821f86a39bc371Paul Rohde Log.d(TAG, "onEnterFilmstrip()"); 1861faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong if (mListener != null) { 18628ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mListener.onEnterFilmstrip(getCurrentItemAdapterIndex()); 1863faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong } 1864faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong } 1865faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong 1866faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong private void onLeaveFilmstrip() { 1867faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong if (mListener != null) { 18688ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mListener.onLeaveFilmstrip(getCurrentItemAdapterIndex()); 1869faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong } 1870faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong } 1871faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong 1872faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong private void onEnterFullScreen() { 18734567160a43fa5787012bf0b618c216cf18ac0457Angus Kong mFullScreenUIHidden = false; 1874faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong if (mListener != null) { 18758ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mListener.onEnterFullScreenUiShown(getCurrentItemAdapterIndex()); 1876faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong } 1877faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong } 1878faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong 1879faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong private void onLeaveFullScreen() { 1880faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong if (mListener != null) { 18818ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mListener.onLeaveFullScreenUiShown(getCurrentItemAdapterIndex()); 18824567160a43fa5787012bf0b618c216cf18ac0457Angus Kong } 18834567160a43fa5787012bf0b618c216cf18ac0457Angus Kong } 18844567160a43fa5787012bf0b618c216cf18ac0457Angus Kong 18854567160a43fa5787012bf0b618c216cf18ac0457Angus Kong private void onEnterFullScreenUiHidden() { 18864567160a43fa5787012bf0b618c216cf18ac0457Angus Kong mFullScreenUIHidden = true; 18874567160a43fa5787012bf0b618c216cf18ac0457Angus Kong if (mListener != null) { 18888ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mListener.onEnterFullScreenUiHidden(getCurrentItemAdapterIndex()); 18894567160a43fa5787012bf0b618c216cf18ac0457Angus Kong } 18904567160a43fa5787012bf0b618c216cf18ac0457Angus Kong } 18914567160a43fa5787012bf0b618c216cf18ac0457Angus Kong 18924567160a43fa5787012bf0b618c216cf18ac0457Angus Kong private void onLeaveFullScreenUiHidden() { 18934567160a43fa5787012bf0b618c216cf18ac0457Angus Kong mFullScreenUIHidden = false; 18944567160a43fa5787012bf0b618c216cf18ac0457Angus Kong if (mListener != null) { 18958ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mListener.onLeaveFullScreenUiHidden(getCurrentItemAdapterIndex()); 1896faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong } 1897faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong } 1898faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong 1899faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong private void onEnterZoomView() { 1900faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong if (mListener != null) { 19018ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mListener.onEnterZoomView(getCurrentItemAdapterIndex()); 1902faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong } 1903faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong } 1904faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong 19054567160a43fa5787012bf0b618c216cf18ac0457Angus Kong private void onLeaveZoomView() { 19064567160a43fa5787012bf0b618c216cf18ac0457Angus Kong mController.setSurroundingViewsVisible(true); 19074567160a43fa5787012bf0b618c216cf18ac0457Angus Kong } 19084567160a43fa5787012bf0b618c216cf18ac0457Angus Kong 1909f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling /** 1910f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling * MyController controls all the geometry animations. It passively tells the 1911f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling * geometry information on demand. 1912f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling */ 19138ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde private class FilmstripControllerImpl implements FilmstripController { 191449b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 1915734598c39e6a9d809982dae2907dc7d10e0b0e9fAngus Kong private final ValueAnimator mScaleAnimator; 1916121022cb590955e37f1264f77190ce4711159976Doris Liu private ValueAnimator mZoomAnimator; 1917d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu private AnimatorSet mFlingAnimator; 191849b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 19198ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde private final FilmstripScrollGesture mScrollGesture; 19207d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong private boolean mCanStopScroll; 1921734598c39e6a9d809982dae2907dc7d10e0b0e9fAngus Kong 19228ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde private final FilmstripScrollGesture.Listener mScrollListener = 19238ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde new FilmstripScrollGesture.Listener() { 1924734598c39e6a9d809982dae2907dc7d10e0b0e9fAngus Kong @Override 1925b21215a1a59812592380f31891becedbdec7468bAngus Kong public void onScrollUpdate(int currX, int currY) { 1926b21215a1a59812592380f31891becedbdec7468bAngus Kong mCenterX = currX; 19273044d8c577432d6e9721fc8b26ac2afbbaf21266Erin Dahlgren 19283044d8c577432d6e9721fc8b26ac2afbbaf21266Erin Dahlgren boolean stopScroll = clampCenterX(); 19293044d8c577432d6e9721fc8b26ac2afbbaf21266Erin Dahlgren if (stopScroll) { 1930c14b6ba434575b7d795a8cd681821f86a39bc371Paul Rohde Log.d(TAG, "[fling] onScrollUpdate() - stopScrolling!"); 19311f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong mController.stopScrolling(true); 19321f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong } 1933b21215a1a59812592380f31891becedbdec7468bAngus Kong invalidate(); 1934734598c39e6a9d809982dae2907dc7d10e0b0e9fAngus Kong } 193549b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 1936b21215a1a59812592380f31891becedbdec7468bAngus Kong @Override 1937b21215a1a59812592380f31891becedbdec7468bAngus Kong public void onScrollEnd() { 1938b21215a1a59812592380f31891becedbdec7468bAngus Kong mCanStopScroll = true; 1939c14b6ba434575b7d795a8cd681821f86a39bc371Paul Rohde Log.d(TAG, "[fling] onScrollEnd() - onScrollEnd"); 19408ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (mViewItems[BUFFER_CENTER] == null) { 1941b21215a1a59812592380f31891becedbdec7468bAngus Kong return; 1942b21215a1a59812592380f31891becedbdec7468bAngus Kong } 19438ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde scrollCurrentItemToCenter(); 19448ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde 19458ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde // onScrollEnd will get called twice, once when 19468ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde // the fling part ends, and once when the manual 19478ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde // scroll center animation finishes. Once everything 19488ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde // stops moving ensure that the items are loaded at 19498ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde // full resolution. 19508ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (isCurrentItemCentered()) { 19518ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde // Since these are getting pushed into a queue, 19528ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde // we want to ensure the item that is "most in view" is 19538ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde // the first one rendered at max size. 1954c14b6ba434575b7d795a8cd681821f86a39bc371Paul Rohde 1955c14b6ba434575b7d795a8cd681821f86a39bc371Paul Rohde Log.d(TAG, "[fling] onScrollEnd() - Ensuring that items are at" 1956c14b6ba434575b7d795a8cd681821f86a39bc371Paul Rohde + " full resolution."); 195777d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde renderThumbnail(BUFFER_CENTER); 195877d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde renderThumbnail(BUFFER_CENTER + 1); 195977d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde renderThumbnail(BUFFER_CENTER - 1); 196077d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde renderThumbnail(BUFFER_CENTER + 2); 19618ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde } 19627d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong } 1963b21215a1a59812592380f31891becedbdec7468bAngus Kong }; 1964b21215a1a59812592380f31891becedbdec7468bAngus Kong 1965280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling private final ValueAnimator.AnimatorUpdateListener mScaleAnimatorUpdateListener = 1966b21215a1a59812592380f31891becedbdec7468bAngus Kong new ValueAnimator.AnimatorUpdateListener() { 1967b21215a1a59812592380f31891becedbdec7468bAngus Kong @Override 1968b21215a1a59812592380f31891becedbdec7468bAngus Kong public void onAnimationUpdate(ValueAnimator animation) { 19698ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (mViewItems[BUFFER_CENTER] == null) { 1970b21215a1a59812592380f31891becedbdec7468bAngus Kong return; 1971b21215a1a59812592380f31891becedbdec7468bAngus Kong } 1972b21215a1a59812592380f31891becedbdec7468bAngus Kong mScale = (Float) animation.getAnimatedValue(); 1973b21215a1a59812592380f31891becedbdec7468bAngus Kong invalidate(); 1974b21215a1a59812592380f31891becedbdec7468bAngus Kong } 1975b21215a1a59812592380f31891becedbdec7468bAngus Kong }; 197649b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 19778ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde FilmstripControllerImpl() { 19781f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong TimeInterpolator decelerateInterpolator = new DecelerateInterpolator(1.5f); 19798ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mScrollGesture = new FilmstripScrollGesture(mActivity.getAndroidContext(), 19801f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong new Handler(mActivity.getMainLooper()), 19818ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mScrollListener, decelerateInterpolator); 1982734598c39e6a9d809982dae2907dc7d10e0b0e9fAngus Kong mCanStopScroll = true; 1983734598c39e6a9d809982dae2907dc7d10e0b0e9fAngus Kong 198449b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong mScaleAnimator = new ValueAnimator(); 1985b21215a1a59812592380f31891becedbdec7468bAngus Kong mScaleAnimator.addUpdateListener(mScaleAnimatorUpdateListener); 19861f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong mScaleAnimator.setInterpolator(decelerateInterpolator); 1987faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong mScaleAnimator.addListener(new Animator.AnimatorListener() { 1988faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong @Override 1989faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong public void onAnimationStart(Animator animator) { 1990faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong if (mScale == FULL_SCREEN_SCALE) { 1991faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong onLeaveFullScreen(); 1992faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong } else { 1993faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong if (mScale == FILM_STRIP_SCALE) { 1994faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong onLeaveFilmstrip(); 1995faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong } 1996faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong } 1997faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong } 1998faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong 1999faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong @Override 2000faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong public void onAnimationEnd(Animator animator) { 2001faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong if (mScale == FULL_SCREEN_SCALE) { 2002faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong onEnterFullScreen(); 2003faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong } else { 2004faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong if (mScale == FILM_STRIP_SCALE) { 2005faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong onEnterFilmstrip(); 2006faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong } 2007faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong } 2008c8924b2ec3788ca6d0f0af5ca749e5fe7be125ceAndy Huibers zoomAtIndexChanged(); 2009faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong } 2010faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong 2011faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong @Override 2012faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong public void onAnimationCancel(Animator animator) { 2013faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong 2014faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong } 2015faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong 2016faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong @Override 2017faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong public void onAnimationRepeat(Animator animator) { 2018faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong 2019faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong } 2020faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong }); 202149b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 202249b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 20236d23f4c77fde7ddf70e0edd48f46cc22b7f7320eAngus Kong @Override 2024faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong public void setImageGap(int imageGap) { 2025faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong FilmstripView.this.setViewGap(imageGap); 2026628481532e1e58a0a26330d238e850aec5657bceAngus Kong } 2027628481532e1e58a0a26330d238e850aec5657bceAngus Kong 2028628481532e1e58a0a26330d238e850aec5657bceAngus Kong @Override 20298ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde public int getCurrentAdapterIndex() { 20308ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde return FilmstripView.this.getCurrentItemAdapterIndex(); 2031628481532e1e58a0a26330d238e850aec5657bceAngus Kong } 2032628481532e1e58a0a26330d238e850aec5657bceAngus Kong 2033628481532e1e58a0a26330d238e850aec5657bceAngus Kong @Override 20348ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde public void setDataAdapter(FilmstripDataAdapter adapter) { 2035628481532e1e58a0a26330d238e850aec5657bceAngus Kong FilmstripView.this.setDataAdapter(adapter); 2036628481532e1e58a0a26330d238e850aec5657bceAngus Kong } 2037628481532e1e58a0a26330d238e850aec5657bceAngus Kong 2038628481532e1e58a0a26330d238e850aec5657bceAngus Kong @Override 2039628481532e1e58a0a26330d238e850aec5657bceAngus Kong public boolean inFilmstrip() { 2040628481532e1e58a0a26330d238e850aec5657bceAngus Kong return FilmstripView.this.inFilmstrip(); 2041628481532e1e58a0a26330d238e850aec5657bceAngus Kong } 2042628481532e1e58a0a26330d238e850aec5657bceAngus Kong 2043628481532e1e58a0a26330d238e850aec5657bceAngus Kong @Override 2044628481532e1e58a0a26330d238e850aec5657bceAngus Kong public boolean inFullScreen() { 2045628481532e1e58a0a26330d238e850aec5657bceAngus Kong return FilmstripView.this.inFullScreen(); 2046628481532e1e58a0a26330d238e850aec5657bceAngus Kong } 2047628481532e1e58a0a26330d238e850aec5657bceAngus Kong 2048628481532e1e58a0a26330d238e850aec5657bceAngus Kong @Override 20498ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde public void setListener(FilmstripListener listener) { 20508ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde FilmstripView.this.setListener(listener); 2051628481532e1e58a0a26330d238e850aec5657bceAngus Kong } 2052628481532e1e58a0a26330d238e850aec5657bceAngus Kong 2053628481532e1e58a0a26330d238e850aec5657bceAngus Kong @Override 20546d23f4c77fde7ddf70e0edd48f46cc22b7f7320eAngus Kong public boolean isScrolling() { 20558ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde return !mScrollGesture.isFinished(); 2056af24d28f8938a05d2e3c40155e39cbc7ff4d64b7Angus Kong } 2057af24d28f8938a05d2e3c40155e39cbc7ff4d64b7Angus Kong 20586d23f4c77fde7ddf70e0edd48f46cc22b7f7320eAngus Kong @Override 20598de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu public boolean isScaling() { 20608de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu return mScaleAnimator.isRunning(); 2061af24d28f8938a05d2e3c40155e39cbc7ff4d64b7Angus Kong } 2062af24d28f8938a05d2e3c40155e39cbc7ff4d64b7Angus Kong 20638ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde private int estimateMinX(int index, int leftPos, int viewWidth) { 20648ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde return leftPos - (index + 100) * (viewWidth + mViewGapInPixel); 206549b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 206649b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 20678ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde private int estimateMaxX(int index, int leftPos, int viewWidth) { 2068f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling return leftPos 20698ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde + (mDataAdapter.getTotalNumber() - index + 100) 2070faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong * (viewWidth + mViewGapInPixel); 20716d23f4c77fde7ddf70e0edd48f46cc22b7f7320eAngus Kong } 20726d23f4c77fde7ddf70e0edd48f46cc22b7f7320eAngus Kong 2073121022cb590955e37f1264f77190ce4711159976Doris Liu /** Zoom all the way in or out on the image at the given pivot point. */ 2074121022cb590955e37f1264f77190ce4711159976Doris Liu private void zoomAt(final ViewItem current, final float focusX, final float focusY) { 2075121022cb590955e37f1264f77190ce4711159976Doris Liu // End previous zoom animation, if any 2076121022cb590955e37f1264f77190ce4711159976Doris Liu if (mZoomAnimator != null) { 2077121022cb590955e37f1264f77190ce4711159976Doris Liu mZoomAnimator.end(); 2078121022cb590955e37f1264f77190ce4711159976Doris Liu } 2079121022cb590955e37f1264f77190ce4711159976Doris Liu // Calculate end scale 20803179f6a49516833761be5155c4e1244ac0aa17feDoris Liu final float maxScale = getCurrentDataMaxScale(false); 2081121022cb590955e37f1264f77190ce4711159976Doris Liu final float endScale = mScale < maxScale - maxScale * TOLERANCE 2082121022cb590955e37f1264f77190ce4711159976Doris Liu ? maxScale : FULL_SCREEN_SCALE; 2083121022cb590955e37f1264f77190ce4711159976Doris Liu 2084121022cb590955e37f1264f77190ce4711159976Doris Liu mZoomAnimator = new ValueAnimator(); 2085121022cb590955e37f1264f77190ce4711159976Doris Liu mZoomAnimator.setFloatValues(mScale, endScale); 2086121022cb590955e37f1264f77190ce4711159976Doris Liu mZoomAnimator.setDuration(ZOOM_ANIMATION_DURATION_MS); 2087121022cb590955e37f1264f77190ce4711159976Doris Liu mZoomAnimator.addListener(new Animator.AnimatorListener() { 2088121022cb590955e37f1264f77190ce4711159976Doris Liu @Override 2089121022cb590955e37f1264f77190ce4711159976Doris Liu public void onAnimationStart(Animator animation) { 2090121022cb590955e37f1264f77190ce4711159976Doris Liu if (mScale == FULL_SCREEN_SCALE) { 20914567160a43fa5787012bf0b618c216cf18ac0457Angus Kong if (mFullScreenUIHidden) { 20924567160a43fa5787012bf0b618c216cf18ac0457Angus Kong onLeaveFullScreenUiHidden(); 20934567160a43fa5787012bf0b618c216cf18ac0457Angus Kong } else { 20944567160a43fa5787012bf0b618c216cf18ac0457Angus Kong onLeaveFullScreen(); 20954567160a43fa5787012bf0b618c216cf18ac0457Angus Kong } 2096121022cb590955e37f1264f77190ce4711159976Doris Liu setSurroundingViewsVisible(false); 20974567160a43fa5787012bf0b618c216cf18ac0457Angus Kong } else if (inZoomView()) { 20984567160a43fa5787012bf0b618c216cf18ac0457Angus Kong onLeaveZoomView(); 2099121022cb590955e37f1264f77190ce4711159976Doris Liu } 2100121022cb590955e37f1264f77190ce4711159976Doris Liu cancelLoadingZoomedImage(); 2101121022cb590955e37f1264f77190ce4711159976Doris Liu } 2102121022cb590955e37f1264f77190ce4711159976Doris Liu 2103121022cb590955e37f1264f77190ce4711159976Doris Liu @Override 2104121022cb590955e37f1264f77190ce4711159976Doris Liu public void onAnimationEnd(Animator animation) { 2105121022cb590955e37f1264f77190ce4711159976Doris Liu // Make sure animation ends up having the correct scale even 2106121022cb590955e37f1264f77190ce4711159976Doris Liu // if it is cancelled before it finishes 2107121022cb590955e37f1264f77190ce4711159976Doris Liu if (mScale != endScale) { 2108280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling current.postScale(focusX, focusY, endScale / mScale, mDrawArea.width(), 2109121022cb590955e37f1264f77190ce4711159976Doris Liu mDrawArea.height()); 2110121022cb590955e37f1264f77190ce4711159976Doris Liu mScale = endScale; 2111121022cb590955e37f1264f77190ce4711159976Doris Liu } 2112121022cb590955e37f1264f77190ce4711159976Doris Liu 21134567160a43fa5787012bf0b618c216cf18ac0457Angus Kong if (inFullScreen()) { 2114121022cb590955e37f1264f77190ce4711159976Doris Liu setSurroundingViewsVisible(true); 2115121022cb590955e37f1264f77190ce4711159976Doris Liu mZoomView.setVisibility(GONE); 2116121022cb590955e37f1264f77190ce4711159976Doris Liu current.resetTransform(); 21174567160a43fa5787012bf0b618c216cf18ac0457Angus Kong onEnterFullScreenUiHidden(); 2118121022cb590955e37f1264f77190ce4711159976Doris Liu } else { 2119121022cb590955e37f1264f77190ce4711159976Doris Liu mController.loadZoomedImage(); 2120faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong onEnterZoomView(); 2121121022cb590955e37f1264f77190ce4711159976Doris Liu } 2122121022cb590955e37f1264f77190ce4711159976Doris Liu mZoomAnimator = null; 2123c8924b2ec3788ca6d0f0af5ca749e5fe7be125ceAndy Huibers zoomAtIndexChanged(); 2124121022cb590955e37f1264f77190ce4711159976Doris Liu } 2125121022cb590955e37f1264f77190ce4711159976Doris Liu 2126121022cb590955e37f1264f77190ce4711159976Doris Liu @Override 2127121022cb590955e37f1264f77190ce4711159976Doris Liu public void onAnimationCancel(Animator animation) { 2128121022cb590955e37f1264f77190ce4711159976Doris Liu // Do nothing. 2129121022cb590955e37f1264f77190ce4711159976Doris Liu } 2130121022cb590955e37f1264f77190ce4711159976Doris Liu 2131121022cb590955e37f1264f77190ce4711159976Doris Liu @Override 2132121022cb590955e37f1264f77190ce4711159976Doris Liu public void onAnimationRepeat(Animator animation) { 2133121022cb590955e37f1264f77190ce4711159976Doris Liu // Do nothing. 2134121022cb590955e37f1264f77190ce4711159976Doris Liu } 2135121022cb590955e37f1264f77190ce4711159976Doris Liu }); 2136121022cb590955e37f1264f77190ce4711159976Doris Liu 2137121022cb590955e37f1264f77190ce4711159976Doris Liu mZoomAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 2138121022cb590955e37f1264f77190ce4711159976Doris Liu @Override 2139121022cb590955e37f1264f77190ce4711159976Doris Liu public void onAnimationUpdate(ValueAnimator animation) { 2140121022cb590955e37f1264f77190ce4711159976Doris Liu float newScale = (Float) animation.getAnimatedValue(); 2141121022cb590955e37f1264f77190ce4711159976Doris Liu float postScale = newScale / mScale; 2142121022cb590955e37f1264f77190ce4711159976Doris Liu mScale = newScale; 2143121022cb590955e37f1264f77190ce4711159976Doris Liu current.postScale(focusX, focusY, postScale, mDrawArea.width(), 2144121022cb590955e37f1264f77190ce4711159976Doris Liu mDrawArea.height()); 2145121022cb590955e37f1264f77190ce4711159976Doris Liu } 2146121022cb590955e37f1264f77190ce4711159976Doris Liu }); 2147121022cb590955e37f1264f77190ce4711159976Doris Liu mZoomAnimator.start(); 2148121022cb590955e37f1264f77190ce4711159976Doris Liu } 2149121022cb590955e37f1264f77190ce4711159976Doris Liu 21506d23f4c77fde7ddf70e0edd48f46cc22b7f7320eAngus Kong @Override 2151a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong public void scroll(float deltaX) { 21527d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong if (!stopScrolling(false)) { 2153a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong return; 2154a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong } 2155a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong mCenterX += deltaX; 21563044d8c577432d6e9721fc8b26ac2afbbaf21266Erin Dahlgren 21573044d8c577432d6e9721fc8b26ac2afbbaf21266Erin Dahlgren boolean stopScroll = clampCenterX(); 21583044d8c577432d6e9721fc8b26ac2afbbaf21266Erin Dahlgren if (stopScroll) { 21591f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong mController.stopScrolling(true); 21601f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong } 216117e669d695ef2a38d28d5ba2512937836293e9caAngus Kong invalidate(); 2162a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong } 2163a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong 2164a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong @Override 21656d23f4c77fde7ddf70e0edd48f46cc22b7f7320eAngus Kong public void fling(float velocityX) { 21667d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong if (!stopScrolling(false)) { 2167f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling return; 2168f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling } 21698ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde final ViewItem item = mViewItems[BUFFER_CENTER]; 21708969a67c926608737f3e49f2d2240298372e8416Angus Kong if (item == null) { 2171f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling return; 2172f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling } 21736d23f4c77fde7ddf70e0edd48f46cc22b7f7320eAngus Kong 21746d23f4c77fde7ddf70e0edd48f46cc22b7f7320eAngus Kong float scaledVelocityX = velocityX / mScale; 217586f1d1f3664c909d1d949951056c7bb1e9627324Alan Newberger if (inFullScreen() && scaledVelocityX < 0) { 2176a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong // Swipe left in camera preview. 2177faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong goToFilmstrip(); 21786d23f4c77fde7ddf70e0edd48f46cc22b7f7320eAngus Kong } 21796d23f4c77fde7ddf70e0edd48f46cc22b7f7320eAngus Kong 21806d23f4c77fde7ddf70e0edd48f46cc22b7f7320eAngus Kong int w = getWidth(); 21816d23f4c77fde7ddf70e0edd48f46cc22b7f7320eAngus Kong // Estimation of possible length on the left. To ensure the 21826d23f4c77fde7ddf70e0edd48f46cc22b7f7320eAngus Kong // velocity doesn't become too slow eventually, we add a huge number 21836d23f4c77fde7ddf70e0edd48f46cc22b7f7320eAngus Kong // to the estimated maximum. 21848ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde int minX = estimateMinX(item.getAdapterIndex(), item.getLeftPosition(), w); 21856d23f4c77fde7ddf70e0edd48f46cc22b7f7320eAngus Kong // Estimation of possible length on the right. Likewise, exaggerate 21866d23f4c77fde7ddf70e0edd48f46cc22b7f7320eAngus Kong // the possible maximum too. 21878ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde int maxX = estimateMaxX(item.getAdapterIndex(), item.getLeftPosition(), w); 2188b6a8810b7a5ac0df1e19efd26628c01bcb32b97bPaul Rohde 21898ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mScrollGesture.fling(mCenterX, 0, (int) -velocityX, 0, minX, maxX, 0, 0); 21906d23f4c77fde7ddf70e0edd48f46cc22b7f7320eAngus Kong } 21916d23f4c77fde7ddf70e0edd48f46cc22b7f7320eAngus Kong 2192c02b13af4c44fe23d4a563d3c2df1ca50e44affcAngus Kong void flingInsideZoomView(float velocityX, float velocityY) { 21934567160a43fa5787012bf0b618c216cf18ac0457Angus Kong if (!inZoomView()) { 2194d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu return; 2195d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu } 2196d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu 21978ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde final ViewItem current = mViewItems[BUFFER_CENTER]; 2198d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu if (current == null) { 2199d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu return; 2200d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu } 2201d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu 2202d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu final int factor = DECELERATION_FACTOR; 2203d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu // Deceleration curve for distance: 2204d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu // S(t) = s + (e - s) * (1 - (1 - t/T) ^ factor) 2205280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling // Need to find the ending distance (e), so that the starting 2206280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling // velocity is the velocity of fling. 2207d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu // Velocity is the derivative of distance 2208d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu // V(t) = (e - s) * factor * (-1) * (1 - t/T) ^ (factor - 1) * (-1/T) 2209d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu // = (e - s) * factor * (1 - t/T) ^ (factor - 1) / T 2210d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu // Since V(0) = V0, we have e = T / factor * V0 + s 2211d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu 2212d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu // Duration T should be long enough so that at the end of the fling, 2213d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu // image moves at 1 pixel/s for about P = 50ms = 0.05s 2214d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu // i.e. V(T - P) = 1 2215d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu // V(T - P) = V0 * (1 - (T -P) /T) ^ (factor - 1) = 1 2216d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu // T = P * V0 ^ (1 / (factor -1)) 2217d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu 2218d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu final float velocity = Math.max(Math.abs(velocityX), Math.abs(velocityY)); 2219d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu // Dynamically calculate duration 2220d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu final float duration = (float) (FLING_COASTING_DURATION_S 2221280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling * Math.pow(velocity, (1f / (factor - 1f)))); 2222d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu 22231f9db2dfe59c33228103c54523281501ef52c9baAngus Kong final float translationX = current.getTranslationX() * mScale; 22241f9db2dfe59c33228103c54523281501ef52c9baAngus Kong final float translationY = current.getTranslationY() * mScale; 2225d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu 2226d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu final ValueAnimator decelerationX = ValueAnimator.ofFloat(translationX, 2227d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu translationX + duration / factor * velocityX); 2228d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu final ValueAnimator decelerationY = ValueAnimator.ofFloat(translationY, 2229d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu translationY + duration / factor * velocityY); 2230d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu 2231d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu decelerationY.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 2232d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu @Override 2233d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu public void onAnimationUpdate(ValueAnimator animation) { 2234d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu float transX = (Float) decelerationX.getAnimatedValue(); 2235d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu float transY = (Float) decelerationY.getAnimatedValue(); 2236d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu 2237d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu current.updateTransform(transX, transY, mScale, 2238d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu mScale, mDrawArea.width(), mDrawArea.height()); 2239d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu } 2240d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu }); 2241d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu 2242d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu mFlingAnimator = new AnimatorSet(); 2243d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu mFlingAnimator.play(decelerationX).with(decelerationY); 2244d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu mFlingAnimator.setDuration((int) (duration * 1000)); 2245d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu mFlingAnimator.setInterpolator(new TimeInterpolator() { 2246d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu @Override 2247d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu public float getInterpolation(float input) { 2248280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling return (float) (1.0f - Math.pow((1.0f - input), factor)); 2249d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu } 2250d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu }); 2251d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu mFlingAnimator.addListener(new Animator.AnimatorListener() { 2252d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu private boolean mCancelled = false; 2253280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling 2254d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu @Override 2255d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu public void onAnimationStart(Animator animation) { 2256d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu 2257d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu } 2258d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu 2259d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu @Override 2260d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu public void onAnimationEnd(Animator animation) { 2261d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu if (!mCancelled) { 2262d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu loadZoomedImage(); 2263d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu } 2264d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu mFlingAnimator = null; 2265d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu } 2266d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu 2267d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu @Override 2268d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu public void onAnimationCancel(Animator animation) { 2269d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu mCancelled = true; 2270d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu } 2271d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu 2272d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu @Override 2273d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu public void onAnimationRepeat(Animator animation) { 2274d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu 2275d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu } 2276d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu }); 2277d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu mFlingAnimator.start(); 2278d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu } 2279d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu 2280d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu @Override 22817d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong public boolean stopScrolling(boolean forced) { 22827d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong if (!isScrolling()) { 22837d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong return true; 22847d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong } else if (!mCanStopScroll && !forced) { 2285f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling return false; 22863d0b691b8f7a844093e8de9267ffa2ce16d0c5a9Angus Kong } 2287b6a8810b7a5ac0df1e19efd26628c01bcb32b97bPaul Rohde 22888ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mScrollGesture.forceFinished(true); 228949b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong return true; 229049b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 229149b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 22926d23f4c77fde7ddf70e0edd48f46cc22b7f7320eAngus Kong private void stopScale() { 229349b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong mScaleAnimator.cancel(); 229449b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 229549b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 22966d23f4c77fde7ddf70e0edd48f46cc22b7f7320eAngus Kong @Override 2297734598c39e6a9d809982dae2907dc7d10e0b0e9fAngus Kong public void scrollToPosition(int position, int duration, boolean interruptible) { 22988ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (mViewItems[BUFFER_CENTER] == null) { 2299f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling return; 23003d0b691b8f7a844093e8de9267ffa2ce16d0c5a9Angus Kong } 230149b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong mCanStopScroll = interruptible; 23028ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mScrollGesture.startScroll(mCenterX, position - mCenterX, duration); 230349b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 230449b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 2305734598c39e6a9d809982dae2907dc7d10e0b0e9fAngus Kong @Override 2306734598c39e6a9d809982dae2907dc7d10e0b0e9fAngus Kong public boolean goToNextItem() { 23078ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde return goToItem(BUFFER_CENTER + 1); 23088099a371048e45b9161ac63e4d6bd9644fcad5b5Alan Newberger } 23098099a371048e45b9161ac63e4d6bd9644fcad5b5Alan Newberger 23108099a371048e45b9161ac63e4d6bd9644fcad5b5Alan Newberger @Override 23118099a371048e45b9161ac63e4d6bd9644fcad5b5Alan Newberger public boolean goToPreviousItem() { 23128ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde return goToItem(BUFFER_CENTER - 1); 23138099a371048e45b9161ac63e4d6bd9644fcad5b5Alan Newberger } 23148099a371048e45b9161ac63e4d6bd9644fcad5b5Alan Newberger 23158099a371048e45b9161ac63e4d6bd9644fcad5b5Alan Newberger private boolean goToItem(int itemIndex) { 23168ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde final ViewItem nextItem = mViewItems[itemIndex]; 2317734598c39e6a9d809982dae2907dc7d10e0b0e9fAngus Kong if (nextItem == null) { 2318734598c39e6a9d809982dae2907dc7d10e0b0e9fAngus Kong return false; 2319734598c39e6a9d809982dae2907dc7d10e0b0e9fAngus Kong } 2320b21215a1a59812592380f31891becedbdec7468bAngus Kong stopScrolling(true); 2321734598c39e6a9d809982dae2907dc7d10e0b0e9fAngus Kong scrollToPosition(nextItem.getCenterX(), GEOMETRY_ADJUST_TIME_MS * 2, false); 2322b21215a1a59812592380f31891becedbdec7468bAngus Kong 2323734598c39e6a9d809982dae2907dc7d10e0b0e9fAngus Kong return true; 2324734598c39e6a9d809982dae2907dc7d10e0b0e9fAngus Kong } 2325734598c39e6a9d809982dae2907dc7d10e0b0e9fAngus Kong 23266d23f4c77fde7ddf70e0edd48f46cc22b7f7320eAngus Kong private void scaleTo(float scale, int duration) { 23278ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (mViewItems[BUFFER_CENTER] == null) { 23283d0b691b8f7a844093e8de9267ffa2ce16d0c5a9Angus Kong return; 23293d0b691b8f7a844093e8de9267ffa2ce16d0c5a9Angus Kong } 23306d23f4c77fde7ddf70e0edd48f46cc22b7f7320eAngus Kong stopScale(); 233149b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong mScaleAnimator.setDuration(duration); 233249b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong mScaleAnimator.setFloatValues(mScale, scale); 233349b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong mScaleAnimator.start(); 233449b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 233549b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 23366d23f4c77fde7ddf70e0edd48f46cc22b7f7320eAngus Kong @Override 2337faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong public void goToFilmstrip() { 23388ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (mViewItems[BUFFER_CENTER] == null) { 2339ec2fb473c094f8dfd1cc0cf5205d470e412d3919Angus Kong return; 2340ec2fb473c094f8dfd1cc0cf5205d470e412d3919Angus Kong } 2341faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong if (mScale == FILM_STRIP_SCALE) { 2342faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong return; 2343faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong } 2344734598c39e6a9d809982dae2907dc7d10e0b0e9fAngus Kong scaleTo(FILM_STRIP_SCALE, GEOMETRY_ADJUST_TIME_MS); 234517e669d695ef2a38d28d5ba2512937836293e9caAngus Kong 23468ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde final ViewItem currItem = mViewItems[BUFFER_CENTER]; 23478ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde final ViewItem nextItem = mViewItems[BUFFER_CENTER + 1]; 234817e669d695ef2a38d28d5ba2512937836293e9caAngus Kong 2349faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong if (mScale == FILM_STRIP_SCALE) { 2350faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong onLeaveFilmstrip(); 2351a52f04c1ff32b2f529c21b49861a62ad34359e28Doris Liu } 23526d23f4c77fde7ddf70e0edd48f46cc22b7f7320eAngus Kong } 23536d23f4c77fde7ddf70e0edd48f46cc22b7f7320eAngus Kong 23546d23f4c77fde7ddf70e0edd48f46cc22b7f7320eAngus Kong @Override 2355734598c39e6a9d809982dae2907dc7d10e0b0e9fAngus Kong public void goToFullScreen() { 23568de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu if (inFullScreen()) { 23578de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu return; 23588de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu } 2359893ca79bdea899fe3f3ed700c22235cc5b460527Spike Sprague 2360faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong scaleTo(FULL_SCREEN_SCALE, GEOMETRY_ADJUST_TIME_MS); 2361a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong } 2362a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong 2363d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu private void cancelFlingAnimation() { 2364d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu // Cancels flinging for zoomed images 2365d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu if (isFlingAnimationRunning()) { 2366d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu mFlingAnimator.cancel(); 2367d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu } 2368d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu } 2369d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu 2370d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu private void cancelZoomAnimation() { 2371d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu if (isZoomAnimationRunning()) { 2372d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu mZoomAnimator.cancel(); 2373d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu } 2374d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu } 2375d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu 23768de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu private void setSurroundingViewsVisible(boolean visible) { 23778de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu // Hide everything on the left 2378280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling // TODO: Need to find a better way to toggle the visibility of views 2379280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling // around the current view. 23808ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde for (int i = 0; i < BUFFER_CENTER; i++) { 23818ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (mViewItems[i] != null) { 23828ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mViewItems[i].setVisibility(visible ? VISIBLE : INVISIBLE); 23838de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu } 23848de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu } 23858de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu } 23868de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu 2387571a8c389798bd3f01429f6be34cd3e606ab34dfAngus Kong private Uri getCurrentUri() { 23888ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde ViewItem curr = mViewItems[BUFFER_CENTER]; 23898de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu if (curr == null) { 23908de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu return Uri.EMPTY; 23918de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu } 23928ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde return mDataAdapter.getFilmstripItemAt(curr.getAdapterIndex()).getData().getUri(); 23938de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu } 23948de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu 23958de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu /** 23968de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu * Here we only support up to 1:1 image zoom (i.e. a 100% view of the 23978de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu * actual pixels). The max scale that we can apply on the view should 23988de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu * make the view same size as the image, in pixels. 23998de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu */ 24003179f6a49516833761be5155c4e1244ac0aa17feDoris Liu private float getCurrentDataMaxScale(boolean allowOverScale) { 24018ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde ViewItem curr = mViewItems[BUFFER_CENTER]; 24023f192ccf03d0d25521b96304c4464b4bad28150aSascha Haeberling if (curr == null) { 24033f192ccf03d0d25521b96304c4464b4bad28150aSascha Haeberling return FULL_SCREEN_SCALE; 24043f192ccf03d0d25521b96304c4464b4bad28150aSascha Haeberling } 24058ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde FilmstripItem imageData = mDataAdapter.getFilmstripItemAt(curr.getAdapterIndex()); 24068ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (imageData == null || !imageData.getAttributes().canZoomInPlace()) { 24078de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu return FULL_SCREEN_SCALE; 24088de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu } 240951cafa0a35546a42c573357aa7a031a79cf9ba1bAlan Newberger float imageWidth = imageData.getDimensions().getWidth(); 241051cafa0a35546a42c573357aa7a031a79cf9ba1bAlan Newberger if (imageData.getOrientation() == 90 241151cafa0a35546a42c573357aa7a031a79cf9ba1bAlan Newberger || imageData.getOrientation() == 270) { 241251cafa0a35546a42c573357aa7a031a79cf9ba1bAlan Newberger imageWidth = imageData.getDimensions().getHeight(); 241306578b59bf15c1ac35dbbffd979f40479b1cbda9ztenghui } 24143179f6a49516833761be5155c4e1244ac0aa17feDoris Liu float scale = imageWidth / curr.getWidth(); 24153179f6a49516833761be5155c4e1244ac0aa17feDoris Liu if (allowOverScale) { 24163179f6a49516833761be5155c4e1244ac0aa17feDoris Liu // In addition to the scale we apply to the view for 100% view 24173179f6a49516833761be5155c4e1244ac0aa17feDoris Liu // (i.e. each pixel on screen corresponds to a pixel in image) 24183179f6a49516833761be5155c4e1244ac0aa17feDoris Liu // we allow scaling beyond that for better detail viewing. 24193179f6a49516833761be5155c4e1244ac0aa17feDoris Liu scale *= mOverScaleFactor; 24203179f6a49516833761be5155c4e1244ac0aa17feDoris Liu } 24213179f6a49516833761be5155c4e1244ac0aa17feDoris Liu return scale; 24228de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu } 24238de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu 24248de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu private void loadZoomedImage() { 24254567160a43fa5787012bf0b618c216cf18ac0457Angus Kong if (!inZoomView()) { 2426f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling return; 2427f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling } 24288ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde ViewItem curr = mViewItems[BUFFER_CENTER]; 242987fc5e1568f737e03327770cb3dee03c4b939c59Doris Liu if (curr == null) { 243087fc5e1568f737e03327770cb3dee03c4b939c59Doris Liu return; 243187fc5e1568f737e03327770cb3dee03c4b939c59Doris Liu } 24328ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde FilmstripItem imageData = mDataAdapter.getFilmstripItemAt(curr.getAdapterIndex()); 24338ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (!imageData.getAttributes().canZoomInPlace()) { 24348de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu return; 24358de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu } 2436571a8c389798bd3f01429f6be34cd3e606ab34dfAngus Kong Uri uri = getCurrentUri(); 24378de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu RectF viewRect = curr.getViewRect(); 24388de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu if (uri == null || uri == Uri.EMPTY) { 24398de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu return; 24408de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu } 244151cafa0a35546a42c573357aa7a031a79cf9ba1bAlan Newberger int orientation = imageData.getOrientation(); 244287fc5e1568f737e03327770cb3dee03c4b939c59Doris Liu mZoomView.loadBitmap(uri, orientation, viewRect); 24438de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu } 24448de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu 24458de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu private void cancelLoadingZoomedImage() { 24468de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu mZoomView.cancelPartialDecodingTask(); 24476d23f4c77fde7ddf70e0edd48f46cc22b7f7320eAngus Kong } 24486d23f4c77fde7ddf70e0edd48f46cc22b7f7320eAngus Kong 24496d23f4c77fde7ddf70e0edd48f46cc22b7f7320eAngus Kong @Override 24503f969c1735e2636bf22dfe44104d0e99924cca97Alan Newberger public void goToFirstItem() { 24518ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (mViewItems[BUFFER_CENTER] == null) { 2452faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong return; 2453faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong } 245403b75411538c60021799ccc7acc8ed4798253b6dDoris Liu resetZoomView(); 24558ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde // TODO: animate to camera if it is still in the mViewItems buffer 24563f969c1735e2636bf22dfe44104d0e99924cca97Alan Newberger // versus a full reload which will perform an immediate transition 24573f969c1735e2636bf22dfe44104d0e99924cca97Alan Newberger reload(); 245849b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 245949b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 24604567160a43fa5787012bf0b618c216cf18ac0457Angus Kong public boolean inZoomView() { 24614567160a43fa5787012bf0b618c216cf18ac0457Angus Kong return FilmstripView.this.inZoomView(); 246249b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 246349b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 2464d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu public boolean isFlingAnimationRunning() { 2465d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu return mFlingAnimator != null && mFlingAnimator.isRunning(); 2466d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu } 2467d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu 2468b21215a1a59812592380f31891becedbdec7468bAngus Kong public boolean isZoomAnimationRunning() { 2469b21215a1a59812592380f31891becedbdec7468bAngus Kong return mZoomAnimator != null && mZoomAnimator.isRunning(); 247049b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 247186f1d1f3664c909d1d949951056c7bb1e9627324Alan Newberger 247286f1d1f3664c909d1d949951056c7bb1e9627324Alan Newberger @Override 247386f1d1f3664c909d1d949951056c7bb1e9627324Alan Newberger public boolean isVisible(FilmstripItem data) { 247486f1d1f3664c909d1d949951056c7bb1e9627324Alan Newberger for (ViewItem viewItem : mViewItems) { 247586f1d1f3664c909d1d949951056c7bb1e9627324Alan Newberger if (data != null && viewItem != null && viewItem.getVisibility() == VISIBLE 247686f1d1f3664c909d1d949951056c7bb1e9627324Alan Newberger && data.equals(viewItem.mData)) { 247786f1d1f3664c909d1d949951056c7bb1e9627324Alan Newberger return true; 247886f1d1f3664c909d1d949951056c7bb1e9627324Alan Newberger } 247986f1d1f3664c909d1d949951056c7bb1e9627324Alan Newberger } 248086f1d1f3664c909d1d949951056c7bb1e9627324Alan Newberger return false; 248186f1d1f3664c909d1d949951056c7bb1e9627324Alan Newberger } 2482b21215a1a59812592380f31891becedbdec7468bAngus Kong } 248349b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 2484ec2fb473c094f8dfd1cc0cf5205d470e412d3919Angus Kong private boolean isCurrentItemCentered() { 24858ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde return mViewItems[BUFFER_CENTER].getCenterX() == mCenterX; 2486ec2fb473c094f8dfd1cc0cf5205d470e412d3919Angus Kong } 2487ec2fb473c094f8dfd1cc0cf5205d470e412d3919Angus Kong 24888ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde private static class FilmstripScrollGesture { 2489b21215a1a59812592380f31891becedbdec7468bAngus Kong public interface Listener { 2490b21215a1a59812592380f31891becedbdec7468bAngus Kong public void onScrollUpdate(int currX, int currY); 2491280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling 2492b21215a1a59812592380f31891becedbdec7468bAngus Kong public void onScrollEnd(); 2493b21215a1a59812592380f31891becedbdec7468bAngus Kong } 2494b21215a1a59812592380f31891becedbdec7468bAngus Kong 2495280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling private final Handler mHandler; 2496280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling private final Listener mListener; 24971f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong 24981f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong private final Scroller mScroller; 24991f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong 25001f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong private final ValueAnimator mXScrollAnimator; 2501280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling private final Runnable mScrollChecker = new Runnable() { 2502b21215a1a59812592380f31891becedbdec7468bAngus Kong @Override 2503b21215a1a59812592380f31891becedbdec7468bAngus Kong public void run() { 25041f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong boolean newPosition = mScroller.computeScrollOffset(); 2505b21215a1a59812592380f31891becedbdec7468bAngus Kong if (!newPosition) { 2506c14b6ba434575b7d795a8cd681821f86a39bc371Paul Rohde Log.d(TAG, "[fling] onScrollEnd from computeScrollOffset"); 2507b21215a1a59812592380f31891becedbdec7468bAngus Kong mListener.onScrollEnd(); 2508b21215a1a59812592380f31891becedbdec7468bAngus Kong return; 2509af24d28f8938a05d2e3c40155e39cbc7ff4d64b7Angus Kong } 25101f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong mListener.onScrollUpdate(mScroller.getCurrX(), mScroller.getCurrY()); 2511b21215a1a59812592380f31891becedbdec7468bAngus Kong mHandler.removeCallbacks(this); 2512b21215a1a59812592380f31891becedbdec7468bAngus Kong mHandler.post(this); 251349b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 2514b21215a1a59812592380f31891becedbdec7468bAngus Kong }; 2515b21215a1a59812592380f31891becedbdec7468bAngus Kong 2516280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling private final ValueAnimator.AnimatorUpdateListener mXScrollAnimatorUpdateListener = 25171f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong new ValueAnimator.AnimatorUpdateListener() { 25181f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong @Override 25191f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong public void onAnimationUpdate(ValueAnimator animation) { 25201f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong mListener.onScrollUpdate((Integer) animation.getAnimatedValue(), 0); 25211f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong } 25221f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong }; 25231f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong 2524280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling private final Animator.AnimatorListener mXScrollAnimatorListener = 25251f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong new Animator.AnimatorListener() { 25261f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong @Override 25271f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong public void onAnimationCancel(Animator animation) { 2528c14b6ba434575b7d795a8cd681821f86a39bc371Paul Rohde Log.d(TAG, "[fling] mXScrollAnimatorListener.onAnimationCancel"); 25291f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong // Do nothing. 25301f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong } 25311f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong 25321f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong @Override 25331f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong public void onAnimationEnd(Animator animation) { 2534c14b6ba434575b7d795a8cd681821f86a39bc371Paul Rohde Log.d(TAG, "[fling] onScrollEnd from mXScrollAnimatorListener.onAnimationEnd"); 25351f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong mListener.onScrollEnd(); 25361f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong } 25371f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong 25381f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong @Override 25391f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong public void onAnimationRepeat(Animator animation) { 2540c14b6ba434575b7d795a8cd681821f86a39bc371Paul Rohde Log.d(TAG, "[fling] mXScrollAnimatorListener.onAnimationRepeat"); 25411f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong // Do nothing. 25421f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong } 25431f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong 25441f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong @Override 25451f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong public void onAnimationStart(Animator animation) { 2546c14b6ba434575b7d795a8cd681821f86a39bc371Paul Rohde Log.d(TAG, "[fling] mXScrollAnimatorListener.onAnimationStart"); 25471f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong // Do nothing. 25481f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong } 25491f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong }; 25501f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong 25518ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde public FilmstripScrollGesture(Context ctx, Handler handler, Listener listener, 25528ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde TimeInterpolator interpolator) { 2553b21215a1a59812592380f31891becedbdec7468bAngus Kong mHandler = handler; 2554b21215a1a59812592380f31891becedbdec7468bAngus Kong mListener = listener; 25551f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong mScroller = new Scroller(ctx); 25561f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong mXScrollAnimator = new ValueAnimator(); 25571f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong mXScrollAnimator.addUpdateListener(mXScrollAnimatorUpdateListener); 25581f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong mXScrollAnimator.addListener(mXScrollAnimatorListener); 25591f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong mXScrollAnimator.setInterpolator(interpolator); 256049b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 256149b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 2562b21215a1a59812592380f31891becedbdec7468bAngus Kong public void fling( 2563b21215a1a59812592380f31891becedbdec7468bAngus Kong int startX, int startY, 2564b21215a1a59812592380f31891becedbdec7468bAngus Kong int velocityX, int velocityY, 2565b21215a1a59812592380f31891becedbdec7468bAngus Kong int minX, int maxX, 2566b21215a1a59812592380f31891becedbdec7468bAngus Kong int minY, int maxY) { 25671f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong mScroller.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY); 2568b21215a1a59812592380f31891becedbdec7468bAngus Kong runChecker(); 256949b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 257049b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 2571b21215a1a59812592380f31891becedbdec7468bAngus Kong public void startScroll(int startX, int startY, int dx, int dy) { 25721f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong mScroller.startScroll(startX, startY, dx, dy); 2573b21215a1a59812592380f31891becedbdec7468bAngus Kong runChecker(); 257449b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 25758de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu 25761f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong /** Only starts and updates scroll in x-axis. */ 25778ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde public void startScroll(int startX, int dx, int duration) { 25781f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong mXScrollAnimator.cancel(); 25791f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong mXScrollAnimator.setDuration(duration); 25801f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong mXScrollAnimator.setIntValues(startX, startX + dx); 25811f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong mXScrollAnimator.start(); 25821f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong } 25831f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong 25841f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong public boolean isFinished() { 25851f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong return (mScroller.isFinished() && !mXScrollAnimator.isRunning()); 25861f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong } 25871f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong 25881f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong public void forceFinished(boolean finished) { 25891f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong mScroller.forceFinished(finished); 25901f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong if (finished) { 25911f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong mXScrollAnimator.cancel(); 25921f36cf1c97faf2b7824bbecd62942456847f0e13Angus Kong } 25938de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu } 2594121022cb590955e37f1264f77190ce4711159976Doris Liu 2595b21215a1a59812592380f31891becedbdec7468bAngus Kong private void runChecker() { 2596b21215a1a59812592380f31891becedbdec7468bAngus Kong if (mHandler == null || mListener == null) { 2597b21215a1a59812592380f31891becedbdec7468bAngus Kong return; 2598b21215a1a59812592380f31891becedbdec7468bAngus Kong } 2599b21215a1a59812592380f31891becedbdec7468bAngus Kong mHandler.removeCallbacks(mScrollChecker); 2600b21215a1a59812592380f31891becedbdec7468bAngus Kong mHandler.post(mScrollChecker); 2601121022cb590955e37f1264f77190ce4711159976Doris Liu } 260249b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 260349b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 26048ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde private class FilmstripGestures implements FilmstripGestureRecognizer.Listener { 260569f0964a91a035c222d1765768dbb8d175c3b0f7Angus Kong 260669f0964a91a035c222d1765768dbb8d175c3b0f7Angus Kong private static final int SCROLL_DIR_NONE = 0; 260769f0964a91a035c222d1765768dbb8d175c3b0f7Angus Kong private static final int SCROLL_DIR_VERTICAL = 1; 260869f0964a91a035c222d1765768dbb8d175c3b0f7Angus Kong private static final int SCROLL_DIR_HORIZONTAL = 2; 260949b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong // Indicating the current trend of scaling is up (>1) or down (<1). 261049b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong private float mScaleTrend; 26118de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu private float mMaxScale; 261269f0964a91a035c222d1765768dbb8d175c3b0f7Angus Kong private int mScrollingDirection = SCROLL_DIR_NONE; 2613bcd1152e8214b1fb4a17963ffe8c292681c81688Sam Judd private long mLastDownTime; 2614bcd1152e8214b1fb4a17963ffe8c292681c81688Sam Judd private float mLastDownY; 261549b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 2616e7263f7ea45cf31d3948984ba8514e03ef86627ePaul Rohde private ViewItem mCurrentlyScalingItem; 2617e7263f7ea45cf31d3948984ba8514e03ef86627ePaul Rohde 261849b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong @Override 261949b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong public boolean onSingleTapUp(float x, float y) { 26208ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde ViewItem centerItem = mViewItems[BUFFER_CENTER]; 2621628481532e1e58a0a26330d238e850aec5657bceAngus Kong if (inFilmstrip()) { 26228969a67c926608737f3e49f2d2240298372e8416Angus Kong if (centerItem != null && centerItem.areaContains(x, y)) { 2623734598c39e6a9d809982dae2907dc7d10e0b0e9fAngus Kong mController.goToFullScreen(); 2624a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong return true; 2625a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong } 2626a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong } else if (inFullScreen()) { 26274567160a43fa5787012bf0b618c216cf18ac0457Angus Kong if (mFullScreenUIHidden) { 26284567160a43fa5787012bf0b618c216cf18ac0457Angus Kong onLeaveFullScreenUiHidden(); 26294567160a43fa5787012bf0b618c216cf18ac0457Angus Kong onEnterFullScreen(); 26304567160a43fa5787012bf0b618c216cf18ac0457Angus Kong } else { 26314567160a43fa5787012bf0b618c216cf18ac0457Angus Kong onLeaveFullScreen(); 26324567160a43fa5787012bf0b618c216cf18ac0457Angus Kong onEnterFullScreenUiHidden(); 26334567160a43fa5787012bf0b618c216cf18ac0457Angus Kong } 2634a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong return true; 2635a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong } 263649b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong return false; 26377e1c5fe26bc861d979b85014a511ba35bc1f4110Angus Kong } 26387e1c5fe26bc861d979b85014a511ba35bc1f4110Angus Kong 26397e1c5fe26bc861d979b85014a511ba35bc1f4110Angus Kong @Override 26407e1c5fe26bc861d979b85014a511ba35bc1f4110Angus Kong public boolean onDoubleTap(float x, float y) { 26418ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde ViewItem current = mViewItems[BUFFER_CENTER]; 26424567160a43fa5787012bf0b618c216cf18ac0457Angus Kong if (current == null) { 26434567160a43fa5787012bf0b618c216cf18ac0457Angus Kong return false; 26444567160a43fa5787012bf0b618c216cf18ac0457Angus Kong } 26454567160a43fa5787012bf0b618c216cf18ac0457Angus Kong if (inFilmstrip()) { 26465326f0265206ccd8a2f3424bb983da674b20a31eDoris Liu mController.goToFullScreen(); 26475326f0265206ccd8a2f3424bb983da674b20a31eDoris Liu return true; 264886f1d1f3664c909d1d949951056c7bb1e9627324Alan Newberger } else if (mScale < FULL_SCREEN_SCALE) { 2649121022cb590955e37f1264f77190ce4711159976Doris Liu return false; 2650121022cb590955e37f1264f77190ce4711159976Doris Liu } 26517d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong if (!mController.stopScrolling(false)) { 26527d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong return false; 2653e1d5ba4fc5470043e8645984e3018b712f5dfcffDoris Liu } 26544567160a43fa5787012bf0b618c216cf18ac0457Angus Kong if (inFullScreen()) { 26554567160a43fa5787012bf0b618c216cf18ac0457Angus Kong mController.zoomAt(current, x, y); 265677d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde renderFullRes(BUFFER_CENTER); 26574567160a43fa5787012bf0b618c216cf18ac0457Angus Kong return true; 26584567160a43fa5787012bf0b618c216cf18ac0457Angus Kong } else if (mScale > FULL_SCREEN_SCALE) { 26594567160a43fa5787012bf0b618c216cf18ac0457Angus Kong // In zoom view. 26604567160a43fa5787012bf0b618c216cf18ac0457Angus Kong mController.zoomAt(current, x, y); 26614567160a43fa5787012bf0b618c216cf18ac0457Angus Kong } 26624567160a43fa5787012bf0b618c216cf18ac0457Angus Kong return false; 266349b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 266449b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 266549b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong @Override 266649b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong public boolean onDown(float x, float y) { 2667bcd1152e8214b1fb4a17963ffe8c292681c81688Sam Judd mLastDownTime = SystemClock.uptimeMillis(); 2668bcd1152e8214b1fb4a17963ffe8c292681c81688Sam Judd mLastDownY = y; 2669d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu mController.cancelFlingAnimation(); 26707d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong if (!mController.stopScrolling(false)) { 26717d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong return false; 2672a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong } 2673b0288ec84e06b83923180a04e1b546724fcfd258Doris Liu 267449b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong return true; 267549b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 267649b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 267749b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong @Override 267887f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong public boolean onUp(float x, float y) { 26798ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde ViewItem currItem = mViewItems[BUFFER_CENTER]; 26807d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong if (currItem == null) { 26817d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong return false; 26827d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong } 2683d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu if (mController.isZoomAnimationRunning() || mController.isFlingAnimationRunning()) { 2684121022cb590955e37f1264f77190ce4711159976Doris Liu return false; 2685121022cb590955e37f1264f77190ce4711159976Doris Liu } 26864567160a43fa5787012bf0b618c216cf18ac0457Angus Kong if (inZoomView()) { 26878de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu mController.loadZoomedImage(); 26888de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu return true; 26898de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu } 2690bcd1152e8214b1fb4a17963ffe8c292681c81688Sam Judd float promoteHeight = getHeight() * PROMOTE_HEIGHT_RATIO; 2691bcd1152e8214b1fb4a17963ffe8c292681c81688Sam Judd float velocityPromoteHeight = getHeight() * VELOCITY_PROMOTE_HEIGHT_RATIO; 269247721fa8f2dc13cb565ae5629a417dc4ed298e81Angus Kong mIsUserScrolling = false; 269369f0964a91a035c222d1765768dbb8d175c3b0f7Angus Kong mScrollingDirection = SCROLL_DIR_NONE; 26947d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong // Finds items promoted/demoted. 2695bcd1152e8214b1fb4a17963ffe8c292681c81688Sam Judd float speedY = Math.abs(y - mLastDownY) 2696bcd1152e8214b1fb4a17963ffe8c292681c81688Sam Judd / (SystemClock.uptimeMillis() - mLastDownTime); 269749b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong for (int i = 0; i < BUFFER_SIZE; i++) { 26988ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (mViewItems[i] == null) { 2699f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling continue; 2700f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling } 27018ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde float transY = mViewItems[i].getTranslationY(); 2702f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling if (transY == 0) { 2703f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling continue; 2704f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling } 27058ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde int index = mViewItems[i].getAdapterIndex(); 270687f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong 27078ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (mDataAdapter.getFilmstripItemAt(index).getAttributes().canSwipeAway() 2708bcd1152e8214b1fb4a17963ffe8c292681c81688Sam Judd && ((transY > promoteHeight) 2709bcd1152e8214b1fb4a17963ffe8c292681c81688Sam Judd || (transY > velocityPromoteHeight && speedY > PROMOTE_VELOCITY))) { 27108ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde demoteData(index); 27118ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde } else if (mDataAdapter.getFilmstripItemAt(index).getAttributes().canSwipeAway() 2712bcd1152e8214b1fb4a17963ffe8c292681c81688Sam Judd && (transY < -promoteHeight 2713bcd1152e8214b1fb4a17963ffe8c292681c81688Sam Judd || (transY < -velocityPromoteHeight && speedY > PROMOTE_VELOCITY))) { 27148ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde promoteData(index); 271587f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong } else { 27169f02c87cfb5039a72f516ea5edc0378c45ac5779Angus Kong // put the view back. 27178ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde slideViewBack(mViewItems[i]); 271887f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong } 271987f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong } 27207d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong 27211f9db2dfe59c33228103c54523281501ef52c9baAngus Kong // The data might be changed. Re-check. 27228ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde currItem = mViewItems[BUFFER_CENTER]; 27231f9db2dfe59c33228103c54523281501ef52c9baAngus Kong if (currItem == null) { 27241f9db2dfe59c33228103c54523281501ef52c9baAngus Kong return true; 27251f9db2dfe59c33228103c54523281501ef52c9baAngus Kong } 27261f9db2dfe59c33228103c54523281501ef52c9baAngus Kong 27278ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde int currId = currItem.getAdapterIndex(); 272886f1d1f3664c909d1d949951056c7bb1e9627324Alan Newberger if (mAdapterIndexUserIsScrollingOver == 0 && currId != 0) { 272986f1d1f3664c909d1d949951056c7bb1e9627324Alan Newberger // Special case to go to filmstrip when the user scroll away 273086f1d1f3664c909d1d949951056c7bb1e9627324Alan Newberger // from the camera preview and the current one is not the 273186f1d1f3664c909d1d949951056c7bb1e9627324Alan Newberger // preview anymore. 2732faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong mController.goToFilmstrip(); 273386f1d1f3664c909d1d949951056c7bb1e9627324Alan Newberger mAdapterIndexUserIsScrollingOver = currId; 27347d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong } 273586f1d1f3664c909d1d949951056c7bb1e9627324Alan Newberger scrollCurrentItemToCenter(); 273687f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong return false; 273787f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong } 273887f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong 273987f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong @Override 274026795a9258c0815ca2a92d2c660438066f001022Angus Kong public void onLongPress(float x, float y) { 27418ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde final int index = getCurrentItemAdapterIndex(); 27428ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (index == -1) { 274326795a9258c0815ca2a92d2c660438066f001022Angus Kong return; 274426795a9258c0815ca2a92d2c660438066f001022Angus Kong } 27458ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mListener.onFocusedDataLongPressed(index); 274626795a9258c0815ca2a92d2c660438066f001022Angus Kong } 274726795a9258c0815ca2a92d2c660438066f001022Angus Kong 274826795a9258c0815ca2a92d2c660438066f001022Angus Kong @Override 274987f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong public boolean onScroll(float x, float y, float dx, float dy) { 27508ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde final ViewItem currItem = mViewItems[BUFFER_CENTER]; 27517be0e2b8439d525c70cb062c6616d10c4fc004aaztenghui if (currItem == null) { 27527be0e2b8439d525c70cb062c6616d10c4fc004aaztenghui return false; 27537be0e2b8439d525c70cb062c6616d10c4fc004aaztenghui } 2754b6a8810b7a5ac0df1e19efd26628c01bcb32b97bPaul Rohde 2755b0288ec84e06b83923180a04e1b546724fcfd258Doris Liu hideZoomView(); 27568de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu // When image is zoomed in to be bigger than the screen 27574567160a43fa5787012bf0b618c216cf18ac0457Angus Kong if (inZoomView()) { 27588ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde ViewItem curr = mViewItems[BUFFER_CENTER]; 27591f9db2dfe59c33228103c54523281501ef52c9baAngus Kong float transX = curr.getTranslationX() * mScale - dx; 27601f9db2dfe59c33228103c54523281501ef52c9baAngus Kong float transY = curr.getTranslationY() * mScale - dy; 27618de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu curr.updateTransform(transX, transY, mScale, mScale, mDrawArea.width(), 27628de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu mDrawArea.height()); 27638de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu return true; 27648de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu } 2765a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong int deltaX = (int) (dx / mScale); 27667d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong // Forces the current scrolling to stop. 27677d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong mController.stopScrolling(true); 27687d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong if (!mIsUserScrolling) { 27697d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong mIsUserScrolling = true; 27708ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mAdapterIndexUserIsScrollingOver = 27718ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mViewItems[BUFFER_CENTER].getAdapterIndex(); 27727d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong } 2773628481532e1e58a0a26330d238e850aec5657bceAngus Kong if (inFilmstrip()) { 277469f0964a91a035c222d1765768dbb8d175c3b0f7Angus Kong // Disambiguate horizontal/vertical first. 277569f0964a91a035c222d1765768dbb8d175c3b0f7Angus Kong if (mScrollingDirection == SCROLL_DIR_NONE) { 277669f0964a91a035c222d1765768dbb8d175c3b0f7Angus Kong mScrollingDirection = (Math.abs(dx) > Math.abs(dy)) ? SCROLL_DIR_HORIZONTAL : 277769f0964a91a035c222d1765768dbb8d175c3b0f7Angus Kong SCROLL_DIR_VERTICAL; 277869f0964a91a035c222d1765768dbb8d175c3b0f7Angus Kong } 277969f0964a91a035c222d1765768dbb8d175c3b0f7Angus Kong if (mScrollingDirection == SCROLL_DIR_HORIZONTAL) { 27808ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (mCenterX == currItem.getCenterX() && currItem.getAdapterIndex() == 0 && 27818ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde dx < 0) { 278269f0964a91a035c222d1765768dbb8d175c3b0f7Angus Kong // Already at the beginning, don't process the swipe. 278369f0964a91a035c222d1765768dbb8d175c3b0f7Angus Kong mIsUserScrolling = false; 278469f0964a91a035c222d1765768dbb8d175c3b0f7Angus Kong mScrollingDirection = SCROLL_DIR_NONE; 278569f0964a91a035c222d1765768dbb8d175c3b0f7Angus Kong return false; 278669f0964a91a035c222d1765768dbb8d175c3b0f7Angus Kong } 2787a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong mController.scroll(deltaX); 2788a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong } else { 2789a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong // Vertical part. Promote or demote. 2790a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong int hit = 0; 2791a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong Rect hitRect = new Rect(); 2792a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong for (; hit < BUFFER_SIZE; hit++) { 27938ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (mViewItems[hit] == null) { 2794f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling continue; 2795f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling } 27968ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mViewItems[hit].getHitRect(hitRect); 2797f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling if (hitRect.contains((int) x, (int) y)) { 2798f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling break; 2799f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling } 2800f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling } 2801f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling if (hit == BUFFER_SIZE) { 2802166e36fb6e04d40a1bef0459ee6b96c9c736039bAngus Kong // Hit none. 2803166e36fb6e04d40a1bef0459ee6b96c9c736039bAngus Kong return true; 2804a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong } 280587f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong 28068ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde FilmstripItem data = mDataAdapter.getFilmstripItemAt( 28078ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mViewItems[hit].getAdapterIndex()); 28088ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde float transY = mViewItems[hit].getTranslationY() - dy / mScale; 28098ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (!data.getAttributes().canSwipeAway() && 2810c02b13af4c44fe23d4a563d3c2df1ca50e44affcAngus Kong transY > 0f) { 2811a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong transY = 0f; 2812a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong } 28138ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (!data.getAttributes().canSwipeAway() && 2814c02b13af4c44fe23d4a563d3c2df1ca50e44affcAngus Kong transY < 0f) { 2815a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong transY = 0f; 2816a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong } 28178ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mViewItems[hit].setTranslationY(transY); 281887f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong } 2819a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong } else if (inFullScreen()) { 28208ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (mViewItems[BUFFER_CENTER] == null || (deltaX < 0 && mCenterX <= 28218ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde currItem.getCenterX() && currItem.getAdapterIndex() == 0)) { 2822166e36fb6e04d40a1bef0459ee6b96c9c736039bAngus Kong return false; 2823166e36fb6e04d40a1bef0459ee6b96c9c736039bAngus Kong } 2824025136bb4639d84b2a5a7b95367fabcc92b86415Angus Kong // Multiplied by 1.2 to make it more easy to swipe. 2825025136bb4639d84b2a5a7b95367fabcc92b86415Angus Kong mController.scroll((int) (deltaX * 1.2)); 282649b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 28277d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong invalidate(); 2828a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong 282949b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong return true; 283049b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 283149b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 283249b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong @Override 28339652134e6e1b312e348ed3565343741239907f11Alan Newberger public boolean onMouseScroll(float hscroll, float vscroll) { 28349652134e6e1b312e348ed3565343741239907f11Alan Newberger final float scroll; 28359652134e6e1b312e348ed3565343741239907f11Alan Newberger 28369652134e6e1b312e348ed3565343741239907f11Alan Newberger hscroll *= MOUSE_SCROLL_FACTOR; 28379652134e6e1b312e348ed3565343741239907f11Alan Newberger vscroll *= MOUSE_SCROLL_FACTOR; 28389652134e6e1b312e348ed3565343741239907f11Alan Newberger 28399652134e6e1b312e348ed3565343741239907f11Alan Newberger if (vscroll != 0f) { 28409652134e6e1b312e348ed3565343741239907f11Alan Newberger scroll = vscroll; 28419652134e6e1b312e348ed3565343741239907f11Alan Newberger } else { 28429652134e6e1b312e348ed3565343741239907f11Alan Newberger scroll = hscroll; 28439652134e6e1b312e348ed3565343741239907f11Alan Newberger } 28449652134e6e1b312e348ed3565343741239907f11Alan Newberger 28459652134e6e1b312e348ed3565343741239907f11Alan Newberger if (inFullScreen()) { 28469652134e6e1b312e348ed3565343741239907f11Alan Newberger onFling(-scroll, 0f); 28479652134e6e1b312e348ed3565343741239907f11Alan Newberger } else if (inZoomView()) { 28489652134e6e1b312e348ed3565343741239907f11Alan Newberger onScroll(0f, 0f, hscroll, vscroll); 28499652134e6e1b312e348ed3565343741239907f11Alan Newberger } else { 28509652134e6e1b312e348ed3565343741239907f11Alan Newberger onScroll(0f, 0f, scroll, 0f); 28519652134e6e1b312e348ed3565343741239907f11Alan Newberger } 28529652134e6e1b312e348ed3565343741239907f11Alan Newberger 28539652134e6e1b312e348ed3565343741239907f11Alan Newberger return true; 28549652134e6e1b312e348ed3565343741239907f11Alan Newberger } 28559652134e6e1b312e348ed3565343741239907f11Alan Newberger 28569652134e6e1b312e348ed3565343741239907f11Alan Newberger @Override 285749b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong public boolean onFling(float velocityX, float velocityY) { 28588ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde final ViewItem currItem = mViewItems[BUFFER_CENTER]; 285917e669d695ef2a38d28d5ba2512937836293e9caAngus Kong if (currItem == null) { 286017e669d695ef2a38d28d5ba2512937836293e9caAngus Kong return false; 286117e669d695ef2a38d28d5ba2512937836293e9caAngus Kong } 2862b6a8810b7a5ac0df1e19efd26628c01bcb32b97bPaul Rohde 28634567160a43fa5787012bf0b618c216cf18ac0457Angus Kong if (inZoomView()) { 2864d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu // Fling within the zoomed image 2865d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu mController.flingInsideZoomView(velocityX, velocityY); 2866d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu return true; 2867d70f0fb68064e170fb2cf041a707ed04d68040f9Doris Liu } 2868025136bb4639d84b2a5a7b95367fabcc92b86415Angus Kong if (Math.abs(velocityX) < Math.abs(velocityY)) { 2869a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong // ignore vertical fling. 2870025136bb4639d84b2a5a7b95367fabcc92b86415Angus Kong return true; 2871025136bb4639d84b2a5a7b95367fabcc92b86415Angus Kong } 2872025136bb4639d84b2a5a7b95367fabcc92b86415Angus Kong 2873280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling // In full-screen, fling of a velocity above a threshold should go 2874280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling // to the next/prev photos 287517e669d695ef2a38d28d5ba2512937836293e9caAngus Kong if (mScale == FULL_SCREEN_SCALE) { 287617e669d695ef2a38d28d5ba2512937836293e9caAngus Kong int currItemCenterX = currItem.getCenterX(); 28777d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong 2878280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling if (velocityX > 0) { // left 287917e669d695ef2a38d28d5ba2512937836293e9caAngus Kong if (mCenterX > currItemCenterX) { 2880280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling // The visually previous item is actually the current 2881280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling // item. 288217e669d695ef2a38d28d5ba2512937836293e9caAngus Kong mController.scrollToPosition( 288317e669d695ef2a38d28d5ba2512937836293e9caAngus Kong currItemCenterX, GEOMETRY_ADJUST_TIME_MS, true); 288417e669d695ef2a38d28d5ba2512937836293e9caAngus Kong return true; 288517e669d695ef2a38d28d5ba2512937836293e9caAngus Kong } 28868ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde ViewItem prevItem = mViewItems[BUFFER_CENTER - 1]; 288717e669d695ef2a38d28d5ba2512937836293e9caAngus Kong if (prevItem == null) { 288817e669d695ef2a38d28d5ba2512937836293e9caAngus Kong return false; 288917e669d695ef2a38d28d5ba2512937836293e9caAngus Kong } 289017e669d695ef2a38d28d5ba2512937836293e9caAngus Kong mController.scrollToPosition( 289117e669d695ef2a38d28d5ba2512937836293e9caAngus Kong prevItem.getCenterX(), GEOMETRY_ADJUST_TIME_MS, true); 2892280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling } else { // right 28937d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong if (mController.stopScrolling(false)) { 28947d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong if (mCenterX < currItemCenterX) { 2895280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling // The visually next item is actually the current 2896280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling // item. 28977d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong mController.scrollToPosition( 28987d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong currItemCenterX, GEOMETRY_ADJUST_TIME_MS, true); 28997d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong return true; 29007d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong } 29018ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde final ViewItem nextItem = mViewItems[BUFFER_CENTER + 1]; 29027d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong if (nextItem == null) { 29037d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong return false; 29047d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong } 290517e669d695ef2a38d28d5ba2512937836293e9caAngus Kong mController.scrollToPosition( 29067d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong nextItem.getCenterX(), GEOMETRY_ADJUST_TIME_MS, true); 290717e669d695ef2a38d28d5ba2512937836293e9caAngus Kong } 290817e669d695ef2a38d28d5ba2512937836293e9caAngus Kong } 290917e669d695ef2a38d28d5ba2512937836293e9caAngus Kong } 291017e669d695ef2a38d28d5ba2512937836293e9caAngus Kong 2911b6a8810b7a5ac0df1e19efd26628c01bcb32b97bPaul Rohde 291217e669d695ef2a38d28d5ba2512937836293e9caAngus Kong if (mScale == FILM_STRIP_SCALE) { 291317e669d695ef2a38d28d5ba2512937836293e9caAngus Kong mController.fling(velocityX); 291449b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 291549b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong return true; 291649b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 291749b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 291849b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong @Override 291949b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong public boolean onScaleBegin(float focusX, float focusY) { 2920b0288ec84e06b83923180a04e1b546724fcfd258Doris Liu hideZoomView(); 2921e7263f7ea45cf31d3948984ba8514e03ef86627ePaul Rohde 2922e7263f7ea45cf31d3948984ba8514e03ef86627ePaul Rohde // This ensures that the item currently being manipulated 2923e7263f7ea45cf31d3948984ba8514e03ef86627ePaul Rohde // is locked at full opacity. 2924e7263f7ea45cf31d3948984ba8514e03ef86627ePaul Rohde mCurrentlyScalingItem = mViewItems[BUFFER_CENTER]; 2925e7263f7ea45cf31d3948984ba8514e03ef86627ePaul Rohde if (mCurrentlyScalingItem != null) { 2926e7263f7ea45cf31d3948984ba8514e03ef86627ePaul Rohde mCurrentlyScalingItem.lockAtFullOpacity(); 2927e7263f7ea45cf31d3948984ba8514e03ef86627ePaul Rohde } 2928e7263f7ea45cf31d3948984ba8514e03ef86627ePaul Rohde 292949b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong mScaleTrend = 1f; 293079dcb12bbbcb9b3650ace5290897e26451218fe1Doris Liu // If the image is smaller than screen size, we should allow to zoom 293179dcb12bbbcb9b3650ace5290897e26451218fe1Doris Liu // in to full screen size 29323179f6a49516833761be5155c4e1244ac0aa17feDoris Liu mMaxScale = Math.max(mController.getCurrentDataMaxScale(true), FULL_SCREEN_SCALE); 293349b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong return true; 293449b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 293549b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 293649b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong @Override 293749b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong public boolean onScale(float focusX, float focusY, float scale) { 293887f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong mScaleTrend = mScaleTrend * 0.3f + scale * 0.7f; 2939121022cb590955e37f1264f77190ce4711159976Doris Liu float newScale = mScale * scale; 2940121022cb590955e37f1264f77190ce4711159976Doris Liu if (mScale < FULL_SCREEN_SCALE && newScale < FULL_SCREEN_SCALE) { 2941faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong if (newScale <= FILM_STRIP_SCALE) { 2942faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong newScale = FILM_STRIP_SCALE; 2943faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong } 2944280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling // Scaled view is smaller than or equal to screen size both 2945280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling // before and after scaling 2946faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong if (mScale != newScale) { 2947faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong if (mScale == FILM_STRIP_SCALE) { 2948faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong onLeaveFilmstrip(); 2949faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong } 2950faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong if (newScale == FILM_STRIP_SCALE) { 2951faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong onEnterFilmstrip(); 2952faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong } 29538de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu } 2954faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong mScale = newScale; 29557d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong invalidate(); 2956121022cb590955e37f1264f77190ce4711159976Doris Liu } else if (mScale < FULL_SCREEN_SCALE && newScale >= FULL_SCREEN_SCALE) { 2957280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling // Going from smaller than screen size to bigger than or equal 2958280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling // to screen size 2959faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong if (mScale == FILM_STRIP_SCALE) { 2960faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong onLeaveFilmstrip(); 2961faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong } 29624ff5a1ab360577c6a7ec953f9197778c84c9d334Angus Kong mScale = FULL_SCREEN_SCALE; 2963faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong onEnterFullScreen(); 29648de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu mController.setSurroundingViewsVisible(false); 29654567160a43fa5787012bf0b618c216cf18ac0457Angus Kong invalidate(); 2966121022cb590955e37f1264f77190ce4711159976Doris Liu } else if (mScale >= FULL_SCREEN_SCALE && newScale < FULL_SCREEN_SCALE) { 2967280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling // Going from bigger than or equal to screen size to smaller 2968280fd3edae1dc35ac1015bcc9532477169fad3aaSascha Haeberling // than screen size 29694567160a43fa5787012bf0b618c216cf18ac0457Angus Kong if (inFullScreen()) { 29704567160a43fa5787012bf0b618c216cf18ac0457Angus Kong if (mFullScreenUIHidden) { 29714567160a43fa5787012bf0b618c216cf18ac0457Angus Kong onLeaveFullScreenUiHidden(); 29724567160a43fa5787012bf0b618c216cf18ac0457Angus Kong } else { 29734567160a43fa5787012bf0b618c216cf18ac0457Angus Kong onLeaveFullScreen(); 29744567160a43fa5787012bf0b618c216cf18ac0457Angus Kong } 29754567160a43fa5787012bf0b618c216cf18ac0457Angus Kong } else { 29764567160a43fa5787012bf0b618c216cf18ac0457Angus Kong onLeaveZoomView(); 2977faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong } 2978121022cb590955e37f1264f77190ce4711159976Doris Liu mScale = newScale; 297977d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde renderThumbnail(BUFFER_CENTER); 29804567160a43fa5787012bf0b618c216cf18ac0457Angus Kong onEnterFilmstrip(); 29817d2388d96522975307cf5c40f7ac911ad963c44dAngus Kong invalidate(); 29828de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu } else { 29838de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu // Scaled view bigger than or equal to screen size both before 29848de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu // and after scaling 29854567160a43fa5787012bf0b618c216cf18ac0457Angus Kong if (!inZoomView()) { 29868de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu mController.setSurroundingViewsVisible(false); 29878de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu } 29888ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde ViewItem curr = mViewItems[BUFFER_CENTER]; 29898de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu // Make sure the image is not overly scaled 2990121022cb590955e37f1264f77190ce4711159976Doris Liu newScale = Math.min(newScale, mMaxScale); 299187fc5e1568f737e03327770cb3dee03c4b939c59Doris Liu if (newScale == mScale) { 299287fc5e1568f737e03327770cb3dee03c4b939c59Doris Liu return true; 299387fc5e1568f737e03327770cb3dee03c4b939c59Doris Liu } 2994121022cb590955e37f1264f77190ce4711159976Doris Liu float postScale = newScale / mScale; 2995121022cb590955e37f1264f77190ce4711159976Doris Liu curr.postScale(focusX, focusY, postScale, mDrawArea.width(), mDrawArea.height()); 2996121022cb590955e37f1264f77190ce4711159976Doris Liu mScale = newScale; 2997faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong if (mScale == FULL_SCREEN_SCALE) { 2998faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong onEnterFullScreen(); 29994567160a43fa5787012bf0b618c216cf18ac0457Angus Kong } else { 30004567160a43fa5787012bf0b618c216cf18ac0457Angus Kong onEnterZoomView(); 3001faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong } 300277d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde renderFullRes(BUFFER_CENTER); 300387f9a62f473a3c57505e2877b0a46ab3cb5e62acAngus Kong } 300449b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong return true; 300549b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 300649b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong 300749b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong @Override 300849b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong public void onScaleEnd() { 3009e7263f7ea45cf31d3948984ba8514e03ef86627ePaul Rohde // Once the item is no longer under direct manipulation, unlock 3010e7263f7ea45cf31d3948984ba8514e03ef86627ePaul Rohde // the opacity so it can be set by other parts of the layout code. 3011e7263f7ea45cf31d3948984ba8514e03ef86627ePaul Rohde if (mCurrentlyScalingItem != null) { 3012e7263f7ea45cf31d3948984ba8514e03ef86627ePaul Rohde mCurrentlyScalingItem.unlockOpacity(); 3013e7263f7ea45cf31d3948984ba8514e03ef86627ePaul Rohde } 3014e7263f7ea45cf31d3948984ba8514e03ef86627ePaul Rohde 3015c8924b2ec3788ca6d0f0af5ca749e5fe7be125ceAndy Huibers zoomAtIndexChanged(); 3016121022cb590955e37f1264f77190ce4711159976Doris Liu if (mScale > FULL_SCREEN_SCALE + TOLERANCE) { 30178de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu return; 30188de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu } 30198de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu mController.setSurroundingViewsVisible(true); 3020121022cb590955e37f1264f77190ce4711159976Doris Liu if (mScale <= FILM_STRIP_SCALE + TOLERANCE) { 3021faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong mController.goToFilmstrip(); 3022121022cb590955e37f1264f77190ce4711159976Doris Liu } else if (mScaleTrend > 1f || mScale > FULL_SCREEN_SCALE - TOLERANCE) { 30234567160a43fa5787012bf0b618c216cf18ac0457Angus Kong if (inZoomView()) { 30248de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu mScale = FULL_SCREEN_SCALE; 3025e1d5ba4fc5470043e8645984e3018b712f5dfcffDoris Liu resetZoomView(); 30268de13111cc4e62da3462ea321d18c7951282e0d0Doris Liu } 3027734598c39e6a9d809982dae2907dc7d10e0b0e9fAngus Kong mController.goToFullScreen(); 302849b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } else { 3029faaee012acc80ad369cb03df9c196e48140f1e7bAngus Kong mController.goToFilmstrip(); 303049b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 3031a6a6a730074e9fedd56c41cd8fa8f1212cfac108Angus Kong mScaleTrend = 1f; 303249b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 303349b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong } 303449b9ba2ba89760f297ecc7d6d94d68fb4b836be1Angus Kong} 3035