11c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu/* 21c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu * Copyright (C) 2013 The Android Open Source Project 31c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu * 41c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu * Licensed under the Apache License, Version 2.0 (the "License"); 51c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu * you may not use this file except in compliance with the License. 61c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu * You may obtain a copy of the License at 71c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu * 81c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu * http://www.apache.org/licenses/LICENSE-2.0 91c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu * 101c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu * Unless required by applicable law or agreed to in writing, software 111c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu * distributed under the License is distributed on an "AS IS" BASIS, 121c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu * See the License for the specific language governing permissions and 141c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu * limitations under the License. 151c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu */ 161c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu 171c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liupackage com.android.camera.ui; 181c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu 191c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liuimport android.animation.Animator; 200496fcaa51f88f6c753975473b971941e4090cfaSpike Spragueimport android.animation.AnimatorListenerAdapter; 211c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liuimport android.animation.AnimatorSet; 221c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liuimport android.animation.ObjectAnimator; 231c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liuimport android.animation.TimeInterpolator; 2470576b611fddc929abbfb466fa44c396a3a793dbDoris Liuimport android.animation.ValueAnimator; 251c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liuimport android.content.Context; 26213a4a086b54904cee543adf60b16fc1a61efe38Doris Liuimport android.graphics.Bitmap; 27b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liuimport android.graphics.Canvas; 28b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liuimport android.graphics.Paint; 290496fcaa51f88f6c753975473b971941e4090cfaSpike Spragueimport android.graphics.Point; 30b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liuimport android.graphics.PorterDuff; 31b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liuimport android.graphics.PorterDuffXfermode; 32213a4a086b54904cee543adf60b16fc1a61efe38Doris Liuimport android.graphics.RectF; 33cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liuimport android.os.SystemClock; 341c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liuimport android.util.AttributeSet; 350496fcaa51f88f6c753975473b971941e4090cfaSpike Spragueimport android.util.SparseBooleanArray; 361c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liuimport android.view.GestureDetector; 371c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liuimport android.view.LayoutInflater; 381c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liuimport android.view.MotionEvent; 39213a4a086b54904cee543adf60b16fc1a61efe38Doris Liuimport android.view.View; 40213a4a086b54904cee543adf60b16fc1a61efe38Doris Liuimport android.widget.FrameLayout; 411c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liuimport android.widget.LinearLayout; 421c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu 4328a2950939614a0c1c83787960ce1a218fb69a5eDoris Liuimport com.android.camera.CaptureLayoutHelper; 44213a4a086b54904cee543adf60b16fc1a61efe38Doris Liuimport com.android.camera.app.CameraAppUI; 455596b4c902dcb685928b43678f428746ca5ffd08Angus Kongimport com.android.camera.debug.Log; 468be316c7a8caf962cf3fcf5e49d332fb2718319fPaul Rohdeimport com.android.camera.util.AndroidServices; 47bd1b8f910d6f2c94daac304f4bd1a098939474c3Doris Liuimport com.android.camera.util.CameraUtil; 481c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liuimport com.android.camera.util.Gusterpolator; 495f4f329d7d1780c6ea052bdaa64680e86bf74181Alan Newbergerimport com.android.camera.stats.UsageStatistics; 50b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liuimport com.android.camera.widget.AnimationEffects; 5126aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liuimport com.android.camera.widget.SettingsCling; 521c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liuimport com.android.camera2.R; 5310c5816e1ff3d30e4c4996643ba05d63d522b81aAndy Huibersimport com.google.common.logging.eventprotos; 541c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu 551c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liuimport java.util.ArrayList; 56cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liuimport java.util.LinkedList; 57a20074f0efeaa62a29b05838110d04a1b7271418Doris Liuimport java.util.List; 581c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu 5970576b611fddc929abbfb466fa44c396a3a793dbDoris Liu/** 6070576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * ModeListView class displays all camera modes and settings in the form 6170576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * of a list. A swipe to the right will bring up this list. Then tapping on 6270576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * any of the items in the list will take the user to that corresponding mode 6370576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * with an animation. To dismiss this list, simply swipe left or select a mode. 6470576b611fddc929abbfb466fa44c396a3a793dbDoris Liu */ 65213a4a086b54904cee543adf60b16fc1a61efe38Doris Liupublic class ModeListView extends FrameLayout 66b908d933736a4ec042aad065b7ebf2059bbcac97Doris Liu implements ModeSelectorItem.VisibleWidthChangedListener, 67b908d933736a4ec042aad065b7ebf2059bbcac97Doris Liu PreviewStatusListener.PreviewAreaChangedListener { 68601921e746832bdef40503c606a95b4469f1bedbSascha Haeberling 695596b4c902dcb685928b43678f428746ca5ffd08Angus Kong private static final Log.Tag TAG = new Log.Tag("ModeListView"); 7070576b611fddc929abbfb466fa44c396a3a793dbDoris Liu 7170576b611fddc929abbfb466fa44c396a3a793dbDoris Liu // Animation Durations 7270576b611fddc929abbfb466fa44c396a3a793dbDoris Liu private static final int DEFAULT_DURATION_MS = 200; 73b00d64307ae77541f8576593a29214d649fb94e9Doris Liu private static final int FLY_IN_DURATION_MS = 0; 741c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu private static final int HOLD_DURATION_MS = 0; 751c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu private static final int FLY_OUT_DURATION_MS = 850; 761c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu private static final int START_DELAY_MS = 100; 771c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu private static final int TOTAL_DURATION_MS = FLY_IN_DURATION_MS + HOLD_DURATION_MS 781c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu + FLY_OUT_DURATION_MS; 79b00d64307ae77541f8576593a29214d649fb94e9Doris Liu private static final int HIDE_SHIMMY_DELAY_MS = 1000; 8069cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu // Assumption for time since last scroll when no data point for last scroll. 8169cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu private static final int SCROLL_INTERVAL_MS = 50; 8269cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu // Last 20% percent of the drawer opening should be slow to ensure soft landing. 8369cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu private static final float SLOW_ZONE_PERCENTAGE = 0.2f; 841c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu 8570576b611fddc929abbfb466fa44c396a3a793dbDoris Liu private static final int NO_ITEM_SELECTED = -1; 861c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu 87cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu // Scrolling delay between non-focused item and focused item 88213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu private static final int DELAY_MS = 30; 896c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu // If the fling velocity exceeds this threshold, snap to full screen at a constant 906c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu // speed. Unit: pixel/ms. 916c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu private static final float VELOCITY_THRESHOLD = 2f; 92cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu 93213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu /** 94213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu * A factor to change the UI responsiveness on a scroll. 95213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu * e.g. A scroll factor of 0.5 means UI will move half as fast as the finger. 96213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu */ 97213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu private static final float SCROLL_FACTOR = 0.5f; 985ac2bfbb23f6277947f284531237ea85c81a06e4Seth Raphael // 60% opaque black background. 993020ba5dc23723bab7503324d82dd5ae3830008cSeth Raphael private static final int BACKGROUND_TRANSPARENTCY = (int) (0.6f * 255); 100213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu private static final int PREVIEW_DOWN_SAMPLE_FACTOR = 4; 101213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu // Threshold, below which snap back will happen. 102213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu private static final float SNAP_BACK_THRESHOLD_RATIO = 0.33f; 103213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu 10470576b611fddc929abbfb466fa44c396a3a793dbDoris Liu private final GestureDetector mGestureDetector; 10526e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger private final CurrentStateManager mCurrentStateManager = new CurrentStateManager(); 10628a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu private final int mSettingsButtonMargin; 10769cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu private long mLastScrollTime; 10870576b611fddc929abbfb466fa44c396a3a793dbDoris Liu private int mListBackgroundColor; 10970576b611fddc929abbfb466fa44c396a3a793dbDoris Liu private LinearLayout mListView; 11028a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu private View mSettingsButton; 11170576b611fddc929abbfb466fa44c396a3a793dbDoris Liu private int mTotalModes; 11270576b611fddc929abbfb466fa44c396a3a793dbDoris Liu private ModeSelectorItem[] mModeSelectorItems; 11370576b611fddc929abbfb466fa44c396a3a793dbDoris Liu private AnimatorSet mAnimatorSet; 1141c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu private int mFocusItem = NO_ITEM_SELECTED; 1152c559c4bd3c65e0cb0bca06f30e3bc979038e6f7Doris Liu private ModeListOpenListener mModeListOpenListener; 1168c1a922df154182b53f00c38198db7da0b4feb20Sascha Haeberling private ModeListVisibilityChangedListener mVisibilityChangedListener; 117213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu private CameraAppUI.CameraModuleScreenShotProvider mScreenShotProvider = null; 118213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu private int[] mInputPixels; 119213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu private int[] mOutputPixels; 120a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu private float mModeListOpenFactor = 1f; 12170576b611fddc929abbfb466fa44c396a3a793dbDoris Liu 12269cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu private View mChildViewTouched = null; 12369cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu private MotionEvent mLastChildTouchEvent = null; 12469cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu private int mVisibleWidth = 0; 12569cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu 12670576b611fddc929abbfb466fa44c396a3a793dbDoris Liu // Width and height of this view. They get updated in onLayout() 12770576b611fddc929abbfb466fa44c396a3a793dbDoris Liu // Unit for width and height are pixels. 1281c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu private int mWidth; 1291c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu private int mHeight; 1301c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu private float mScrollTrendX = 0f; 1311c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu private float mScrollTrendY = 0f; 1322c559c4bd3c65e0cb0bca06f30e3bc979038e6f7Doris Liu private ModeSwitchListener mModeSwitchListener = null; 133bd1b8f910d6f2c94daac304f4bd1a098939474c3Doris Liu private ArrayList<Integer> mSupportedModes; 134cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu private final LinkedList<TimeBasedPosition> mPositionHistory 135cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu = new LinkedList<TimeBasedPosition>(); 136cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu private long mCurrentTime; 1376c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu private float mVelocityX; // Unit: pixel/ms. 138a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu private long mLastDownTime = 0; 13928a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu private CaptureLayoutHelper mCaptureLayoutHelper = null; 14026aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu private SettingsCling mSettingsCling = null; 141a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 14226e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger private class CurrentStateManager { 14326e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger private ModeListState mCurrentState; 14426e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger 14526e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger ModeListState getCurrentState() { 14626e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger return mCurrentState; 14726e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger } 14826e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger 14926e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger void setCurrentState(ModeListState state) { 15026e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger mCurrentState = state; 15126e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger state.onCurrentState(); 15226e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger } 15326e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger } 15426e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger 155a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu /** 156a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * ModeListState defines a set of functions through which the view could manage 157a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * or change the states. Sub-classes could selectively override these functions 158a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * accordingly to respect the specific requirements for each state. By overriding 159a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * these methods, state transition can also be achieved. 160a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu */ 161a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu private abstract class ModeListState implements GestureDetector.OnGestureListener { 162a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu protected AnimationEffects mCurrentAnimationEffects = null; 163a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 164a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu /** 16526e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger * Called by the state manager when this state instance becomes the current 16626e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger * mode list state. 16726e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger */ 16826e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger public void onCurrentState() { 16926e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger // Do nothing. 17026aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu showSettingsClingIfEnabled(false); 17126e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger } 17226e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger 17326e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger /** 174a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * If supported, this should show the mode switcher and starts the accordion 175a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * animation with a delay. If the view does not currently have focus, (e.g. 176a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * There are popups on top of it.) start the delayed accordion animation 177a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * when it gains focus. Otherwise, start the animation with a delay right 178a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * away. 179a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu */ 180a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public void showSwitcherHint() { 181a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu // Do nothing. 182a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 183a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 184a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu /** 185a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * Gets the currently running animation effects for the current state. 186a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu */ 187a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public AnimationEffects getCurrentAnimationEffects() { 188a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return mCurrentAnimationEffects; 189a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 190a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 191a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu /** 192a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * Returns true if the touch event should be handled, false otherwise. 193a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * 194a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * @param ev motion event to be handled 195a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * @return true if the event should be handled, false otherwise. 196a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu */ 197a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public boolean shouldHandleTouchEvent(MotionEvent ev) { 198a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return true; 199a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 200a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 201a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu /** 202a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * Handles touch event. This will be called if 203a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * {@link ModeListState#shouldHandleTouchEvent(android.view.MotionEvent)} 204a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * returns {@code true} 205a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * 206a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * @param ev touch event to be handled 207a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * @return always true 208a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu */ 209a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public boolean onTouchEvent(MotionEvent ev) { 210a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return true; 211a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 212a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 213a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu /** 214a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * Gets called when the window focus has changed. 215a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * 216a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * @param hasFocus whether current window has focus 217a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu */ 218a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public void onWindowFocusChanged(boolean hasFocus) { 219a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu // Default to do nothing. 220a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 221a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 222a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu /** 223a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * Gets called when back key is pressed. 224a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * 225a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * @return true if handled, false otherwise. 226a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu */ 227a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public boolean onBackPressed() { 228a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return false; 229a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 230a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 231a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu /** 23215691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren * Gets called when menu key is pressed. 23315691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren * 23415691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren * @return true if handled, false otherwise. 23515691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren */ 23615691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren public boolean onMenuPressed() { 23715691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren return false; 23815691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren } 23915691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren 24015691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren /** 241a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * Gets called when there is a {@link View#setVisibility(int)} call to 242a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * change the visibility of the mode drawer. Visibility change does not 243a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * always make sense, for example there can be an outside call to make 244a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * the mode drawer visible when it is in the fully hidden state. The logic 245a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * is that the mode drawer can only be made visible when user swipe it in. 246a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * 247a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * @param visibility the proposed visibility change 248a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * @return true if the visibility change is valid and therefore should be 249a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * handled, false otherwise. 250a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu */ 251a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public boolean shouldHandleVisibilityChange(int visibility) { 252a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return true; 253a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 254a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 255a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu /** 256a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * If supported, this should start blurring the camera preview and 257a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * start the mode switch. 258a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * 259a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * @param selectedItem mode item that has been selected 260a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu */ 261a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public void onItemSelected(ModeSelectorItem selectedItem) { 262a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu // Do nothing. 263a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 264a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 265a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu /** 266a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * This gets called when mode switch has finished and UI needs to 267a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * pinhole into the new mode through animation. 268a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu */ 269a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public void startModeSelectionAnimation() { 270a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu // Do nothing. 271a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 272a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 273a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu /** 274a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * Hide the mode drawer and switch to fully hidden state. 275a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu */ 276a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public void hide() { 277a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu // Do nothing. 278a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 279a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 2804c96d840aeff669011a9e8697cbac77fe8f4eda2Spike Sprague /** 2814c96d840aeff669011a9e8697cbac77fe8f4eda2Spike Sprague * Hide the mode drawer (with animation, if supported) 2824c96d840aeff669011a9e8697cbac77fe8f4eda2Spike Sprague * and switch to fully hidden state. 2834c96d840aeff669011a9e8697cbac77fe8f4eda2Spike Sprague * Default is to simply call {@link #hide()}. 2844c96d840aeff669011a9e8697cbac77fe8f4eda2Spike Sprague */ 2854c96d840aeff669011a9e8697cbac77fe8f4eda2Spike Sprague public void hideAnimated() { 2864c96d840aeff669011a9e8697cbac77fe8f4eda2Spike Sprague hide(); 2874c96d840aeff669011a9e8697cbac77fe8f4eda2Spike Sprague } 2884c96d840aeff669011a9e8697cbac77fe8f4eda2Spike Sprague 289a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu /***************GestureListener implementation*****************/ 290a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 291a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public boolean onDown(MotionEvent e) { 292a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return false; 293a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 294a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 295a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 296a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public void onShowPress(MotionEvent e) { 297a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu // Do nothing. 298a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 299a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 300a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 301a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public boolean onSingleTapUp(MotionEvent e) { 302a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return false; 303a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 304a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 305a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 306a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { 307a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return false; 308a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 309a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 310a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 311a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public void onLongPress(MotionEvent e) { 312a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu // Do nothing. 313a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 314a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 315a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 316a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { 317a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return false; 318a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 319a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 320a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 321a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu /** 322a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * Fully hidden state. Transitioning to ScrollingState and ShimmyState are supported 323a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * in this state. 324a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu */ 325a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu private class FullyHiddenState extends ModeListState { 32615691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren private Animator mAnimator = null; 327a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu private boolean mShouldBeVisible = false; 32815691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren 329a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public FullyHiddenState() { 330a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu reset(); 331a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 332a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 333a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 334a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { 335a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu mShouldBeVisible = true; 336a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu // Change visibility, and switch to scrolling state. 337a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu resetModeSelectors(); 33826e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger mCurrentStateManager.setCurrentState(new ScrollingState()); 339a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return true; 340a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 341a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 342a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 343a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public void showSwitcherHint() { 344a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu mShouldBeVisible = true; 34526e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger mCurrentStateManager.setCurrentState(new ShimmyState()); 346a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 3476c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu 3486c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu @Override 349a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public boolean shouldHandleTouchEvent(MotionEvent ev) { 350a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return true; 351a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 352a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 353a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 354a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public boolean onTouchEvent(MotionEvent ev) { 355a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) { 356a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu mFocusItem = getFocusItem(ev.getX(), ev.getY()); 357a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu setSwipeMode(true); 358a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 359a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return true; 360a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 361a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 362a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 36315691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren public boolean onMenuPressed() { 36415691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren if (mAnimator != null) { 36515691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren return false; 36615691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren } 36715691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren snapOpenAndShow(); 36815691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren return true; 36915691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren } 37015691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren 37115691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren @Override 372a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public boolean shouldHandleVisibilityChange(int visibility) { 37315691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren if (mAnimator != null) { 37415691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren return false; 37515691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren } 376a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu if (visibility == VISIBLE && !mShouldBeVisible) { 377a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return false; 378a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 379a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return true; 380a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 38115691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren /** 38215691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren * Snaps open the mode list and go to the fully shown state. 38315691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren */ 38415691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren private void snapOpenAndShow() { 38515691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren mShouldBeVisible = true; 38615691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren setVisibility(VISIBLE); 387a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 38815691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren mAnimator = snapToFullScreen(); 38915691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren if (mAnimator != null) { 39015691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren mAnimator.addListener(new Animator.AnimatorListener() { 39115691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren @Override 39215691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren public void onAnimationStart(Animator animation) { 39315691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren 39415691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren } 39515691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren 39615691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren @Override 39715691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren public void onAnimationEnd(Animator animation) { 39815691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren mAnimator = null; 39926e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger mCurrentStateManager.setCurrentState(new FullyShownState()); 40015691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren } 40115691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren 40215691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren @Override 40315691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren public void onAnimationCancel(Animator animation) { 40415691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren 40515691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren } 40615691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren 40715691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren @Override 40815691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren public void onAnimationRepeat(Animator animation) { 40915691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren 41015691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren } 41115691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren }); 41215691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren } else { 41326e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger mCurrentStateManager.setCurrentState(new FullyShownState()); 41410c5816e1ff3d30e4c4996643ba05d63d522b81aAndy Huibers UsageStatistics.instance().controlUsed( 41510c5816e1ff3d30e4c4996643ba05d63d522b81aAndy Huibers eventprotos.ControlEvent.ControlType.MENU_FULL_FROM_HIDDEN); 41615691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren } 41715691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren } 41826e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger 41926e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger @Override 42026e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger public void onCurrentState() { 42126aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu super.onCurrentState(); 42226aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu announceForAccessibility( 42326aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu getContext().getResources().getString(R.string.accessibility_mode_list_hidden)); 42426e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger } 425a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 426a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 427a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu /** 428a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * Fully shown state. This state represents when the mode list is entirely shown 429a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * on screen without any on-going animation. Transitions from this state could be 430a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * to ScrollingState, SelectedState, or FullyHiddenState. 431a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu */ 432a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu private class FullyShownState extends ModeListState { 433a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu private Animator mAnimator = null; 434a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 435a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 436a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { 437a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu // Go to scrolling state. 438a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu if (distanceX > 0) { 439a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu // Swipe out 440a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu cancelForwardingTouchEvent(); 44126e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger mCurrentStateManager.setCurrentState(new ScrollingState()); 442a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 443a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return true; 444a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 445a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 446a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 447a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public boolean shouldHandleTouchEvent(MotionEvent ev) { 448a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu if (mAnimator != null && mAnimator.isRunning()) { 449a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return false; 450a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 451a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return true; 452a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 453a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 454a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 455a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public boolean onTouchEvent(MotionEvent ev) { 456a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) { 457a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu mFocusItem = NO_ITEM_SELECTED; 458a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu setSwipeMode(false); 459a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu // If the down event happens inside the mode list, find out which 460a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu // mode item is being touched and forward all the subsequent touch 461a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu // events to that mode item for its pressed state and click handling. 462a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu if (isTouchInsideList(ev)) { 463a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu mChildViewTouched = mModeSelectorItems[getFocusItem(ev.getX(), ev.getY())]; 464a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 465a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 466a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu forwardTouchEventToChild(ev); 467a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return true; 468a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 469a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 470a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 471a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 472a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public boolean onSingleTapUp(MotionEvent ev) { 473a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu // If the tap is not inside the mode drawer area, snap back. 474a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu if(!isTouchInsideList(ev)) { 475a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu snapBackAndHide(); 476a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return false; 477a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 478a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return true; 479a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 480a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 481a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 482a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public boolean onBackPressed() { 483a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu snapBackAndHide(); 484a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return true; 485a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 486a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 487a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 48815691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren public boolean onMenuPressed() { 48915691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren snapBackAndHide(); 49015691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren return true; 49115691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren } 49215691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren 49315691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren @Override 494a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public void onItemSelected(ModeSelectorItem selectedItem) { 49526e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger mCurrentStateManager.setCurrentState(new SelectedState(selectedItem)); 496a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 497a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 498a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu /** 499a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * Snaps back the mode list and go to the fully hidden state. 500a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu */ 501a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu private void snapBackAndHide() { 502a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu mAnimator = snapBack(true); 503a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu if (mAnimator != null) { 504a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu mAnimator.addListener(new Animator.AnimatorListener() { 505a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 506a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public void onAnimationStart(Animator animation) { 507a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 508a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 509a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 510a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 511a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public void onAnimationEnd(Animator animation) { 512a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu mAnimator = null; 51326e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger mCurrentStateManager.setCurrentState(new FullyHiddenState()); 514a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 515a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 516a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 517a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public void onAnimationCancel(Animator animation) { 518a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 519a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 520a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 521a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 522a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public void onAnimationRepeat(Animator animation) { 523a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 524a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 525a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu }); 526a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } else { 52726e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger mCurrentStateManager.setCurrentState(new FullyHiddenState()); 528a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 529a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 530a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 531a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 532a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public void hide() { 533a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu if (mAnimator != null) { 534a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu mAnimator.cancel(); 535a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } else { 53626e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger mCurrentStateManager.setCurrentState(new FullyHiddenState()); 537a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 538a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 53926e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger 54026e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger @Override 54126e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger public void onCurrentState() { 54226aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu announceForAccessibility( 54326aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu getContext().getResources().getString(R.string.accessibility_mode_list_shown)); 54426aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu showSettingsClingIfEnabled(true); 54526e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger } 546a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 547a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 548a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu /** 549a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * Shimmy state handles the specifics for shimmy animation, including 550a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * setting up to show mode drawer (without text) and hide it with shimmy animation. 551a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * 552a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * This state can be interrupted when scrolling or mode selection happened, 553a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * in which case the state will transition into ScrollingState, or SelectedState. 554a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * Otherwise, after shimmy finishes successfully, a transition to fully hidden 555a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * state will happen. 556a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu */ 557a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu private class ShimmyState extends ModeListState { 558a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 559a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu private boolean mStartHidingShimmyWhenWindowGainsFocus = false; 560a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu private Animator mAnimator = null; 561a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu private final Runnable mHideShimmy = new Runnable() { 562a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 563a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public void run() { 564a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu startHidingShimmy(); 565a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 566a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu }; 567a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 568a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public ShimmyState() { 5696c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu setVisibility(VISIBLE); 570a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu mSettingsButton.setVisibility(INVISIBLE); 571a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu mModeListOpenFactor = 0f; 572a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu onModeListOpenRatioUpdate(0); 573a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu int maxVisibleWidth = mModeSelectorItems[0].getMaxVisibleWidth(); 574a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu for (int i = 0; i < mModeSelectorItems.length; i++) { 575a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu mModeSelectorItems[i].setVisibleWidth(maxVisibleWidth); 576a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 577a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu if (hasWindowFocus()) { 578a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu hideShimmyWithDelay(); 579a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } else { 580a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu mStartHidingShimmyWhenWindowGainsFocus = true; 581a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 582a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 583a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 584a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 585a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { 586a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu // Scroll happens during accordion animation. 587a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu cancelAnimation(); 5881c5a87b4301c4211d3e3b85be5c863c50d4eab7bDoris Liu cancelForwardingTouchEvent(); 589a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu // Go to scrolling state 59026e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger mCurrentStateManager.setCurrentState(new ScrollingState()); 59110c5816e1ff3d30e4c4996643ba05d63d522b81aAndy Huibers UsageStatistics.instance().controlUsed( 59210c5816e1ff3d30e4c4996643ba05d63d522b81aAndy Huibers eventprotos.ControlEvent.ControlType.MENU_SCROLL_FROM_SHIMMY); 593a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return true; 594a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 595a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 596a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 597a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public boolean shouldHandleTouchEvent(MotionEvent ev) { 598a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu if (MotionEvent.ACTION_DOWN == ev.getActionMasked()) { 599a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu if (isTouchInsideList(ev) && 600a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu ev.getX() <= mModeSelectorItems[0].getMaxVisibleWidth()) { 601a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu mChildViewTouched = mModeSelectorItems[getFocusItem(ev.getX(), ev.getY())]; 602a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return true; 603a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 604a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu // If shimmy is on-going, reject the first down event, so that it can be handled 605a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu // by the view underneath. If a swipe is detected, the same series of touch will 606a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu // re-enter this function, in which case we will consume the touch events. 607a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu if (mLastDownTime != ev.getDownTime()) { 608a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu mLastDownTime = ev.getDownTime(); 609a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return false; 610a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 611a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 612a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return true; 6136c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu } 6146c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu 6156c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu @Override 616a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public boolean onTouchEvent(MotionEvent ev) { 617a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu if (MotionEvent.ACTION_DOWN == ev.getActionMasked()) { 618a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) { 619a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu mFocusItem = getFocusItem(ev.getX(), ev.getY()); 620a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu setSwipeMode(true); 621a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 622a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 623a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu forwardTouchEventToChild(ev); 624a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return true; 625a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 626a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 627a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 628a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public void onItemSelected(ModeSelectorItem selectedItem) { 629a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu cancelAnimation(); 63026e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger mCurrentStateManager.setCurrentState(new SelectedState(selectedItem)); 631a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 632a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 633a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu private void hideShimmyWithDelay() { 634a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu postDelayed(mHideShimmy, HIDE_SHIMMY_DELAY_MS); 635a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 636a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 637a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 638a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public void onWindowFocusChanged(boolean hasFocus) { 639a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu if (mStartHidingShimmyWhenWindowGainsFocus && hasFocus) { 640a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu mStartHidingShimmyWhenWindowGainsFocus = false; 641a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu hideShimmyWithDelay(); 642a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 643a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 644a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 645a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu /** 646a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * This starts the accordion animation, unless it's already running, in which 647a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * case the start animation call will be ignored. 648a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu */ 649a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu private void startHidingShimmy() { 650a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu if (mAnimator != null) { 65169cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu return; 65269cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu } 653a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu int maxVisibleWidth = mModeSelectorItems[0].getMaxVisibleWidth(); 654a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu mAnimator = animateListToWidth(START_DELAY_MS * (-1), TOTAL_DURATION_MS, 655a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu Gusterpolator.INSTANCE, maxVisibleWidth, 0); 656a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu mAnimator.addListener(new Animator.AnimatorListener() { 657a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu private boolean mSuccess = true; 658a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 659a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public void onAnimationStart(Animator animation) { 660a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu // Do nothing. 661a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 662a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 663a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 664a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public void onAnimationEnd(Animator animation) { 665a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu mAnimator = null; 666a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu ShimmyState.this.onAnimationEnd(mSuccess); 667a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 668a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 669a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 670a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public void onAnimationCancel(Animator animation) { 671a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu mSuccess = false; 672a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 673a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 674a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 675a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public void onAnimationRepeat(Animator animation) { 676a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu // Do nothing. 677a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 678a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu }); 679a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 680a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 681a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu /** 682a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * Cancels the pending/on-going animation. 683a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu */ 684a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu private void cancelAnimation() { 685a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu removeCallbacks(mHideShimmy); 686a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu if (mAnimator != null && mAnimator.isRunning()) { 687a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu mAnimator.cancel(); 688a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } else { 689a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu mAnimator = null; 690a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu onAnimationEnd(false); 691a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 692a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 693a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 694c064750b7a02c4e495a30d2ec8d25319a9e49e9cSpike Sprague @Override 695c064750b7a02c4e495a30d2ec8d25319a9e49e9cSpike Sprague public void onCurrentState() { 696c064750b7a02c4e495a30d2ec8d25319a9e49e9cSpike Sprague super.onCurrentState(); 697c064750b7a02c4e495a30d2ec8d25319a9e49e9cSpike Sprague ModeListView.this.disableA11yOnModeSelectorItems(); 698c064750b7a02c4e495a30d2ec8d25319a9e49e9cSpike Sprague } 699a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu /** 700a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * Gets called when the animation finishes or gets canceled. 701a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * 702a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * @param success indicates whether the animation finishes successfully 703a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu */ 704a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu private void onAnimationEnd(boolean success) { 7057543914f2de33b1be25626afb31fa979b06dd582Paul Rohde if (mSettingsButton.getLayerType() == View.LAYER_TYPE_HARDWARE) { 7061908beee07fe9792338dbf8e0c36a5f1e3e9401fPaul Rohde Log.v(TAG, "Disabling hardware layer for the Settings Button. (onAnimationEnd)"); 7071908beee07fe9792338dbf8e0c36a5f1e3e9401fPaul Rohde mSettingsButton.setLayerType(View.LAYER_TYPE_NONE, null); 7081908beee07fe9792338dbf8e0c36a5f1e3e9401fPaul Rohde } 7091908beee07fe9792338dbf8e0c36a5f1e3e9401fPaul Rohde 710a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu mSettingsButton.setVisibility(VISIBLE); 711a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu // If successfully finish hiding shimmy, then we should go back to 712a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu // fully hidden state. 713a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu if (success) { 714c064750b7a02c4e495a30d2ec8d25319a9e49e9cSpike Sprague ModeListView.this.enableA11yOnModeSelectorItems(); 715a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu mModeListOpenFactor = 1; 71626e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger mCurrentStateManager.setCurrentState(new FullyHiddenState()); 717a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return; 7186c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu } 719a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 720a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu // If the animation was canceled before it's finished, animate the mode 721a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu // list open factor from 0 to 1 to ensure a smooth visual transition. 722a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu final ValueAnimator openFactorAnimator = ValueAnimator.ofFloat(mModeListOpenFactor, 1f); 723a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu openFactorAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 724a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 725a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public void onAnimationUpdate(ValueAnimator animation) { 726a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu mModeListOpenFactor = (Float) openFactorAnimator.getAnimatedValue(); 727a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu onVisibleWidthChanged(mVisibleWidth); 728a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 729a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu }); 730a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu openFactorAnimator.addListener(new Animator.AnimatorListener() { 731a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 732a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public void onAnimationStart(Animator animation) { 733a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu // Do nothing. 734a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 735a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 736a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 737a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public void onAnimationEnd(Animator animation) { 738a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu mModeListOpenFactor = 1f; 739a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 740a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 741a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 742a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public void onAnimationCancel(Animator animation) { 743a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu // Do nothing. 744a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 745a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 746a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 747a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public void onAnimationRepeat(Animator animation) { 748a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu // Do nothing. 749a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 750a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu }); 751a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu openFactorAnimator.start(); 7526c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu } 7536c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu 7546c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu @Override 755a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public void hide() { 756a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu cancelAnimation(); 75726e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger mCurrentStateManager.setCurrentState(new FullyHiddenState()); 75826e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger } 75926e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger 7604c96d840aeff669011a9e8697cbac77fe8f4eda2Spike Sprague @Override 7614c96d840aeff669011a9e8697cbac77fe8f4eda2Spike Sprague public void hideAnimated() { 7624c96d840aeff669011a9e8697cbac77fe8f4eda2Spike Sprague cancelAnimation(); 7634c96d840aeff669011a9e8697cbac77fe8f4eda2Spike Sprague animateListToWidth(0).addListener(new AnimatorListenerAdapter() { 7644c96d840aeff669011a9e8697cbac77fe8f4eda2Spike Sprague @Override 7654c96d840aeff669011a9e8697cbac77fe8f4eda2Spike Sprague public void onAnimationEnd(Animator animation) { 7664c96d840aeff669011a9e8697cbac77fe8f4eda2Spike Sprague mCurrentStateManager.setCurrentState(new FullyHiddenState()); 7674c96d840aeff669011a9e8697cbac77fe8f4eda2Spike Sprague } 7684c96d840aeff669011a9e8697cbac77fe8f4eda2Spike Sprague }); 7694c96d840aeff669011a9e8697cbac77fe8f4eda2Spike Sprague } 770a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 771a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 772a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu /** 773a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * When the mode list is being scrolled, it will be in ScrollingState. From 774a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * this state, the mode list could transition to fully hidden, fully open 775a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * depending on which direction the scrolling goes. 776a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu */ 777a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu private class ScrollingState extends ModeListState { 778a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu private Animator mAnimator = null; 779a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 780a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public ScrollingState() { 781a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu setVisibility(VISIBLE); 7826c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu } 7836c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu 7846c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu @Override 785a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { 786a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu // Scroll based on the scrolling distance on the currently focused 787a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu // item. 788a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu scroll(mFocusItem, distanceX * SCROLL_FACTOR, 789a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu distanceY * SCROLL_FACTOR); 790a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return true; 791a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 7926c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu 793a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 794a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public boolean shouldHandleTouchEvent(MotionEvent ev) { 795a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu // If the snap back/to full screen animation is on going, ignore any 796a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu // touch. 797a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu if (mAnimator != null) { 798a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return false; 799a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 800a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return true; 8016c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu } 80269cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu 803a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 804a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public boolean onTouchEvent(MotionEvent ev) { 805a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu if (ev.getActionMasked() == MotionEvent.ACTION_UP || 806a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu ev.getActionMasked() == MotionEvent.ACTION_CANCEL) { 807a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu final boolean shouldSnapBack = shouldSnapBack(); 808a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu if (shouldSnapBack) { 809a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu mAnimator = snapBack(); 810a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } else { 811a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu mAnimator = snapToFullScreen(); 812a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 813a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu mAnimator.addListener(new Animator.AnimatorListener() { 814a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 815a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public void onAnimationStart(Animator animation) { 816a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 817a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 818a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 819a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 820a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public void onAnimationEnd(Animator animation) { 821a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu mAnimator = null; 822a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu mFocusItem = NO_ITEM_SELECTED; 823a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu if (shouldSnapBack) { 82426e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger mCurrentStateManager.setCurrentState(new FullyHiddenState()); 825a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } else { 82626e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger mCurrentStateManager.setCurrentState(new FullyShownState()); 82710c5816e1ff3d30e4c4996643ba05d63d522b81aAndy Huibers UsageStatistics.instance().controlUsed( 82810c5816e1ff3d30e4c4996643ba05d63d522b81aAndy Huibers eventprotos.ControlEvent.ControlType.MENU_FULL_FROM_SCROLL); 829a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 830a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 831a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 832a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 833a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public void onAnimationCancel(Animator animation) { 834a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 835a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 836a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 837a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 838a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public void onAnimationRepeat(Animator animation) { 839a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 840a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 841a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu }); 842a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 843a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return true; 844a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 845a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 846a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 847a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu /** 848a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * Mode list gets in this state when a mode item has been selected/clicked. 849a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * There will be an animation with the blurred preview fading in, a potential 850a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * pause to wait for the new mode to be ready, and then the new mode will 851a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * be revealed through a pinhole animation. After all the animations finish, 852a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu * mode list will transition into fully hidden state. 853a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu */ 8543c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague private class SelectedState extends ModeListState { 855a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public SelectedState(ModeSelectorItem selectedItem) { 856a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu final int modeId = selectedItem.getModeId(); 857a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu // Un-highlight all the modes. 858a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu for (int i = 0; i < mModeSelectorItems.length; i++) { 859a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu mModeSelectorItems[i].setSelected(false); 860a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 8610496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague 862a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu PeepholeAnimationEffect effect = new PeepholeAnimationEffect(); 863a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu effect.setSize(mWidth, mHeight); 864a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 865a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu // Calculate the position of the icon in the selected item, and 866a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu // start animation from that position. 867a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu int[] location = new int[2]; 868a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu // Gets icon's center position in relative to the window. 869a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu selectedItem.getIconCenterLocationInWindow(location); 870a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu int iconX = location[0]; 871a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu int iconY = location[1]; 872a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu // Gets current view's top left position relative to the window. 873a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu getLocationInWindow(location); 874a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu // Calculate icon location relative to this view 875a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu iconX -= location[0]; 876a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu iconY -= location[1]; 877a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 878a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu effect.setAnimationStartingPosition(iconX, iconY); 8790496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague effect.setModeSpecificColor(selectedItem.getHighlightColor()); 880a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu if (mScreenShotProvider != null) { 881a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu effect.setBackground(mScreenShotProvider 88228a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu .getPreviewFrame(PREVIEW_DOWN_SAMPLE_FACTOR), 88328a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu mCaptureLayoutHelper.getPreviewRect()); 884a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu effect.setBackgroundOverlay(mScreenShotProvider.getPreviewOverlayAndControls()); 885a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 886a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu mCurrentAnimationEffects = effect; 8870496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague effect.startFadeoutAnimation(null, selectedItem, iconX, iconY, modeId); 888a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu invalidate(); 889a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 890a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 891a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 892a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public boolean shouldHandleTouchEvent(MotionEvent ev) { 893a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return false; 894a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 895a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 896a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 897a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public void startModeSelectionAnimation() { 8980496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague mCurrentAnimationEffects.startAnimation(new AnimatorListenerAdapter() { 899a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 900a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public void onAnimationEnd(Animator animation) { 901a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu mCurrentAnimationEffects = null; 90226e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger mCurrentStateManager.setCurrentState(new FullyHiddenState()); 903a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 904a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu }); 90569cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu } 906fa50f7d71a77dc730746c33fd17a570d42453759Doris Liu 907fa50f7d71a77dc730746c33fd17a570d42453759Doris Liu @Override 908fa50f7d71a77dc730746c33fd17a570d42453759Doris Liu public void hide() { 909fa50f7d71a77dc730746c33fd17a570d42453759Doris Liu if (!mCurrentAnimationEffects.cancelAnimation()) { 910fa50f7d71a77dc730746c33fd17a570d42453759Doris Liu mCurrentAnimationEffects = null; 911fa50f7d71a77dc730746c33fd17a570d42453759Doris Liu mCurrentStateManager.setCurrentState(new FullyHiddenState()); 912fa50f7d71a77dc730746c33fd17a570d42453759Doris Liu } 913fa50f7d71a77dc730746c33fd17a570d42453759Doris Liu } 91469cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu } 9151c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu 9161c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu public interface ModeSwitchListener { 917427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu public void onModeButtonPressed(int modeIndex); 9181c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu public void onModeSelected(int modeIndex); 919213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu public int getCurrentModeIndex(); 9209d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu public void onSettingsSelected(); 9211c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu } 9221c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu 9232c559c4bd3c65e0cb0bca06f30e3bc979038e6f7Doris Liu public interface ModeListOpenListener { 9249d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu /** 9259d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu * Mode list will open to full screen after current animation. 9269d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu */ 9272c559c4bd3c65e0cb0bca06f30e3bc979038e6f7Doris Liu public void onOpenFullScreen(); 9289d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu 9299d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu /** 9309d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu * Updates the listener with the current progress of mode drawer opening. 9319d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu * 9329d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu * @param progress progress of the mode drawer opening, ranging [0f, 1f] 9339d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu * 0 means mode drawer is fully closed, 1 indicates a fully 9349d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu * open mode drawer. 9359d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu */ 9369d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu public void onModeListOpenProgress(float progress); 9379d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu 9389d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu /** 9399d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu * Gets called when mode list is completely closed. 9409d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu */ 9419d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu public void onModeListClosed(); 9422c559c4bd3c65e0cb0bca06f30e3bc979038e6f7Doris Liu } 9432c559c4bd3c65e0cb0bca06f30e3bc979038e6f7Doris Liu 9448c1a922df154182b53f00c38198db7da0b4feb20Sascha Haeberling public static abstract class ModeListVisibilityChangedListener { 945b49ab283fe6fce242901a1a09fc2b148b27fe123Sascha Haeberling private Boolean mCurrentVisibility = null; 9468c1a922df154182b53f00c38198db7da0b4feb20Sascha Haeberling 9478c1a922df154182b53f00c38198db7da0b4feb20Sascha Haeberling /** Whether the mode list is (partially or fully) visible. */ 9488c1a922df154182b53f00c38198db7da0b4feb20Sascha Haeberling public abstract void onVisibilityChanged(boolean visible); 9498c1a922df154182b53f00c38198db7da0b4feb20Sascha Haeberling 9508c1a922df154182b53f00c38198db7da0b4feb20Sascha Haeberling /** 9518c1a922df154182b53f00c38198db7da0b4feb20Sascha Haeberling * Internal method to be called by the mode list whenever a visibility 9528c1a922df154182b53f00c38198db7da0b4feb20Sascha Haeberling * even occurs. 9538c1a922df154182b53f00c38198db7da0b4feb20Sascha Haeberling * <p> 9548c1a922df154182b53f00c38198db7da0b4feb20Sascha Haeberling * Do not call {@link #onVisibilityChanged(boolean)} directly, as this 9558c1a922df154182b53f00c38198db7da0b4feb20Sascha Haeberling * is only called when the visibility has actually changed and not on 9568c1a922df154182b53f00c38198db7da0b4feb20Sascha Haeberling * each visibility event. 9578c1a922df154182b53f00c38198db7da0b4feb20Sascha Haeberling * 9588c1a922df154182b53f00c38198db7da0b4feb20Sascha Haeberling * @param visible whether the mode drawer is currently visible. 9598c1a922df154182b53f00c38198db7da0b4feb20Sascha Haeberling */ 9608c1a922df154182b53f00c38198db7da0b4feb20Sascha Haeberling private void onVisibilityEvent(boolean visible) { 961b49ab283fe6fce242901a1a09fc2b148b27fe123Sascha Haeberling if (mCurrentVisibility == null || mCurrentVisibility != visible) { 962b49ab283fe6fce242901a1a09fc2b148b27fe123Sascha Haeberling mCurrentVisibility = visible; 9638c1a922df154182b53f00c38198db7da0b4feb20Sascha Haeberling onVisibilityChanged(visible); 964b49ab283fe6fce242901a1a09fc2b148b27fe123Sascha Haeberling } 9658c1a922df154182b53f00c38198db7da0b4feb20Sascha Haeberling } 9668c1a922df154182b53f00c38198db7da0b4feb20Sascha Haeberling } 9678c1a922df154182b53f00c38198db7da0b4feb20Sascha Haeberling 96870576b611fddc929abbfb466fa44c396a3a793dbDoris Liu /** 969cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu * This class aims to help store time and position in pairs. 970cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu */ 971cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu private static class TimeBasedPosition { 972601921e746832bdef40503c606a95b4469f1bedbSascha Haeberling private final float mPosition; 973601921e746832bdef40503c606a95b4469f1bedbSascha Haeberling private final long mTimeStamp; 974cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu public TimeBasedPosition(float position, long time) { 975cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu mPosition = position; 976cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu mTimeStamp = time; 977cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu } 978cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu 979cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu public float getPosition() { 980cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu return mPosition; 981cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu } 982cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu 983cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu public long getTimeStamp() { 984cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu return mTimeStamp; 985cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu } 986cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu } 987cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu 988cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu /** 98970576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * This is a highly customized interpolator. The purpose of having this subclass 99070576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * is to encapsulate intricate animation timing, so that the actual animation 99170576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * implementation can be re-used with other interpolators to achieve different 99270576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * animation effects. 99370576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * 99470576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * The accordion animation consists of three stages: 99570576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * 1) Animate into the screen within a pre-specified fly in duration. 99670576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * 2) Hold in place for a certain amount of time (Optional). 99770576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * 3) Animate out of the screen within the given time. 99870576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * 99970576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * The accordion animator is initialized with 3 parameter: 1) initial position, 100070576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * 2) how far out the view should be before flying back out, 3) end position. 100170576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * The interpolation output should be [0f, 0.5f] during animation between 1) 100270576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * to 2), and [0.5f, 1f] for flying from 2) to 3). 100370576b611fddc929abbfb466fa44c396a3a793dbDoris Liu */ 1004601921e746832bdef40503c606a95b4469f1bedbSascha Haeberling private final TimeInterpolator mAccordionInterpolator = new TimeInterpolator() { 10051c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu @Override 10061c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu public float getInterpolation(float input) { 10071c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu 10081c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu float flyInDuration = (float) FLY_OUT_DURATION_MS / (float) TOTAL_DURATION_MS; 10091c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu float holdDuration = (float) (FLY_OUT_DURATION_MS + HOLD_DURATION_MS) 10101c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu / (float) TOTAL_DURATION_MS; 10111c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu if (input == 0) { 10121c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu return 0; 101369cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu } else if (input < flyInDuration) { 101470576b611fddc929abbfb466fa44c396a3a793dbDoris Liu // Stage 1, project result to [0f, 0.5f] 10151c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu input /= flyInDuration; 10161c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu float result = Gusterpolator.INSTANCE.getInterpolation(input); 10171c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu return result * 0.5f; 10181c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu } else if (input < holdDuration) { 101970576b611fddc929abbfb466fa44c396a3a793dbDoris Liu // Stage 2 10201c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu return 0.5f; 10211c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu } else { 102270576b611fddc929abbfb466fa44c396a3a793dbDoris Liu // Stage 3, project result to [0.5f, 1f] 10231c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu input -= holdDuration; 10241c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu input /= (1 - holdDuration); 10251c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu float result = Gusterpolator.INSTANCE.getInterpolation(input); 10261c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu return 0.5f + result * 0.5f; 10271c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu } 10281c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu } 10291c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu }; 10301c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu 103170576b611fddc929abbfb466fa44c396a3a793dbDoris Liu /** 103270576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * The listener that is used to notify when gestures occur. 103370576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * Here we only listen to a subset of gestures. 103470576b611fddc929abbfb466fa44c396a3a793dbDoris Liu */ 1035601921e746832bdef40503c606a95b4469f1bedbSascha Haeberling private final GestureDetector.OnGestureListener mOnGestureListener 10361c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu = new GestureDetector.SimpleOnGestureListener(){ 103770576b611fddc929abbfb466fa44c396a3a793dbDoris Liu @Override 10381c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu public boolean onScroll(MotionEvent e1, MotionEvent e2, 10391c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu float distanceX, float distanceY) { 104026e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger mCurrentStateManager.getCurrentState().onScroll(e1, e2, distanceX, distanceY); 104169cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu mLastScrollTime = System.currentTimeMillis(); 10421c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu return true; 10431c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu } 10441c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu 10451c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu @Override 10461c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu public boolean onSingleTapUp(MotionEvent ev) { 104726e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger mCurrentStateManager.getCurrentState().onSingleTapUp(ev); 10481c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu return true; 10491c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu } 10506c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu 10516c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu @Override 10526c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { 10536c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu // Cache velocity in the unit pixel/ms. 1054213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu mVelocityX = velocityX / 1000f * SCROLL_FACTOR; 105526e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger mCurrentStateManager.getCurrentState().onFling(e1, e2, velocityX, velocityY); 1056a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return true; 1057a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 1058a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 1059a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 1060a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public boolean onDown(MotionEvent ev) { 1061a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu mVelocityX = 0; 106226e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger mCurrentStateManager.getCurrentState().onDown(ev); 10636c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu return true; 10646c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu } 10651c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu }; 10661c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu 10676ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu /** 10686ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu * Gets called when a mode item in the mode drawer is clicked. 10696ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu * 10706ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu * @param selectedItem the item being clicked 10716ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu */ 10726ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu private void onItemSelected(ModeSelectorItem selectedItem) { 1073427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu int modeId = selectedItem.getModeId(); 1074427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu mModeSwitchListener.onModeButtonPressed(modeId); 1075427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu 107626e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger mCurrentStateManager.getCurrentState().onItemSelected(selectedItem); 10776ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu } 10786ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu 10796ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu /** 10806ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu * Checks whether a touch event is inside of the bounds of the mode list. 10816ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu * 10826ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu * @param ev touch event to be checked 10836ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu * @return whether the touch is inside the bounds of the mode list 10846ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu */ 10856ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu private boolean isTouchInsideList(MotionEvent ev) { 10866ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu // Ignore the tap if it happens outside of the mode list linear layout. 10876ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu float x = ev.getX() - mListView.getX(); 10886ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu float y = ev.getY() - mListView.getY(); 10896ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu if (x < 0 || x > mListView.getWidth() || y < 0 || y > mListView.getHeight()) { 10906ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu return false; 10916ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu } 10926ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu return true; 10936ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu } 10946ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu 10951c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu public ModeListView(Context context, AttributeSet attrs) { 10961c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu super(context, attrs); 10971c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu mGestureDetector = new GestureDetector(context, mOnGestureListener); 109870576b611fddc929abbfb466fa44c396a3a793dbDoris Liu mListBackgroundColor = getResources().getColor(R.color.mode_list_background); 109928a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu mSettingsButtonMargin = getResources().getDimensionPixelSize( 110028a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu R.dimen.mode_list_settings_icon_margin); 1101e7e0c028d568c1a4c3e88ed75411b8b41c5aec69Doris Liu } 1102e7e0c028d568c1a4c3e88ed75411b8b41c5aec69Doris Liu 1103c064750b7a02c4e495a30d2ec8d25319a9e49e9cSpike Sprague private void disableA11yOnModeSelectorItems() { 1104c064750b7a02c4e495a30d2ec8d25319a9e49e9cSpike Sprague for (View selectorItem : mModeSelectorItems) { 1105c064750b7a02c4e495a30d2ec8d25319a9e49e9cSpike Sprague selectorItem.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); 1106c064750b7a02c4e495a30d2ec8d25319a9e49e9cSpike Sprague } 1107c064750b7a02c4e495a30d2ec8d25319a9e49e9cSpike Sprague } 1108c064750b7a02c4e495a30d2ec8d25319a9e49e9cSpike Sprague 1109c064750b7a02c4e495a30d2ec8d25319a9e49e9cSpike Sprague private void enableA11yOnModeSelectorItems() { 1110c064750b7a02c4e495a30d2ec8d25319a9e49e9cSpike Sprague for (View selectorItem : mModeSelectorItems) { 1111c064750b7a02c4e495a30d2ec8d25319a9e49e9cSpike Sprague selectorItem.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO); 1112c064750b7a02c4e495a30d2ec8d25319a9e49e9cSpike Sprague } 1113c064750b7a02c4e495a30d2ec8d25319a9e49e9cSpike Sprague } 1114c064750b7a02c4e495a30d2ec8d25319a9e49e9cSpike Sprague 111570576b611fddc929abbfb466fa44c396a3a793dbDoris Liu /** 111670576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * Sets the alpha on the list background. This is called whenever the list 111770576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * is scrolling or animating, so that background can adjust its dimness. 111870576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * 111970576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * @param alpha new alpha to be applied on list background color 112070576b611fddc929abbfb466fa44c396a3a793dbDoris Liu */ 112170576b611fddc929abbfb466fa44c396a3a793dbDoris Liu private void setBackgroundAlpha(int alpha) { 112270576b611fddc929abbfb466fa44c396a3a793dbDoris Liu // Make sure alpha is valid. 112370576b611fddc929abbfb466fa44c396a3a793dbDoris Liu alpha = alpha & 0xFF; 112470576b611fddc929abbfb466fa44c396a3a793dbDoris Liu // Change alpha on the background color. 112570576b611fddc929abbfb466fa44c396a3a793dbDoris Liu mListBackgroundColor = mListBackgroundColor & 0xFFFFFF; 112670576b611fddc929abbfb466fa44c396a3a793dbDoris Liu mListBackgroundColor = mListBackgroundColor | (alpha << 24); 112770576b611fddc929abbfb466fa44c396a3a793dbDoris Liu // Set new color to list background. 1128213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu setBackgroundColor(mListBackgroundColor); 11291c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu } 11301c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu 1131a20074f0efeaa62a29b05838110d04a1b7271418Doris Liu /** 1132a20074f0efeaa62a29b05838110d04a1b7271418Doris Liu * Initialize mode list with a list of indices of supported modes. 1133a20074f0efeaa62a29b05838110d04a1b7271418Doris Liu * 1134a20074f0efeaa62a29b05838110d04a1b7271418Doris Liu * @param modeIndexList a list of indices of supported modes 1135a20074f0efeaa62a29b05838110d04a1b7271418Doris Liu */ 1136a20074f0efeaa62a29b05838110d04a1b7271418Doris Liu public void init(List<Integer> modeIndexList) { 1137bd1b8f910d6f2c94daac304f4bd1a098939474c3Doris Liu int[] modeSequence = getResources() 1138bd1b8f910d6f2c94daac304f4bd1a098939474c3Doris Liu .getIntArray(R.array.camera_modes_in_nav_drawer_if_supported); 1139bd1b8f910d6f2c94daac304f4bd1a098939474c3Doris Liu int[] visibleModes = getResources() 1140bd1b8f910d6f2c94daac304f4bd1a098939474c3Doris Liu .getIntArray(R.array.camera_modes_always_visible); 1141a20074f0efeaa62a29b05838110d04a1b7271418Doris Liu 1142a20074f0efeaa62a29b05838110d04a1b7271418Doris Liu // Mark the supported modes in a boolean array to preserve the 1143a20074f0efeaa62a29b05838110d04a1b7271418Doris Liu // sequence of the modes 11440496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague SparseBooleanArray modeIsSupported = new SparseBooleanArray(); 1145a20074f0efeaa62a29b05838110d04a1b7271418Doris Liu for (int i = 0; i < modeIndexList.size(); i++) { 1146a20074f0efeaa62a29b05838110d04a1b7271418Doris Liu int mode = modeIndexList.get(i); 1147bd1b8f910d6f2c94daac304f4bd1a098939474c3Doris Liu modeIsSupported.put(mode, true); 1148a20074f0efeaa62a29b05838110d04a1b7271418Doris Liu } 1149bd1b8f910d6f2c94daac304f4bd1a098939474c3Doris Liu for (int i = 0; i < visibleModes.length; i++) { 1150bd1b8f910d6f2c94daac304f4bd1a098939474c3Doris Liu int mode = visibleModes[i]; 1151bd1b8f910d6f2c94daac304f4bd1a098939474c3Doris Liu modeIsSupported.put(mode, true); 1152bd1b8f910d6f2c94daac304f4bd1a098939474c3Doris Liu } 1153bd1b8f910d6f2c94daac304f4bd1a098939474c3Doris Liu 1154a20074f0efeaa62a29b05838110d04a1b7271418Doris Liu // Put the indices of supported modes into an array preserving their 1155a20074f0efeaa62a29b05838110d04a1b7271418Doris Liu // display order. 1156bd1b8f910d6f2c94daac304f4bd1a098939474c3Doris Liu mSupportedModes = new ArrayList<Integer>(); 1157bd1b8f910d6f2c94daac304f4bd1a098939474c3Doris Liu for (int i = 0; i < modeSequence.length; i++) { 1158bd1b8f910d6f2c94daac304f4bd1a098939474c3Doris Liu int mode = modeSequence[i]; 1159bd1b8f910d6f2c94daac304f4bd1a098939474c3Doris Liu if (modeIsSupported.get(mode, false)) { 1160bd1b8f910d6f2c94daac304f4bd1a098939474c3Doris Liu mSupportedModes.add(mode); 1161a20074f0efeaa62a29b05838110d04a1b7271418Doris Liu } 1162a20074f0efeaa62a29b05838110d04a1b7271418Doris Liu } 1163bd1b8f910d6f2c94daac304f4bd1a098939474c3Doris Liu mTotalModes = mSupportedModes.size(); 1164a20074f0efeaa62a29b05838110d04a1b7271418Doris Liu initializeModeSelectorItems(); 116528a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu mSettingsButton = findViewById(R.id.settings_button); 11669d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu mSettingsButton.setOnClickListener(new OnClickListener() { 11679d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu @Override 11689d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu public void onClick(View v) { 11695842607d1b9ec2b5e751a8aaf43ff97cc3f85d22Doris Liu // Post this callback to make sure current user interaction has 11705842607d1b9ec2b5e751a8aaf43ff97cc3f85d22Doris Liu // been reflected in the UI. Specifically, the pressed state gets 11715842607d1b9ec2b5e751a8aaf43ff97cc3f85d22Doris Liu // unset after click happens. In order to ensure the pressed state 11725842607d1b9ec2b5e751a8aaf43ff97cc3f85d22Doris Liu // gets unset in UI before getting in the low frame rate settings 11735842607d1b9ec2b5e751a8aaf43ff97cc3f85d22Doris Liu // activity launch stage, the settings selected callback is posted. 11745842607d1b9ec2b5e751a8aaf43ff97cc3f85d22Doris Liu post(new Runnable() { 11755842607d1b9ec2b5e751a8aaf43ff97cc3f85d22Doris Liu @Override 11765842607d1b9ec2b5e751a8aaf43ff97cc3f85d22Doris Liu public void run() { 11775842607d1b9ec2b5e751a8aaf43ff97cc3f85d22Doris Liu mModeSwitchListener.onSettingsSelected(); 11785842607d1b9ec2b5e751a8aaf43ff97cc3f85d22Doris Liu } 11795842607d1b9ec2b5e751a8aaf43ff97cc3f85d22Doris Liu }); 11809d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu } 11819d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu }); 11828676e7802fb40f64a3b465c9b5e1a0a1ada9f699Doris Liu // The mode list is initialized to be all the way closed. 11838676e7802fb40f64a3b465c9b5e1a0a1ada9f699Doris Liu onModeListOpenRatioUpdate(0); 118426e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger if (mCurrentStateManager.getCurrentState() == null) { 118526e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger mCurrentStateManager.setCurrentState(new FullyHiddenState()); 1186a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 1187a20074f0efeaa62a29b05838110d04a1b7271418Doris Liu } 1188a20074f0efeaa62a29b05838110d04a1b7271418Doris Liu 1189213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu /** 1190213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu * Sets the screen shot provider for getting a preview frame and a bitmap 1191213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu * of the controls and overlay. 1192213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu */ 1193213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu public void setCameraModuleScreenShotProvider( 1194213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu CameraAppUI.CameraModuleScreenShotProvider provider) { 1195213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu mScreenShotProvider = provider; 1196213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu } 1197213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu 1198a20074f0efeaa62a29b05838110d04a1b7271418Doris Liu private void initializeModeSelectorItems() { 1199a20074f0efeaa62a29b05838110d04a1b7271418Doris Liu mModeSelectorItems = new ModeSelectorItem[mTotalModes]; 120070576b611fddc929abbfb466fa44c396a3a793dbDoris Liu // Inflate the mode selector items and add them to a linear layout 12018be316c7a8caf962cf3fcf5e49d332fb2718319fPaul Rohde LayoutInflater inflater = AndroidServices.instance().provideLayoutInflater(); 12021c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu mListView = (LinearLayout) findViewById(R.id.mode_list); 12031c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu for (int i = 0; i < mTotalModes; i++) { 12046ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu final ModeSelectorItem selectorItem = 12051c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu (ModeSelectorItem) inflater.inflate(R.layout.mode_selector, null); 12061c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu mListView.addView(selectorItem); 1207e7e0c028d568c1a4c3e88ed75411b8b41c5aec69Doris Liu // Sets the top padding of the top item to 0. 1208e7e0c028d568c1a4c3e88ed75411b8b41c5aec69Doris Liu if (i == 0) { 1209e7e0c028d568c1a4c3e88ed75411b8b41c5aec69Doris Liu selectorItem.setPadding(selectorItem.getPaddingLeft(), 0, 1210e7e0c028d568c1a4c3e88ed75411b8b41c5aec69Doris Liu selectorItem.getPaddingRight(), selectorItem.getPaddingBottom()); 1211e7e0c028d568c1a4c3e88ed75411b8b41c5aec69Doris Liu } 1212e7e0c028d568c1a4c3e88ed75411b8b41c5aec69Doris Liu // Sets the bottom padding of the bottom item to 0. 1213e7e0c028d568c1a4c3e88ed75411b8b41c5aec69Doris Liu if (i == mTotalModes - 1) { 1214e7e0c028d568c1a4c3e88ed75411b8b41c5aec69Doris Liu selectorItem.setPadding(selectorItem.getPaddingLeft(), selectorItem.getPaddingTop(), 1215e7e0c028d568c1a4c3e88ed75411b8b41c5aec69Doris Liu selectorItem.getPaddingRight(), 0); 1216e7e0c028d568c1a4c3e88ed75411b8b41c5aec69Doris Liu } 1217213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu 1218a20074f0efeaa62a29b05838110d04a1b7271418Doris Liu int modeId = getModeIndex(i); 1219213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu selectorItem.setHighlightColor(getResources() 1220bd1b8f910d6f2c94daac304f4bd1a098939474c3Doris Liu .getColor(CameraUtil.getCameraThemeColorId(modeId, getContext()))); 12211c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu 12221c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu // Set image 1223bd1b8f910d6f2c94daac304f4bd1a098939474c3Doris Liu selectorItem.setImageResource(CameraUtil.getCameraModeIconResId(modeId, getContext())); 122470576b611fddc929abbfb466fa44c396a3a793dbDoris Liu 12251c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu // Set text 1226bd1b8f910d6f2c94daac304f4bd1a098939474c3Doris Liu selectorItem.setText(CameraUtil.getCameraModeText(modeId, getContext())); 122779718f6c6fb60aedd09edeedb2c16d1e2f9fe02dSpike Sprague 122879718f6c6fb60aedd09edeedb2c16d1e2f9fe02dSpike Sprague // Set content description (for a11y) 122979718f6c6fb60aedd09edeedb2c16d1e2f9fe02dSpike Sprague selectorItem.setContentDescription(CameraUtil 123079718f6c6fb60aedd09edeedb2c16d1e2f9fe02dSpike Sprague .getCameraModeContentDescription(modeId, getContext())); 12316ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu selectorItem.setModeId(modeId); 12326ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu selectorItem.setOnClickListener(new OnClickListener() { 12336ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu @Override 12346ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu public void onClick(View v) { 12356ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu onItemSelected(selectorItem); 12366ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu } 12376ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu }); 123879718f6c6fb60aedd09edeedb2c16d1e2f9fe02dSpike Sprague 123970576b611fddc929abbfb466fa44c396a3a793dbDoris Liu mModeSelectorItems[i] = selectorItem; 12401c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu } 124169cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu // During drawer opening/closing, we change the visible width of the mode 124269cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu // items in sequence, so we listen to the last item's visible width change 124369cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu // for a good timing to do corresponding UI adjustments. 124469cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu mModeSelectorItems[mTotalModes - 1].setVisibleWidthChangedListener(this); 12451c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu resetModeSelectors(); 12461c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu } 12471c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu 1248a20074f0efeaa62a29b05838110d04a1b7271418Doris Liu /** 1249a20074f0efeaa62a29b05838110d04a1b7271418Doris Liu * Maps between the UI mode selector index to the actual mode id. 1250a20074f0efeaa62a29b05838110d04a1b7271418Doris Liu * 1251a20074f0efeaa62a29b05838110d04a1b7271418Doris Liu * @param modeSelectorIndex the index of the UI item 1252a20074f0efeaa62a29b05838110d04a1b7271418Doris Liu * @return the index of the corresponding camera mode 1253a20074f0efeaa62a29b05838110d04a1b7271418Doris Liu */ 1254a20074f0efeaa62a29b05838110d04a1b7271418Doris Liu private int getModeIndex(int modeSelectorIndex) { 1255a20074f0efeaa62a29b05838110d04a1b7271418Doris Liu if (modeSelectorIndex < mTotalModes && modeSelectorIndex >= 0) { 1256bd1b8f910d6f2c94daac304f4bd1a098939474c3Doris Liu return mSupportedModes.get(modeSelectorIndex); 1257a20074f0efeaa62a29b05838110d04a1b7271418Doris Liu } 12585596b4c902dcb685928b43678f428746ca5ffd08Angus Kong Log.e(TAG, "Invalid mode selector index: " + modeSelectorIndex + ", total modes: " + 12595596b4c902dcb685928b43678f428746ca5ffd08Angus Kong mTotalModes); 1260bd1b8f910d6f2c94daac304f4bd1a098939474c3Doris Liu return getResources().getInteger(R.integer.camera_mode_photo); 1261a20074f0efeaa62a29b05838110d04a1b7271418Doris Liu } 1262a20074f0efeaa62a29b05838110d04a1b7271418Doris Liu 126370576b611fddc929abbfb466fa44c396a3a793dbDoris Liu /** Notify ModeSwitchListener, if any, of the mode change. */ 12641c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu private void onModeSelected(int modeIndex) { 12652c559c4bd3c65e0cb0bca06f30e3bc979038e6f7Doris Liu if (mModeSwitchListener != null) { 12662c559c4bd3c65e0cb0bca06f30e3bc979038e6f7Doris Liu mModeSwitchListener.onModeSelected(modeIndex); 12671c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu } 12681c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu } 12691c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu 12701c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu /** 127170576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * Sets a listener that listens to receive mode switch event. 127270576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * 127370576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * @param listener a listener that gets notified when mode changes. 12741c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu */ 12751c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu public void setModeSwitchListener(ModeSwitchListener listener) { 12762c559c4bd3c65e0cb0bca06f30e3bc979038e6f7Doris Liu mModeSwitchListener = listener; 12772c559c4bd3c65e0cb0bca06f30e3bc979038e6f7Doris Liu } 12782c559c4bd3c65e0cb0bca06f30e3bc979038e6f7Doris Liu 12792c559c4bd3c65e0cb0bca06f30e3bc979038e6f7Doris Liu /** 12802c559c4bd3c65e0cb0bca06f30e3bc979038e6f7Doris Liu * Sets a listener that gets notified when the mode list is open full screen. 12812c559c4bd3c65e0cb0bca06f30e3bc979038e6f7Doris Liu * 12822c559c4bd3c65e0cb0bca06f30e3bc979038e6f7Doris Liu * @param listener a listener that listens to mode list open events 12832c559c4bd3c65e0cb0bca06f30e3bc979038e6f7Doris Liu */ 12842c559c4bd3c65e0cb0bca06f30e3bc979038e6f7Doris Liu public void setModeListOpenListener(ModeListOpenListener listener) { 12852c559c4bd3c65e0cb0bca06f30e3bc979038e6f7Doris Liu mModeListOpenListener = listener; 12861c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu } 12871c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu 12888c1a922df154182b53f00c38198db7da0b4feb20Sascha Haeberling /** 12898c1a922df154182b53f00c38198db7da0b4feb20Sascha Haeberling * Sets or replaces a listener that is called when the visibility of the 12908c1a922df154182b53f00c38198db7da0b4feb20Sascha Haeberling * mode list changed. 12918c1a922df154182b53f00c38198db7da0b4feb20Sascha Haeberling */ 12928c1a922df154182b53f00c38198db7da0b4feb20Sascha Haeberling public void setVisibilityChangedListener(ModeListVisibilityChangedListener listener) { 12938c1a922df154182b53f00c38198db7da0b4feb20Sascha Haeberling mVisibilityChangedListener = listener; 12948c1a922df154182b53f00c38198db7da0b4feb20Sascha Haeberling } 12958c1a922df154182b53f00c38198db7da0b4feb20Sascha Haeberling 12961c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu @Override 12971c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu public boolean onTouchEvent(MotionEvent ev) { 1298a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu // Reset touch forward recipient 1299a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu if (MotionEvent.ACTION_DOWN == ev.getActionMasked()) { 1300a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu mChildViewTouched = null; 1301b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu } 1302b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu 130326e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger if (!mCurrentStateManager.getCurrentState().shouldHandleTouchEvent(ev)) { 1304a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return false; 130569cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu } 13069eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu getParent().requestDisallowInterceptTouchEvent(true); 13071c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu super.onTouchEvent(ev); 1308908bace4c8ceb9ebf4644827350a0792cbd44331Seth Raphael 130970576b611fddc929abbfb466fa44c396a3a793dbDoris Liu // Pass all touch events to gesture detector for gesture handling. 13101c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu mGestureDetector.onTouchEvent(ev); 131126e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger mCurrentStateManager.getCurrentState().onTouchEvent(ev); 13121c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu return true; 13131c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu } 13141c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu 13151c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu /** 13166ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu * Forward touch events to a recipient child view. Before feeding the motion 13176ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu * event into the child view, the event needs to be converted in child view's 13186ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu * coordinates. 13196ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu */ 13206ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu private void forwardTouchEventToChild(MotionEvent ev) { 13216ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu if (mChildViewTouched != null) { 13226ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu float x = ev.getX() - mListView.getX(); 13236ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu float y = ev.getY() - mListView.getY(); 13246ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu x -= mChildViewTouched.getLeft(); 13256ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu y -= mChildViewTouched.getTop(); 13266ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu 13276ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu mLastChildTouchEvent = MotionEvent.obtain(ev); 13286ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu mLastChildTouchEvent.setLocation(x, y); 13296ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu mChildViewTouched.onTouchEvent(mLastChildTouchEvent); 13306ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu } 13316ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu } 13326ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu 13336ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu /** 13341c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu * Sets the swipe mode to indicate whether this is a swiping in 13351c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu * or out, and therefore we can have different animations. 133670576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * 133770576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * @param swipeIn indicates whether the swipe should reveal/hide the list. 13381c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu */ 13391c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu private void setSwipeMode(boolean swipeIn) { 134070576b611fddc929abbfb466fa44c396a3a793dbDoris Liu for (int i = 0 ; i < mModeSelectorItems.length; i++) { 134170576b611fddc929abbfb466fa44c396a3a793dbDoris Liu mModeSelectorItems[i].onSwipeModeChanged(swipeIn); 13421c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu } 13431c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu } 13441c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu 13451c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu @Override 13461c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 13471c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu super.onLayout(changed, left, top, right, bottom); 13481c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu mWidth = right - left; 13491c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu mHeight = bottom - top - getPaddingTop() - getPaddingBottom(); 135028a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu 135128a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu updateModeListLayout(); 135228a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu 135326e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger if (mCurrentStateManager.getCurrentState().getCurrentAnimationEffects() != null) { 135426e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger mCurrentStateManager.getCurrentState().getCurrentAnimationEffects().setSize( 135526e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger mWidth, mHeight); 1356b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu } 13571c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu } 13581c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu 135970576b611fddc929abbfb466fa44c396a3a793dbDoris Liu /** 136028a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu * Sets a capture layout helper to query layout rect from. 136170576b611fddc929abbfb466fa44c396a3a793dbDoris Liu */ 136228a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu public void setCaptureLayoutHelper(CaptureLayoutHelper helper) { 136328a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu mCaptureLayoutHelper = helper; 136428a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu } 136528a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu 1366b908d933736a4ec042aad065b7ebf2059bbcac97Doris Liu @Override 1367b908d933736a4ec042aad065b7ebf2059bbcac97Doris Liu public void onPreviewAreaChanged(RectF previewArea) { 1368b908d933736a4ec042aad065b7ebf2059bbcac97Doris Liu if (getVisibility() == View.VISIBLE && !hasWindowFocus()) { 1369b908d933736a4ec042aad065b7ebf2059bbcac97Doris Liu // When the preview area has changed, to avoid visual disruption we 1370b908d933736a4ec042aad065b7ebf2059bbcac97Doris Liu // only make corresponding UI changes when mode list does not have 1371b908d933736a4ec042aad065b7ebf2059bbcac97Doris Liu // window focus. 1372b908d933736a4ec042aad065b7ebf2059bbcac97Doris Liu updateModeListLayout(); 1373b908d933736a4ec042aad065b7ebf2059bbcac97Doris Liu } 1374b908d933736a4ec042aad065b7ebf2059bbcac97Doris Liu } 1375b908d933736a4ec042aad065b7ebf2059bbcac97Doris Liu 137628a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu private void updateModeListLayout() { 137728a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu if (mCaptureLayoutHelper == null) { 137828a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu Log.e(TAG, "Capture layout helper needs to be set first."); 137928a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu return; 138028a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu } 138128a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu // Center mode drawer in the portion of camera preview that is not covered by 138228a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu // bottom bar. 138328a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu RectF uncoveredPreviewArea = mCaptureLayoutHelper.getUncoveredPreviewRect(); 138428a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu // Align left: 138528a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu mListView.setTranslationX(uncoveredPreviewArea.left); 138628a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu // Align center vertical: 138728a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu mListView.setTranslationY(uncoveredPreviewArea.centerY() 138828a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu - mListView.getMeasuredHeight() / 2); 138928a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu 139028a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu updateSettingsButtonLayout(uncoveredPreviewArea); 139128a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu } 139228a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu 139328a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu private void updateSettingsButtonLayout(RectF uncoveredPreviewArea) { 139428a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu if (mWidth > mHeight) { 139528a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu // Align to the top right. 139628a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu mSettingsButton.setTranslationX(uncoveredPreviewArea.right - mSettingsButtonMargin 139728a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu - mSettingsButton.getMeasuredWidth()); 139828a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu mSettingsButton.setTranslationY(uncoveredPreviewArea.top + mSettingsButtonMargin); 139928a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu } else { 140028a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu // Align to the bottom right. 140128a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu mSettingsButton.setTranslationX(uncoveredPreviewArea.right - mSettingsButtonMargin 140228a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu - mSettingsButton.getMeasuredWidth()); 140328a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu mSettingsButton.setTranslationY(uncoveredPreviewArea.bottom - mSettingsButtonMargin 140428a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu - mSettingsButton.getMeasuredHeight()); 140528a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu } 140626aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu if (mSettingsCling != null) { 140726aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu mSettingsCling.updatePosition(mSettingsButton); 140826aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu } 14091c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu } 14101c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu 1411b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu @Override 1412b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu public void draw(Canvas canvas) { 141326e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger ModeListState currentState = mCurrentStateManager.getCurrentState(); 1414bee2022d8dcde61d2b0c6cf9b709d8e34cdcb739Doris Liu AnimationEffects currentEffects = currentState.getCurrentAnimationEffects(); 1415bee2022d8dcde61d2b0c6cf9b709d8e34cdcb739Doris Liu if (currentEffects != null) { 1416bee2022d8dcde61d2b0c6cf9b709d8e34cdcb739Doris Liu currentEffects.drawBackground(canvas); 1417bee2022d8dcde61d2b0c6cf9b709d8e34cdcb739Doris Liu if (currentEffects.shouldDrawSuper()) { 1418bee2022d8dcde61d2b0c6cf9b709d8e34cdcb739Doris Liu super.draw(canvas); 1419bee2022d8dcde61d2b0c6cf9b709d8e34cdcb739Doris Liu } 1420bee2022d8dcde61d2b0c6cf9b709d8e34cdcb739Doris Liu currentEffects.drawForeground(canvas); 1421b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu } else { 1422b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu super.draw(canvas); 1423b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu } 1424b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu } 1425b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu 142670576b611fddc929abbfb466fa44c396a3a793dbDoris Liu /** 142726aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu * Sets whether a cling for settings button should be shown. If not, remove 142826aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu * the cling from view hierarchy if any. If a cling should be shown, inflate 142926aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu * the cling into this view group. 143026aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu * 143126aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu * @param show whether the cling needs to be shown. 143226aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu */ 143326aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu public void setShouldShowSettingsCling(boolean show) { 143426aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu if (show) { 143526aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu if (mSettingsCling == null) { 143626aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu inflate(getContext(), R.layout.settings_cling, this); 143726aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu mSettingsCling = (SettingsCling) findViewById(R.id.settings_cling); 143826aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu } 143926aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu } else { 144026aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu if (mSettingsCling != null) { 144126aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu // Remove settings cling from view hierarchy. 144226aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu removeView(mSettingsCling); 144326aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu mSettingsCling = null; 144426aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu } 144526aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu } 144626aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu } 144726aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu 144826aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu /** 144926aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu * Show or hide cling for settings button. The cling will only be shown if 145026aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu * settings button has never been clicked. Otherwise, cling will be null, 145126aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu * and will not show even if this method is called to show it. 145226aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu */ 145326aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu private void showSettingsClingIfEnabled(boolean show) { 145426aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu if (mSettingsCling != null) { 145526aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu int visibility = show ? VISIBLE : INVISIBLE; 145626aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu mSettingsCling.setVisibility(visibility); 145726aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu } 145826aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu } 145926aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu 146026aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu /** 1461b00d64307ae77541f8576593a29214d649fb94e9Doris Liu * This shows the mode switcher and starts the accordion animation with a delay. 1462b00d64307ae77541f8576593a29214d649fb94e9Doris Liu * If the view does not currently have focus, (e.g. There are popups on top of 1463b00d64307ae77541f8576593a29214d649fb94e9Doris Liu * it.) start the delayed accordion animation when it gains focus. Otherwise, 1464b00d64307ae77541f8576593a29214d649fb94e9Doris Liu * start the animation with a delay right away. 1465b7d3ce145dd7b1cf0ac51f53d5bc73dbbf35f6e6Doris Liu */ 1466b00d64307ae77541f8576593a29214d649fb94e9Doris Liu public void showModeSwitcherHint() { 146726e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger mCurrentStateManager.getCurrentState().showSwitcherHint(); 1468b7d3ce145dd7b1cf0ac51f53d5bc73dbbf35f6e6Doris Liu } 1469b7d3ce145dd7b1cf0ac51f53d5bc73dbbf35f6e6Doris Liu 1470b7d3ce145dd7b1cf0ac51f53d5bc73dbbf35f6e6Doris Liu /** 14714c96d840aeff669011a9e8697cbac77fe8f4eda2Spike Sprague * Hide the mode list immediately (provided the current state allows it). 14724c96d840aeff669011a9e8697cbac77fe8f4eda2Spike Sprague */ 14734c96d840aeff669011a9e8697cbac77fe8f4eda2Spike Sprague public void hide() { 14744c96d840aeff669011a9e8697cbac77fe8f4eda2Spike Sprague mCurrentStateManager.getCurrentState().hide(); 14754c96d840aeff669011a9e8697cbac77fe8f4eda2Spike Sprague } 14764c96d840aeff669011a9e8697cbac77fe8f4eda2Spike Sprague 14774c96d840aeff669011a9e8697cbac77fe8f4eda2Spike Sprague /** 14784c96d840aeff669011a9e8697cbac77fe8f4eda2Spike Sprague * Hide the mode list with an animation. 14794c96d840aeff669011a9e8697cbac77fe8f4eda2Spike Sprague */ 14804c96d840aeff669011a9e8697cbac77fe8f4eda2Spike Sprague public void hideAnimated() { 14814c96d840aeff669011a9e8697cbac77fe8f4eda2Spike Sprague mCurrentStateManager.getCurrentState().hideAnimated(); 14824c96d840aeff669011a9e8697cbac77fe8f4eda2Spike Sprague } 14834c96d840aeff669011a9e8697cbac77fe8f4eda2Spike Sprague 14844c96d840aeff669011a9e8697cbac77fe8f4eda2Spike Sprague /** 148570576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * Resets the visible width of all the mode selectors to 0. 148670576b611fddc929abbfb466fa44c396a3a793dbDoris Liu */ 14871c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu private void resetModeSelectors() { 148870576b611fddc929abbfb466fa44c396a3a793dbDoris Liu for (int i = 0; i < mModeSelectorItems.length; i++) { 148970576b611fddc929abbfb466fa44c396a3a793dbDoris Liu mModeSelectorItems[i].setVisibleWidth(0); 14901c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu } 14911c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu } 14921c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu 14931c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu private boolean isRunningAccordionAnimation() { 14941c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu return mAnimatorSet != null && mAnimatorSet.isRunning(); 14951c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu } 14961c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu 149770576b611fddc929abbfb466fa44c396a3a793dbDoris Liu /** 149870576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * Calculate the mode selector item in the list that is at position (x, y). 1499213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu * If the position is above the top item or below the bottom item, return 1500213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu * the top item or bottom item respectively. 1501612321f39ca524de2efced1e826db9ec523bd6dcAngus Kong * 150270576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * @param x horizontal position 150370576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * @param y vertical position 150470576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * @return index of the item that is at position (x, y) 150570576b611fddc929abbfb466fa44c396a3a793dbDoris Liu */ 15061c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu private int getFocusItem(float x, float y) { 1507213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu // Convert coordinates into child view's coordinates. 1508e7e0c028d568c1a4c3e88ed75411b8b41c5aec69Doris Liu x -= mListView.getX(); 1509e7e0c028d568c1a4c3e88ed75411b8b41c5aec69Doris Liu y -= mListView.getY(); 15101c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu 151170576b611fddc929abbfb466fa44c396a3a793dbDoris Liu for (int i = 0; i < mModeSelectorItems.length; i++) { 1512213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu if (y <= mModeSelectorItems[i].getBottom()) { 15131c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu return i; 15141c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu } 15151c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu } 1516213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu return mModeSelectorItems.length - 1; 1517213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu } 1518213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu 1519213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu @Override 1520b00d64307ae77541f8576593a29214d649fb94e9Doris Liu public void onWindowFocusChanged(boolean hasFocus) { 1521b00d64307ae77541f8576593a29214d649fb94e9Doris Liu super.onWindowFocusChanged(hasFocus); 152226e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger mCurrentStateManager.getCurrentState().onWindowFocusChanged(hasFocus); 1523b00d64307ae77541f8576593a29214d649fb94e9Doris Liu } 1524b00d64307ae77541f8576593a29214d649fb94e9Doris Liu 1525b00d64307ae77541f8576593a29214d649fb94e9Doris Liu @Override 1526213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu public void onVisibilityChanged(View v, int visibility) { 1527213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu super.onVisibilityChanged(v, visibility); 1528213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu if (visibility == VISIBLE) { 1529213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu // Highlight current module 1530213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu if (mModeSwitchListener != null) { 1531213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu int modeId = mModeSwitchListener.getCurrentModeIndex(); 1532213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu int parentMode = CameraUtil.getCameraModeParentModeId(modeId, getContext()); 1533213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu // Find parent mode in the nav drawer. 1534213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu for (int i = 0; i < mSupportedModes.size(); i++) { 1535213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu if (mSupportedModes.get(i) == parentMode) { 15366ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu mModeSelectorItems[i].setSelected(true); 1537213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu } 1538213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu } 1539213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu } 154028a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu updateModeListLayout(); 15419d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu } else { 15429d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu if (mModeSelectorItems != null) { 15439d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu // When becoming invisible/gone after initializing mode selector items. 15449d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu for (int i = 0; i < mModeSelectorItems.length; i++) { 15459d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu mModeSelectorItems[i].setSelected(false); 15469d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu } 15479d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu } 15488c1a922df154182b53f00c38198db7da0b4feb20Sascha Haeberling if (mModeListOpenListener != null) { 15499d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu mModeListOpenListener.onModeListClosed(); 1550213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu } 1551213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu } 155238989540cb1488cb7b8062ff74b9dedcd76c047fSpike Sprague 15538c1a922df154182b53f00c38198db7da0b4feb20Sascha Haeberling if (mVisibilityChangedListener != null) { 1554b49ab283fe6fce242901a1a09fc2b148b27fe123Sascha Haeberling mVisibilityChangedListener.onVisibilityEvent(getVisibility() == VISIBLE); 15558c1a922df154182b53f00c38198db7da0b4feb20Sascha Haeberling } 1556213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu } 1557213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu 1558a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu @Override 1559a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public void setVisibility(int visibility) { 156026e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger ModeListState currentState = mCurrentStateManager.getCurrentState(); 156126e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger if (currentState != null && !currentState.shouldHandleVisibilityChange(visibility)) { 1562a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return; 1563a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 1564a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu super.setVisibility(visibility); 1565a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 1566a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 15671c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu private void scroll(int itemId, float deltaX, float deltaY) { 156870576b611fddc929abbfb466fa44c396a3a793dbDoris Liu // Scrolling trend on X and Y axis, to track the trend by biasing 156970576b611fddc929abbfb466fa44c396a3a793dbDoris Liu // towards latest touch events. 15701c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu mScrollTrendX = mScrollTrendX * 0.3f + deltaX * 0.7f; 15711c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu mScrollTrendY = mScrollTrendY * 0.3f + deltaY * 0.7f; 15721c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu 157370576b611fddc929abbfb466fa44c396a3a793dbDoris Liu // TODO: Change how the curve is calculated below when UX finalize their design. 1574cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu mCurrentTime = SystemClock.uptimeMillis(); 15751c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu float longestWidth; 157670576b611fddc929abbfb466fa44c396a3a793dbDoris Liu if (itemId != NO_ITEM_SELECTED) { 157769cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu longestWidth = mModeSelectorItems[itemId].getVisibleWidth(); 15781c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu } else { 157969cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu longestWidth = mModeSelectorItems[0].getVisibleWidth(); 15801c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu } 158169cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu float newPosition = longestWidth - deltaX; 158269cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu int maxVisibleWidth = mModeSelectorItems[0].getMaxVisibleWidth(); 158369cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu newPosition = Math.min(newPosition, getMaxMovementBasedOnPosition((int) longestWidth, 158469cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu maxVisibleWidth)); 158569cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu newPosition = Math.max(newPosition, 0); 158669cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu insertNewPosition(newPosition, mCurrentTime); 15871c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu 158870576b611fddc929abbfb466fa44c396a3a793dbDoris Liu for (int i = 0; i < mModeSelectorItems.length; i++) { 1589d2710487e724660cbb890ebf5eb887b4a93281c1Alan Newberger mModeSelectorItems[i].setVisibleWidth((int) newPosition); 15901c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu } 15911c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu } 15921c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu 1593cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu /** 1594cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu * Insert new position and time stamp into the history position list, and 1595cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu * remove stale position items. 1596cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu * 1597cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu * @param position latest position of the focus item 1598cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu * @param time current time in milliseconds 1599cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu */ 1600cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu private void insertNewPosition(float position, long time) { 1601cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu // TODO: Consider re-using stale position objects rather than 1602cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu // always creating new position objects. 1603cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu mPositionHistory.add(new TimeBasedPosition(position, time)); 1604cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu 1605cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu // Positions that are from too long ago will not be of any use for 1606cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu // future position interpolation. So we need to remove those positions 1607cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu // from the list. 1608cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu long timeCutoff = time - (mTotalModes - 1) * DELAY_MS; 1609cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu while (mPositionHistory.size() > 0) { 1610cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu // Remove all the position items that are prior to the cutoff time. 1611cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu TimeBasedPosition historyPosition = mPositionHistory.getFirst(); 1612cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu if (historyPosition.getTimeStamp() < timeCutoff) { 1613cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu mPositionHistory.removeFirst(); 1614cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu } else { 1615cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu break; 1616cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu } 1617cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu } 1618cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu } 1619cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu 1620cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu /** 1621cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu * Gets the interpolated position at the specified time. This involves going 1622cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu * through the recorded positions until a {@link TimeBasedPosition} is found 1623cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu * such that the position the recorded before the given time, and the 1624cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu * {@link TimeBasedPosition} after that is recorded no earlier than the given 1625cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu * time. These two positions are then interpolated to get the position at the 1626cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu * specified time. 1627cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu */ 162869cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu private float getPosition(long time, float currentPosition) { 1629cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu int i; 1630cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu for (i = 0; i < mPositionHistory.size(); i++) { 1631cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu TimeBasedPosition historyPosition = mPositionHistory.get(i); 1632cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu if (historyPosition.getTimeStamp() > time) { 1633cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu // Found the winner. Now interpolate between position i and position i - 1 1634cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu if (i == 0) { 163569cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu // Slowly approaching to the destination if there isn't enough data points 163669cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu float weight = 0.2f; 163769cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu return historyPosition.getPosition() * weight + (1f - weight) * currentPosition; 1638cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu } else { 1639cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu TimeBasedPosition prevTimeBasedPosition = mPositionHistory.get(i - 1); 1640cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu // Start interpolation 1641cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu float fraction = (float) (time - prevTimeBasedPosition.getTimeStamp()) / 1642cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu (float) (historyPosition.getTimeStamp() - prevTimeBasedPosition.getTimeStamp()); 1643cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu float position = fraction * (historyPosition.getPosition() 1644cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu - prevTimeBasedPosition.getPosition()) + prevTimeBasedPosition.getPosition(); 1645cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu return position; 1646cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu } 1647cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu } 1648cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu } 1649cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu // It should never get here. 1650cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu Log.e(TAG, "Invalid time input for getPosition(). time: " + time); 1651cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu if (mPositionHistory.size() == 0) { 1652cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu Log.e(TAG, "TimeBasedPosition history size is 0"); 1653cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu } else { 1654cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu Log.e(TAG, "First position recorded at " + mPositionHistory.getFirst().getTimeStamp() 1655cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu + " , last position recorded at " + mPositionHistory.getLast().getTimeStamp()); 1656cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu } 1657cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu assert (i < mPositionHistory.size()); 1658cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu return i; 1659cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu } 1660cfaf7b0226e5d556ce12b34793f9bd0901652c62Doris Liu 16611c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu private void reset() { 16621c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu resetModeSelectors(); 16631c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu mScrollTrendX = 0f; 16641c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu mScrollTrendY = 0f; 16651c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu setVisibility(INVISIBLE); 16661c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu } 16671c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu 16681c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu /** 166970576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * When visible width of list is changed, the background of the list needs 167070576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * to darken/lighten correspondingly. 167170576b611fddc929abbfb466fa44c396a3a793dbDoris Liu */ 16720496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague @Override 167369cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu public void onVisibleWidthChanged(int visibleWidth) { 167469cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu mVisibleWidth = visibleWidth; 167569cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu 1676213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu // When the longest mode item is entirely shown (across the screen), the 167770576b611fddc929abbfb466fa44c396a3a793dbDoris Liu // background should be 50% transparent. 1678213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu int maxVisibleWidth = mModeSelectorItems[0].getMaxVisibleWidth(); 167969cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu visibleWidth = Math.min(maxVisibleWidth, visibleWidth); 168069cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu if (visibleWidth != maxVisibleWidth) { 16816ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu // No longer full screen. 16826ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu cancelForwardingTouchEvent(); 16836ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu } 168469cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu float openRatio = (float) visibleWidth / maxVisibleWidth; 1685a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu onModeListOpenRatioUpdate(openRatio * mModeListOpenFactor); 168669cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu } 168769cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu 168869cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu /** 168969cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu * Gets called when UI elements such as background and gear icon need to adjust 169069cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu * their appearance based on the percentage of the mode list opening. 169169cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu * 169269cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu * @param openRatio percentage of the mode list opening, ranging [0f, 1f] 169369cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu */ 169469cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu private void onModeListOpenRatioUpdate(float openRatio) { 169569cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu for (int i = 0; i < mModeSelectorItems.length; i++) { 169669cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu mModeSelectorItems[i].setTextAlpha(openRatio); 169769cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu } 16989d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu setBackgroundAlpha((int) (BACKGROUND_TRANSPARENTCY * openRatio)); 16999d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu if (mModeListOpenListener != null) { 17009d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu mModeListOpenListener.onModeListOpenProgress(openRatio); 17019d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu } 17029d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu if (mSettingsButton != null) { 17031908beee07fe9792338dbf8e0c36a5f1e3e9401fPaul Rohde // Disable the hardware layer when the ratio reaches 0.0 or 1.0. 17041908beee07fe9792338dbf8e0c36a5f1e3e9401fPaul Rohde if (openRatio >= 1.0f || openRatio <= 0.0f) { 17057543914f2de33b1be25626afb31fa979b06dd582Paul Rohde if (mSettingsButton.getLayerType() == View.LAYER_TYPE_HARDWARE) { 17061908beee07fe9792338dbf8e0c36a5f1e3e9401fPaul Rohde Log.v(TAG, "Disabling hardware layer for the Settings Button. (via alpha)"); 17071908beee07fe9792338dbf8e0c36a5f1e3e9401fPaul Rohde mSettingsButton.setLayerType(View.LAYER_TYPE_NONE, null); 17081908beee07fe9792338dbf8e0c36a5f1e3e9401fPaul Rohde } 17091908beee07fe9792338dbf8e0c36a5f1e3e9401fPaul Rohde } else { 17107543914f2de33b1be25626afb31fa979b06dd582Paul Rohde if (mSettingsButton.getLayerType() != View.LAYER_TYPE_HARDWARE) { 17111908beee07fe9792338dbf8e0c36a5f1e3e9401fPaul Rohde Log.v(TAG, "Enabling hardware layer for the Settings Button."); 17121908beee07fe9792338dbf8e0c36a5f1e3e9401fPaul Rohde mSettingsButton.setLayerType(View.LAYER_TYPE_HARDWARE, null); 17131908beee07fe9792338dbf8e0c36a5f1e3e9401fPaul Rohde } 17141908beee07fe9792338dbf8e0c36a5f1e3e9401fPaul Rohde } 17151908beee07fe9792338dbf8e0c36a5f1e3e9401fPaul Rohde 17169d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu mSettingsButton.setAlpha(openRatio); 17179d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu } 171870576b611fddc929abbfb466fa44c396a3a793dbDoris Liu } 171970576b611fddc929abbfb466fa44c396a3a793dbDoris Liu 17206ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu /** 17216ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu * Cancels the touch event forwarding by sending a cancel event to the recipient 17226ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu * view and resetting the touch forward recipient to ensure no more events 17236ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu * can be forwarded in the current series of the touch events. 17246ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu */ 17256ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu private void cancelForwardingTouchEvent() { 17266ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu if (mChildViewTouched != null) { 17276ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu mLastChildTouchEvent.setAction(MotionEvent.ACTION_CANCEL); 17286ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu mChildViewTouched.onTouchEvent(mLastChildTouchEvent); 17296ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu mChildViewTouched = null; 17306ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu } 17316ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu } 17326ababe9379ecee4056a415085e28e7eb5e1249bfDoris Liu 1733b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu @Override 1734b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu public void onWindowVisibilityChanged(int visibility) { 1735b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu super.onWindowVisibilityChanged(visibility); 1736b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu if (visibility != VISIBLE) { 173726e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger mCurrentStateManager.getCurrentState().hide(); 1738b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu } 1739b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu } 1740b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu 174170576b611fddc929abbfb466fa44c396a3a793dbDoris Liu /** 174215691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren * Defines how the list view should respond to a menu button pressed 174315691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren * event. 174415691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren */ 174515691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren public boolean onMenuPressed() { 174626e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger return mCurrentStateManager.getCurrentState().onMenuPressed(); 174715691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren } 174815691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren 174915691af76927d932fcc1250b4ffaefd31a61cf81Erin Dahlgren /** 17501c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu * The list view should either snap back or snap to full screen after a gesture. 17511c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu * This function is called when an up or cancel event is received, and then based 17521c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu * on the current position of the list and the gesture we can decide which way 17531c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu * to snap. 17541c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu */ 17551c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu private void snap() { 1756a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu if (shouldSnapBack()) { 1757a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu snapBack(); 1758a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } else { 1759a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu snapToFullScreen(); 1760a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 1761a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } 1762a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 1763a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu private boolean shouldSnapBack() { 1764a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu int itemId = Math.max(0, mFocusItem); 1765a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu if (Math.abs(mVelocityX) > VELOCITY_THRESHOLD) { 1766a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu // Fling to open / close 1767a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return mVelocityX < 0; 1768a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } else if (mModeSelectorItems[itemId].getVisibleWidth() 1769a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu < mModeSelectorItems[itemId].getMaxVisibleWidth() * SNAP_BACK_THRESHOLD_RATIO) { 1770a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return true; 1771a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } else if (Math.abs(mScrollTrendX) > Math.abs(mScrollTrendY) && mScrollTrendX > 0) { 1772a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return true; 1773a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu } else { 1774a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return false; 17751c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu } 17761c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu } 17771c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu 1778b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu /** 1779b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu * Snaps back out of the screen. 1780b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu * 1781b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu * @param withAnimation whether snapping back should be animated 1782b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu */ 1783a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public Animator snapBack(boolean withAnimation) { 1784b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu if (withAnimation) { 1785213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu if (mVelocityX > -VELOCITY_THRESHOLD * SCROLL_FACTOR) { 1786a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return animateListToWidth(0); 1787213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu } else { 1788a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return animateListToWidthAtVelocity(mVelocityX, 0); 1789213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu } 1790b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu } else { 1791b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu setVisibility(INVISIBLE); 1792b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu resetModeSelectors(); 1793a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return null; 1794b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu } 1795b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu } 1796b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu 1797b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu /** 1798b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu * Snaps the mode list back out with animation. 1799b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu */ 1800a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu private Animator snapBack() { 1801a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return snapBack(true); 18021c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu } 18031c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu 1804a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu private Animator snapToFullScreen() { 1805a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu Animator animator; 1806213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu int focusItem = mFocusItem == NO_ITEM_SELECTED ? 0 : mFocusItem; 1807213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu int fullWidth = mModeSelectorItems[focusItem].getMaxVisibleWidth(); 180869cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu if (mVelocityX <= VELOCITY_THRESHOLD) { 1809a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu animator = animateListToWidth(fullWidth); 18106c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu } else { 18116c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu // If the fling velocity exceeds this threshold, snap to full screen 18126c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu // at a constant speed. 1813a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu animator = animateListToWidthAtVelocity(VELOCITY_THRESHOLD, fullWidth); 18146c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu } 18152c559c4bd3c65e0cb0bca06f30e3bc979038e6f7Doris Liu if (mModeListOpenListener != null) { 18162c559c4bd3c65e0cb0bca06f30e3bc979038e6f7Doris Liu mModeListOpenListener.onOpenFullScreen(); 18172c559c4bd3c65e0cb0bca06f30e3bc979038e6f7Doris Liu } 1818a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return animator; 18191c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu } 18201c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu 182170576b611fddc929abbfb466fa44c396a3a793dbDoris Liu /** 182270576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * Overloaded function to provide a simple way to start animation. Animation 182370576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * will use default duration, and a value of <code>null</code> for interpolator 182470576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * means linear interpolation will be used. 182570576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * 182670576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * @param width a set of values that the animation will animate between over time 182770576b611fddc929abbfb466fa44c396a3a793dbDoris Liu */ 1828a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu private Animator animateListToWidth(int... width) { 1829a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return animateListToWidth(0, DEFAULT_DURATION_MS, null, width); 18301c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu } 18311c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu 183270576b611fddc929abbfb466fa44c396a3a793dbDoris Liu /** 183370576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * Animate the mode list between the given set of visible width. 183470576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * 1835b00d64307ae77541f8576593a29214d649fb94e9Doris Liu * @param delay start delay between consecutive mode item. If delay < 0, the 1836b00d64307ae77541f8576593a29214d649fb94e9Doris Liu * leader in the animation will be the bottom item. 183770576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * @param duration duration for the animation of each mode item 183870576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * @param interpolator interpolator to be used by the animation 183970576b611fddc929abbfb466fa44c396a3a793dbDoris Liu * @param width a set of values that the animation will animate between over time 184070576b611fddc929abbfb466fa44c396a3a793dbDoris Liu */ 184169cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu private Animator animateListToWidth(int delay, int duration, 18421c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu TimeInterpolator interpolator, int... width) { 18431c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu if (mAnimatorSet != null && mAnimatorSet.isRunning()) { 18441c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu mAnimatorSet.end(); 18451c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu } 18461c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu 18471c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu ArrayList<Animator> animators = new ArrayList<Animator>(); 1848b00d64307ae77541f8576593a29214d649fb94e9Doris Liu boolean animateModeItemsInOrder = true; 1849b00d64307ae77541f8576593a29214d649fb94e9Doris Liu if (delay < 0) { 1850b00d64307ae77541f8576593a29214d649fb94e9Doris Liu animateModeItemsInOrder = false; 1851b00d64307ae77541f8576593a29214d649fb94e9Doris Liu delay *= -1; 1852b00d64307ae77541f8576593a29214d649fb94e9Doris Liu } 18531c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu for (int i = 0; i < mTotalModes; i++) { 1854b00d64307ae77541f8576593a29214d649fb94e9Doris Liu ObjectAnimator animator; 1855b00d64307ae77541f8576593a29214d649fb94e9Doris Liu if (animateModeItemsInOrder) { 1856b00d64307ae77541f8576593a29214d649fb94e9Doris Liu animator = ObjectAnimator.ofInt(mModeSelectorItems[i], 185770576b611fddc929abbfb466fa44c396a3a793dbDoris Liu "visibleWidth", width); 1858b00d64307ae77541f8576593a29214d649fb94e9Doris Liu } else { 1859b00d64307ae77541f8576593a29214d649fb94e9Doris Liu animator = ObjectAnimator.ofInt(mModeSelectorItems[mTotalModes - 1 -i], 1860b00d64307ae77541f8576593a29214d649fb94e9Doris Liu "visibleWidth", width); 1861b00d64307ae77541f8576593a29214d649fb94e9Doris Liu } 18621c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu animator.setDuration(duration); 18631c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu animators.add(animator); 18641c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu } 18651c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu 18661c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu mAnimatorSet = new AnimatorSet(); 18671c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu mAnimatorSet.playTogether(animators); 18681c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu mAnimatorSet.setInterpolator(interpolator); 18696c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu mAnimatorSet.start(); 187069cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu 187169cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu return mAnimatorSet; 18726c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu } 18731c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu 18746c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu /** 18756c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu * Animate the mode list to the given width at a constant velocity. 18766c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu * 18776c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu * @param velocity the velocity that animation will be at 18786c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu * @param width final width of the list 18796c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu */ 1880a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu private Animator animateListToWidthAtVelocity(float velocity, int width) { 18816c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu if (mAnimatorSet != null && mAnimatorSet.isRunning()) { 18826c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu mAnimatorSet.end(); 18836c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu } 18841c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu 18856c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu ArrayList<Animator> animators = new ArrayList<Animator>(); 18866c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu for (int i = 0; i < mTotalModes; i++) { 18876c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu ObjectAnimator animator = ObjectAnimator.ofInt(mModeSelectorItems[i], 18886c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu "visibleWidth", width); 18898c1a922df154182b53f00c38198db7da0b4feb20Sascha Haeberling int duration = (int) (width / velocity); 18906c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu animator.setDuration(duration); 18916c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu animators.add(animator); 18926c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu } 18931c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu 18946c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu mAnimatorSet = new AnimatorSet(); 18956c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu mAnimatorSet.playTogether(animators); 18966c5a5375524efe7e5160f92edcaad121c7fbdb07Doris Liu mAnimatorSet.setInterpolator(null); 18971c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu mAnimatorSet.start(); 1898a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu 1899a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu return mAnimatorSet; 19001c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu } 1901f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu 1902f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu /** 1903b9b7240d62dd2ad245f2c0e09fd1056a28687978Doris Liu * Called when the back key is pressed. 1904b9b7240d62dd2ad245f2c0e09fd1056a28687978Doris Liu * 1905b9b7240d62dd2ad245f2c0e09fd1056a28687978Doris Liu * @return Whether the UI responded to the key event. 1906b9b7240d62dd2ad245f2c0e09fd1056a28687978Doris Liu */ 1907b9b7240d62dd2ad245f2c0e09fd1056a28687978Doris Liu public boolean onBackPressed() { 190826e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger return mCurrentStateManager.getCurrentState().onBackPressed(); 1909b9b7240d62dd2ad245f2c0e09fd1056a28687978Doris Liu } 1910b9b7240d62dd2ad245f2c0e09fd1056a28687978Doris Liu 1911b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu public void startModeSelectionAnimation() { 191226e901ed46054fb6cc2cb4c09bef3a779a1cbf78Alan Newberger mCurrentStateManager.getCurrentState().startModeSelectionAnimation(); 1913b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu } 1914b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu 191569cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu public float getMaxMovementBasedOnPosition(int lastVisibleWidth, int maxWidth) { 191669cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu int timeElapsed = (int) (System.currentTimeMillis() - mLastScrollTime); 191769cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu if (timeElapsed > SCROLL_INTERVAL_MS) { 191869cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu timeElapsed = SCROLL_INTERVAL_MS; 191969cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu } 192069cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu float position; 192169cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu int slowZone = (int) (maxWidth * SLOW_ZONE_PERCENTAGE); 192269cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu if (lastVisibleWidth < (maxWidth - slowZone)) { 19230496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague position = VELOCITY_THRESHOLD * timeElapsed + lastVisibleWidth; 192469cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu } else { 192569cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu float percentageIntoSlowZone = (lastVisibleWidth - (maxWidth - slowZone)) / slowZone; 192669cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu float velocity = (1 - percentageIntoSlowZone) * VELOCITY_THRESHOLD; 19270496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague position = velocity * timeElapsed + lastVisibleWidth; 192869cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu } 192969cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu position = Math.min(maxWidth, position); 193069cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu return position; 193169cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu } 193269cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu 1933a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu private class PeepholeAnimationEffect extends AnimationEffects { 1934b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu 1935b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu private final static int UNSET = -1; 19367dae6bb5ec44da5d7b51a4b98c45821ee5e2860eSpike Sprague private final static int PEEP_HOLE_ANIMATION_DURATION_MS = 500; 1937213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu 1938213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu private final Paint mMaskPaint = new Paint(); 1939213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu private final RectF mBackgroundDrawArea = new RectF(); 1940b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu 1941b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu private int mPeepHoleCenterX = UNSET; 1942b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu private int mPeepHoleCenterY = UNSET; 1943b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu private float mRadius = 0f; 1944b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu private ValueAnimator mPeepHoleAnimator; 19453c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague private ValueAnimator mFadeOutAlphaAnimator; 19463c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague private ValueAnimator mRevealAlphaAnimator; 1947213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu private Bitmap mBackground; 1948213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu private Bitmap mBackgroundOverlay; 1949b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu 19500496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague private Paint mCirclePaint = new Paint(); 19510496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague private Paint mCoverPaint = new Paint(); 19520496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague 19530496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague private TouchCircleDrawable mCircleDrawable; 19540496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague 1955b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu public PeepholeAnimationEffect() { 1956b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu mMaskPaint.setAlpha(0); 1957b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu mMaskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); 19580496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague 19590496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague mCirclePaint.setColor(0); 19600496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague mCirclePaint.setAlpha(0); 19610496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague 19620496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague mCoverPaint.setColor(0); 19630496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague mCoverPaint.setAlpha(0); 19643c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague 19653c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague setupAnimators(); 19663c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague } 19673c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague 19683c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague private void setupAnimators() { 19693c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague mFadeOutAlphaAnimator = ValueAnimator.ofInt(0, 255); 19703c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague mFadeOutAlphaAnimator.setDuration(100); 19713c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague mFadeOutAlphaAnimator.setInterpolator(Gusterpolator.INSTANCE); 19723c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague mFadeOutAlphaAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 19733c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague @Override 19743c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague public void onAnimationUpdate(ValueAnimator animation) { 19753c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague mCoverPaint.setAlpha((Integer) animation.getAnimatedValue()); 19763c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague invalidate(); 19773c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague } 19783c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague }); 19793c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague mFadeOutAlphaAnimator.addListener(new AnimatorListenerAdapter() { 19803c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague @Override 19813c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague public void onAnimationStart(Animator animation) { 19823c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague // Sets a HW layer on the view for the animation. 19833c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague setLayerType(LAYER_TYPE_HARDWARE, null); 19843c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague } 19853c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague 19863c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague @Override 19873c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague public void onAnimationEnd(Animator animation) { 19883c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague // Sets the layer type back to NONE as a workaround for b/12594617. 19893c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague setLayerType(LAYER_TYPE_NONE, null); 19903c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague } 19913c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague }); 19923c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague 19933c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague ///////////////// 19943c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague 19953c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague mRevealAlphaAnimator = ValueAnimator.ofInt(255, 0); 19963c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague mRevealAlphaAnimator.setDuration(PEEP_HOLE_ANIMATION_DURATION_MS); 19973c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague mRevealAlphaAnimator.setInterpolator(Gusterpolator.INSTANCE); 19983c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague mRevealAlphaAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 19993c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague @Override 20003c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague public void onAnimationUpdate(ValueAnimator animation) { 20013c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague int alpha = (Integer) animation.getAnimatedValue(); 20023c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague mCirclePaint.setAlpha(alpha); 20033c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague mCoverPaint.setAlpha(alpha); 20043c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague } 20053c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague }); 20063c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague mRevealAlphaAnimator.addListener(new AnimatorListenerAdapter() { 20073c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague @Override 20083c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague public void onAnimationStart(Animator animation) { 20093c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague // Sets a HW layer on the view for the animation. 20103c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague setLayerType(LAYER_TYPE_HARDWARE, null); 20113c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague } 20123c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague 20133c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague @Override 20143c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague public void onAnimationEnd(Animator animation) { 20153c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague // Sets the layer type back to NONE as a workaround for b/12594617. 20163c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague setLayerType(LAYER_TYPE_NONE, null); 20173c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague } 20183c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague }); 20193c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague 20203c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague //////////////// 20213c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague 20223c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague int horizontalDistanceToFarEdge = Math.max(mPeepHoleCenterX, mWidth - mPeepHoleCenterX); 20233c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague int verticalDistanceToFarEdge = Math.max(mPeepHoleCenterY, mHeight - mPeepHoleCenterY); 20243c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague int endRadius = (int) (Math.sqrt(horizontalDistanceToFarEdge * horizontalDistanceToFarEdge 20253c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague + verticalDistanceToFarEdge * verticalDistanceToFarEdge)); 20263c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague int startRadius = getResources().getDimensionPixelSize( 20273c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague R.dimen.mode_selector_icon_block_width) / 2; 20283c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague 20293c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague mPeepHoleAnimator = ValueAnimator.ofFloat(startRadius, endRadius); 20303c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague mPeepHoleAnimator.setDuration(PEEP_HOLE_ANIMATION_DURATION_MS); 20313c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague mPeepHoleAnimator.setInterpolator(Gusterpolator.INSTANCE); 20323c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague mPeepHoleAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 20333c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague @Override 20343c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague public void onAnimationUpdate(ValueAnimator animation) { 20353c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague // Modify mask by enlarging the hole 20363c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague mRadius = (Float) mPeepHoleAnimator.getAnimatedValue(); 20373c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague invalidate(); 20383c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague } 20393c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague }); 20403c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague mPeepHoleAnimator.addListener(new AnimatorListenerAdapter() { 20413c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague @Override 20423c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague public void onAnimationStart(Animator animation) { 20433c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague // Sets a HW layer on the view for the animation. 20443c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague setLayerType(LAYER_TYPE_HARDWARE, null); 20453c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague } 20463c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague 20473c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague @Override 20483c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague public void onAnimationEnd(Animator animation) { 20493c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague // Sets the layer type back to NONE as a workaround for b/12594617. 20503c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague setLayerType(LAYER_TYPE_NONE, null); 20513c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague } 20523c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague }); 20533c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague 20543c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague //////////////// 20553c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague int size = getContext().getResources() 20563c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague .getDimensionPixelSize(R.dimen.mode_selector_icon_block_width); 20573c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague mCircleDrawable = new TouchCircleDrawable(getContext().getResources()); 20583c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague mCircleDrawable.setSize(size, size); 20593c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague mCircleDrawable.setUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 20603c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague @Override 20613c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague public void onAnimationUpdate(ValueAnimator animation) { 20623c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague invalidate(); 20633c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague } 20643c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague }); 2065b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu } 2066b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu 2067601921e746832bdef40503c606a95b4469f1bedbSascha Haeberling @Override 2068b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu public void setSize(int width, int height) { 2069b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu mWidth = width; 2070b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu mHeight = height; 2071b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu } 2072b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu 2073601921e746832bdef40503c606a95b4469f1bedbSascha Haeberling @Override 207469cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu public boolean onTouchEvent(MotionEvent event) { 207569cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu return true; 207669cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu } 207769cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu 20783c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague @Override 20793c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague public void drawForeground(Canvas canvas) { 20803c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague // Draw the circle in clear mode 20813c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague if (mPeepHoleAnimator != null) { 20823c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague // Draw a transparent circle using clear mode 20833c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague canvas.drawCircle(mPeepHoleCenterX, mPeepHoleCenterY, mRadius, mMaskPaint); 20843c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague canvas.drawCircle(mPeepHoleCenterX, mPeepHoleCenterY, mRadius, mCirclePaint); 20853c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague } 20863c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague } 20873c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague 2088b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu public void setAnimationStartingPosition(int x, int y) { 2089b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu mPeepHoleCenterX = x; 2090b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu mPeepHoleCenterY = y; 2091b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu } 2092b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu 20930496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague public void setModeSpecificColor(int color) { 20940496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague mCirclePaint.setColor(color & 0x00ffffff); 20950496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague } 20960496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague 2097213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu /** 2098213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu * Sets the bitmap to be drawn in the background and the drawArea to draw 20990496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague * the bitmap. 2100213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu * 2101213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu * @param background image to be drawn in the background 2102213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu * @param drawArea area to draw the background image 2103213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu */ 2104213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu public void setBackground(Bitmap background, RectF drawArea) { 2105213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu mBackground = background; 2106213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu mBackgroundDrawArea.set(drawArea); 2107213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu } 2108213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu 2109213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu /** 2110213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu * Sets the overlay image to be drawn on top of the background. 2111213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu */ 2112213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu public void setBackgroundOverlay(Bitmap overlay) { 2113213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu mBackgroundOverlay = overlay; 2114213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu } 2115213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu 2116213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu @Override 2117213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu public void drawBackground(Canvas canvas) { 2118213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu if (mBackground != null && mBackgroundOverlay != null) { 2119213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu canvas.drawBitmap(mBackground, null, mBackgroundDrawArea, null); 21200496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague canvas.drawPaint(mCoverPaint); 2121213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu canvas.drawBitmap(mBackgroundOverlay, 0, 0, null); 21220496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague 21230496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague if (mCircleDrawable != null) { 21240496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague mCircleDrawable.draw(canvas); 21250496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague } 21260496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague } 21270496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague } 21280496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague 21290496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague @Override 2130bee2022d8dcde61d2b0c6cf9b709d8e34cdcb739Doris Liu public boolean shouldDrawSuper() { 2131bee2022d8dcde61d2b0c6cf9b709d8e34cdcb739Doris Liu // No need to draw super when mBackgroundOverlay is being drawn, as 2132bee2022d8dcde61d2b0c6cf9b709d8e34cdcb739Doris Liu // background overlay already contains what's drawn in super. 2133bee2022d8dcde61d2b0c6cf9b709d8e34cdcb739Doris Liu return (mBackground == null || mBackgroundOverlay == null); 2134bee2022d8dcde61d2b0c6cf9b709d8e34cdcb739Doris Liu } 2135bee2022d8dcde61d2b0c6cf9b709d8e34cdcb739Doris Liu 21360496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague public void startFadeoutAnimation(Animator.AnimatorListener listener, 21370496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague final ModeSelectorItem selectedItem, 21380496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague int x, int y, final int modeId) { 21390496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague mCoverPaint.setColor(0); 21400496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague mCoverPaint.setAlpha(0); 21410496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague 21420496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague mCircleDrawable.setIconDrawable( 21430496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague selectedItem.getIcon().getIconDrawableClone(), 21440496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague selectedItem.getIcon().getIconDrawableSize()); 21450496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague mCircleDrawable.setCenter(new Point(x, y)); 21460496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague mCircleDrawable.setColor(selectedItem.getHighlightColor()); 21470496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague mCircleDrawable.setAnimatorListener(new AnimatorListenerAdapter() { 21480496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague @Override 21490496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague public void onAnimationEnd(Animator animation) { 21500496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague // Post mode selection runnable to the end of the message queue 21510496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague // so that current UI changes can finish before mode initialization 21520496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague // clogs up UI thread. 21530496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague post(new Runnable() { 21540496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague @Override 21550496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague public void run() { 21560496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague // Select the focused item. 21570496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague selectedItem.setSelected(true); 21580496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague onModeSelected(modeId); 21590496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague } 21600496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague }); 21610496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague } 21620496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague }); 21633c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague 21643c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague // add fade out animator to a set, so we can freely add 21653c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague // the listener without having to worry about listener dupes 21663c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague AnimatorSet s = new AnimatorSet(); 21673c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague s.play(mFadeOutAlphaAnimator); 21683c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague if (listener != null) { 21693c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague s.addListener(listener); 21703c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague } 21710496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague mCircleDrawable.animate(); 21723c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague s.start(); 21730496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague } 21740496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague 2175bee2022d8dcde61d2b0c6cf9b709d8e34cdcb739Doris Liu @Override 2176a8a24e0241ad3a3d3c8d8b77ac5cbd7138736bd5Doris Liu public void startAnimation(Animator.AnimatorListener listener) { 2177b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu if (mPeepHoleAnimator != null && mPeepHoleAnimator.isRunning()) { 2178b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu return; 2179b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu } 2180b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu if (mPeepHoleCenterY == UNSET || mPeepHoleCenterX == UNSET) { 2181b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu mPeepHoleCenterX = mWidth / 2; 2182b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu mPeepHoleCenterY = mHeight / 2; 2183b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu } 2184b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu 21850496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague mCirclePaint.setAlpha(255); 21860496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague mCoverPaint.setAlpha(255); 2187759122e8b3071b79fa2a388f00403af4e21be68cDoris Liu 21883c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague // add peephole and reveal animators to a set, so we can 21893c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague // freely add the listener without having to worry about 21903c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague // listener dupes 21913c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague AnimatorSet s = new AnimatorSet(); 21923c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague s.play(mPeepHoleAnimator).with(mRevealAlphaAnimator); 21933c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague if (listener != null) { 21943c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague s.addListener(listener); 21953c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague } 21963c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague s.start(); 2197b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu } 2198b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu 219969cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu @Override 220069cb84076c2f290ee2cd782ab668a661c9d5386eDoris Liu public void endAnimation() { 2201b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu } 2202213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu 2203fa50f7d71a77dc730746c33fd17a570d42453759Doris Liu @Override 2204fa50f7d71a77dc730746c33fd17a570d42453759Doris Liu public boolean cancelAnimation() { 2205fa50f7d71a77dc730746c33fd17a570d42453759Doris Liu if (mPeepHoleAnimator == null || !mPeepHoleAnimator.isRunning()) { 2206fa50f7d71a77dc730746c33fd17a570d42453759Doris Liu return false; 2207fa50f7d71a77dc730746c33fd17a570d42453759Doris Liu } else { 2208fa50f7d71a77dc730746c33fd17a570d42453759Doris Liu mPeepHoleAnimator.cancel(); 2209fa50f7d71a77dc730746c33fd17a570d42453759Doris Liu return true; 2210fa50f7d71a77dc730746c33fd17a570d42453759Doris Liu } 2211fa50f7d71a77dc730746c33fd17a570d42453759Doris Liu } 2212b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu } 22131c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu} 2214