150a531337e7d6d49b40a1c96636962507ccf6c61Daniel Sandler/*
250a531337e7d6d49b40a1c96636962507ccf6c61Daniel Sandler * Copyright (C) 2012 The Android Open Source Project
350a531337e7d6d49b40a1c96636962507ccf6c61Daniel Sandler *
450a531337e7d6d49b40a1c96636962507ccf6c61Daniel Sandler * Licensed under the Apache License, Version 2.0 (the "License");
550a531337e7d6d49b40a1c96636962507ccf6c61Daniel Sandler * you may not use this file except in compliance with the License.
650a531337e7d6d49b40a1c96636962507ccf6c61Daniel Sandler * You may obtain a copy of the License at
750a531337e7d6d49b40a1c96636962507ccf6c61Daniel Sandler *
850a531337e7d6d49b40a1c96636962507ccf6c61Daniel Sandler *      http://www.apache.org/licenses/LICENSE-2.0
950a531337e7d6d49b40a1c96636962507ccf6c61Daniel Sandler *
1050a531337e7d6d49b40a1c96636962507ccf6c61Daniel Sandler * Unless required by applicable law or agreed to in writing, software
1150a531337e7d6d49b40a1c96636962507ccf6c61Daniel Sandler * distributed under the License is distributed on an "AS IS" BASIS,
1250a531337e7d6d49b40a1c96636962507ccf6c61Daniel Sandler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1350a531337e7d6d49b40a1c96636962507ccf6c61Daniel Sandler * See the License for the specific language governing permissions and
1450a531337e7d6d49b40a1c96636962507ccf6c61Daniel Sandler * limitations under the License.
1550a531337e7d6d49b40a1c96636962507ccf6c61Daniel Sandler */
1650a531337e7d6d49b40a1c96636962507ccf6c61Daniel Sandler
1708d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandlerpackage com.android.systemui.statusbar.phone;
1808d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler
191d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggiimport android.animation.Animator;
201d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggiimport android.animation.AnimatorListenerAdapter;
210c1b75c17b79979e0f210b5bf03226d1091a4c21Daniel Sandlerimport android.animation.ObjectAnimator;
221d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggiimport android.animation.ValueAnimator;
2308d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandlerimport android.content.Context;
24b84a1074b34f64174d9451234fa7c684f8283b6cSelim Cinekimport android.content.res.Configuration;
2508d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandlerimport android.content.res.Resources;
2608d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandlerimport android.util.AttributeSet;
27cd686b5b6d4166b510df8e32138479a9559bc117John Spurlockimport android.util.Log;
28de750b4499763f0470c5291a518fad82052760ceJun Mukaiimport android.view.InputDevice;
2908d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandlerimport android.view.MotionEvent;
30b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinekimport android.view.ViewConfiguration;
310a27be899c7143df1d8b64ef842b7f6b7fcf0baaJorim Jaggiimport android.view.ViewTreeObserver;
329012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggiimport android.view.animation.Interpolator;
3308d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandlerimport android.widget.FrameLayout;
3408d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler
35b018399a3a2762e95126acbe14397eca15bad772Christoph Studerimport com.android.systemui.EventLogConstants;
36b018399a3a2762e95126acbe14397eca15bad772Christoph Studerimport com.android.systemui.EventLogTags;
37c0d7058b14c24cd07912f5629c26b39b7b4673d5Winsonimport com.android.systemui.Interpolators;
3808d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandlerimport com.android.systemui.R;
390e2ffbd48bbedf47deb7f6aed96bd07e2fc96f53Blazej Magnowskiimport com.android.systemui.classifier.FalsingManager;
40813552cc27cbeac366166cdda82fd813c8458bbfJohn Spurlockimport com.android.systemui.doze.DozeLog;
411d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggiimport com.android.systemui.statusbar.FlingAnimationUtils;
429012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggiimport com.android.systemui.statusbar.StatusBarState;
43b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinekimport com.android.systemui.statusbar.policy.HeadsUpManager;
4408d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler
45de84f0e77ea2bf713d15c290264059a413c2486aJohn Spurlockimport java.io.FileDescriptor;
46de84f0e77ea2bf713d15c290264059a413c2486aJohn Spurlockimport java.io.PrintWriter;
47de84f0e77ea2bf713d15c290264059a413c2486aJohn Spurlock
484c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinekpublic abstract class PanelView extends FrameLayout {
49198a0306e5b0ef6b02d61e299a4b4ab4c1c2cdc8Daniel Sandler    public static final boolean DEBUG = PanelBar.DEBUG;
5008d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    public static final String TAG = PanelView.class.getSimpleName();
51173f2d0fad8dc889beefff67be96ec865465d1e0Selim Cinek
529764218ff979f735aee2f1189e3547d5f3b02f83John Spurlock    private final void logf(String fmt, Object... args) {
53cd686b5b6d4166b510df8e32138479a9559bc117John Spurlock        Log.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args));
5408d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    }
5508d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler
569012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi    protected PhoneStatusBar mStatusBar;
57684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek    protected HeadsUpManager mHeadsUpManager;
58684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek
590c1b75c17b79979e0f210b5bf03226d1091a4c21Daniel Sandler    private float mPeekHeight;
609012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi    private float mHintDistance;
61b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek    private float mInitialOffsetOnTouch;
6279d79c455beecf7a70460575ab21d9bf49767e2cSelim Cinek    private boolean mCollapsedAndHeadsUpOnDown;
6308d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    private float mExpandedFraction = 0;
641408eb5a58d669933c701e347fd3498ceab70f3cSelim Cinek    protected float mExpandedHeight = 0;
6531094df5c6e3cb3a4a4faacb091e35eea1f6a5deSelim Cinek    private boolean mPanelClosedOnDown;
6631094df5c6e3cb3a4a4faacb091e35eea1f6a5deSelim Cinek    private boolean mHasLayoutedSinceDown;
6731094df5c6e3cb3a4a4faacb091e35eea1f6a5deSelim Cinek    private float mUpdateFlingVelocity;
6831094df5c6e3cb3a4a4faacb091e35eea1f6a5deSelim Cinek    private boolean mUpdateFlingOnLayout;
69b7a3303f807ee01bbe405f4153a2285e55c0b6e3Jorim Jaggi    private boolean mPeekTouching;
700c1b75c17b79979e0f210b5bf03226d1091a4c21Daniel Sandler    private boolean mJustPeeked;
715050813f15a1d39d49cb8eca5a3aa6df43c4d450Daniel Sandler    private boolean mClosing;
728dd95e03f8555c278217bac7e4faef865b1850a7Jorim Jaggi    protected boolean mTracking;
739012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi    private boolean mTouchSlopExceeded;
7448fa91a818e321208e90d6af234c1d4bed5a945dJohn Spurlock    private int mTrackingPointer;
75d7daab7b9e33cd56f2692b9ebea87ef21290c1eaJorim Jaggi    protected int mTouchSlop;
76b3f0a2ff000ca2481f95ee8f7d7b487e33b87ecaJorim Jaggi    protected boolean mHintAnimationRunning;
7747c85a3525dcd0bbd3168632830e8ab491d18462Jorim Jaggi    private boolean mOverExpandedBeforeFling;
7819c8c708f16546fc75ae12659aa190f5e3dfbb52Selim Cinek    private boolean mTouchAboveFalsingThreshold;
7919c8c708f16546fc75ae12659aa190f5e3dfbb52Selim Cinek    private int mUnlockFalsingThreshold;
80ab1dc954b2b97b59f868c96921f2daabc3336034Selim Cinek    private boolean mTouchStartedInEmptyArea;
81547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek    private boolean mMotionAborted;
829db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek    private boolean mUpwardsWhenTresholdReached;
83173f2d0fad8dc889beefff67be96ec865465d1e0Selim Cinek    private boolean mAnimatingOnDown;
8408d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler
851d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi    private ValueAnimator mHeightAnimator;
860c1b75c17b79979e0f210b5bf03226d1091a4c21Daniel Sandler    private ObjectAnimator mPeekAnimator;
87b7b61ddaef4f2a2ebc79e832fb909fd4dcac8ba5Jorim Jaggi    private VelocityTrackerInterface mVelocityTracker;
881d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi    private FlingAnimationUtils mFlingAnimationUtils;
890e2ffbd48bbedf47deb7f6aed96bd07e2fc96f53Blazej Magnowski    private FalsingManager mFalsingManager;
9008d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler
910a27be899c7143df1d8b64ef842b7f6b7fcf0baaJorim Jaggi    /**
920a27be899c7143df1d8b64ef842b7f6b7fcf0baaJorim Jaggi     * Whether an instant expand request is currently pending and we are just waiting for layout.
930a27be899c7143df1d8b64ef842b7f6b7fcf0baaJorim Jaggi     */
940a27be899c7143df1d8b64ef842b7f6b7fcf0baaJorim Jaggi    private boolean mInstantExpanding;
956626f54e658e3da44fab8a5cd6d9d3d4852e2cd1Jorim Jaggi    private boolean mAnimateAfterExpanding;
960a27be899c7143df1d8b64ef842b7f6b7fcf0baaJorim Jaggi
9708d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    PanelBar mBar;
9808d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler
995050813f15a1d39d49cb8eca5a3aa6df43c4d450Daniel Sandler    private String mViewName;
100d7daab7b9e33cd56f2692b9ebea87ef21290c1eaJorim Jaggi    private float mInitialTouchY;
101d7daab7b9e33cd56f2692b9ebea87ef21290c1eaJorim Jaggi    private float mInitialTouchX;
102d41083ad06f63e335a1d1a1d5050ed3646f4fd35Jorim Jaggi    private boolean mTouchDisabled;
10308d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler
1049012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi    private Interpolator mBounceInterpolator;
105f99d0007646781b99a63bc0d2103a45f0f72e724Selim Cinek    protected KeyguardBottomAreaView mKeyguardBottomArea;
1069012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi
107b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi    private boolean mPeekPending;
108b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi    private boolean mCollapseAfterPeek;
109f3b3bee12994a24b60bd447dede9e8791151fcc9Jorim Jaggi
110f3b3bee12994a24b60bd447dede9e8791151fcc9Jorim Jaggi    /**
111f3b3bee12994a24b60bd447dede9e8791151fcc9Jorim Jaggi     * Speed-up factor to be used when {@link #mFlingCollapseRunnable} runs the next time.
112f3b3bee12994a24b60bd447dede9e8791151fcc9Jorim Jaggi     */
113f3b3bee12994a24b60bd447dede9e8791151fcc9Jorim Jaggi    private float mNextCollapseSpeedUpFactor = 1.0f;
114f3b3bee12994a24b60bd447dede9e8791151fcc9Jorim Jaggi
1151d071ce9b1810fbcf231fd17c4cb5621e68ff419Jorim Jaggi    protected boolean mExpanding;
116b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi    private boolean mGestureWaitForTouchSlop;
1179db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek    private boolean mIgnoreXTouchSlop;
118b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi    private Runnable mPeekRunnable = new Runnable() {
119b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi        @Override
120b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi        public void run() {
121b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi            mPeekPending = false;
122b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi            runPeekAnimation();
123b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi        }
124b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi    };
125b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi
1261685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    protected void onExpandingFinished() {
1272fbad7b6a724cf0a5b98b66fe639d58f5ab10af3Jorim Jaggi        mBar.onExpandingFinished();
1281685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    }
1291685e634fb0b14033bd436af8d7174436699ffecSelim Cinek
1301685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    protected void onExpandingStarted() {
1311685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    }
1321685e634fb0b14033bd436af8d7174436699ffecSelim Cinek
133b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi    private void notifyExpandingStarted() {
134b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi        if (!mExpanding) {
135b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi            mExpanding = true;
136b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi            onExpandingStarted();
137b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi        }
138b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi    }
139b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi
1401d071ce9b1810fbcf231fd17c4cb5621e68ff419Jorim Jaggi    protected final void notifyExpandingFinished() {
141b0e4f9e97e272783f08b2245219239aaa667073dSelim Cinek        endClosing();
142b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi        if (mExpanding) {
143b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi            mExpanding = false;
144b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi            onExpandingFinished();
145b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi        }
146b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi    }
147b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi
148b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi    private void schedulePeek() {
149b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi        mPeekPending = true;
150b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi        long timeout = ViewConfiguration.getTapTimeout();
151b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi        postOnAnimationDelayed(mPeekRunnable, timeout);
152b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi        notifyBarPanelExpansionChanged();
153b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi    }
154b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi
1550c1b75c17b79979e0f210b5bf03226d1091a4c21Daniel Sandler    private void runPeekAnimation() {
1562580a976ec93a01ed00fae51364ad872bc591d95Jorim Jaggi        mPeekHeight = getPeekHeight();
1579764218ff979f735aee2f1189e3547d5f3b02f83John Spurlock        if (DEBUG) logf("peek to height=%.1f", mPeekHeight);
1581d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi        if (mHeightAnimator != null) {
1590c1b75c17b79979e0f210b5bf03226d1091a4c21Daniel Sandler            return;
1600c1b75c17b79979e0f210b5bf03226d1091a4c21Daniel Sandler        }
161b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi        mPeekAnimator = ObjectAnimator.ofFloat(this, "expandedHeight", mPeekHeight)
162b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi                .setDuration(250);
163c18010f6720f606003cde3cd376ddacaca30f6e5Selim Cinek        mPeekAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
164b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi        mPeekAnimator.addListener(new AnimatorListenerAdapter() {
165b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi            private boolean mCancelled;
166b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi
167b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi            @Override
168b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi            public void onAnimationCancel(Animator animation) {
169b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi                mCancelled = true;
170b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi            }
171b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi
172b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi            @Override
173b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi            public void onAnimationEnd(Animator animation) {
174b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi                mPeekAnimator = null;
175b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi                if (mCollapseAfterPeek && !mCancelled) {
176a0f5c76ffdc728c9f291addd3f4a7bc2d1817733Selim Cinek                    postOnAnimation(mPostCollapseRunnable);
177b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi                }
178b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi                mCollapseAfterPeek = false;
179b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi            }
180b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi        });
181b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi        notifyExpandingStarted();
1820c1b75c17b79979e0f210b5bf03226d1091a4c21Daniel Sandler        mPeekAnimator.start();
183b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi        mJustPeeked = true;
1840c1b75c17b79979e0f210b5bf03226d1091a4c21Daniel Sandler    }
1850c1b75c17b79979e0f210b5bf03226d1091a4c21Daniel Sandler
18608d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    public PanelView(Context context, AttributeSet attrs) {
18708d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        super(context, attrs);
1881d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi        mFlingAnimationUtils = new FlingAnimationUtils(context, 0.6f);
1899012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi        mBounceInterpolator = new BounceInterpolator();
1900e2ffbd48bbedf47deb7f6aed96bd07e2fc96f53Blazej Magnowski        mFalsingManager = FalsingManager.getInstance(context);
19108d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    }
19208d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler
193069cd03740312159faf24a01910ff1daeae93131Jorim Jaggi    protected void loadDimens() {
19408d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        final Resources res = getContext().getResources();
195b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek        final ViewConfiguration configuration = ViewConfiguration.get(getContext());
196b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek        mTouchSlop = configuration.getScaledTouchSlop();
1979012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi        mHintDistance = res.getDimension(R.dimen.hint_move_distance);
19819c8c708f16546fc75ae12659aa190f5e3dfbb52Selim Cinek        mUnlockFalsingThreshold = res.getDimensionPixelSize(R.dimen.unlock_falsing_threshold);
19908d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    }
20008d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler
20108d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    private void trackMovement(MotionEvent event) {
20208d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        // Add movement to velocity tracker using raw screen X and Y coordinates instead
20308d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        // of window coordinates because the window frame may be moving at the same time.
20408d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        float deltaX = event.getRawX() - event.getX();
20508d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        float deltaY = event.getRawY() - event.getY();
20608d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        event.offsetLocation(deltaX, deltaY);
207b17a726f2fb1066060b5646d35233d26222e8721Daniel Sandler        if (mVelocityTracker != null) mVelocityTracker.addMovement(event);
20808d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        event.offsetLocation(-deltaX, -deltaY);
20908d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    }
21008d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler
211d41083ad06f63e335a1d1a1d5050ed3646f4fd35Jorim Jaggi    public void setTouchDisabled(boolean disabled) {
212d41083ad06f63e335a1d1a1d5050ed3646f4fd35Jorim Jaggi        mTouchDisabled = disabled;
2133127daf036337e047746f4b6bca56cc5ae18259cSelim Cinek        if (mTouchDisabled && mTracking) {
2143127daf036337e047746f4b6bca56cc5ae18259cSelim Cinek            onTrackingStopped(true /* expanded */);
2153127daf036337e047746f4b6bca56cc5ae18259cSelim Cinek        }
216d41083ad06f63e335a1d1a1d5050ed3646f4fd35Jorim Jaggi    }
217d41083ad06f63e335a1d1a1d5050ed3646f4fd35Jorim Jaggi
218bf526d14f3252b8a5c123291e4cd8b1c51346560Daniel Sandler    @Override
219bf526d14f3252b8a5c123291e4cd8b1c51346560Daniel Sandler    public boolean onTouchEvent(MotionEvent event) {
220547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek        if (mInstantExpanding || mTouchDisabled
221547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek                || (mMotionAborted && event.getActionMasked() != MotionEvent.ACTION_DOWN)) {
2220a27be899c7143df1d8b64ef842b7f6b7fcf0baaJorim Jaggi            return false;
2230a27be899c7143df1d8b64ef842b7f6b7fcf0baaJorim Jaggi        }
224b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek
225cf9933cf39e0f924dc25ba918617ed66572fd9e9Jun Mukai        // On expanding, single mouse click expands the panel instead of dragging.
226c99243aff8f039734fcc9af93f6854c3838796cfJun Mukai        if (isFullyCollapsed() && event.isFromSource(InputDevice.SOURCE_MOUSE)) {
227cf9933cf39e0f924dc25ba918617ed66572fd9e9Jun Mukai            if (event.getAction() == MotionEvent.ACTION_UP) {
228cf9933cf39e0f924dc25ba918617ed66572fd9e9Jun Mukai                expand(true);
229cf9933cf39e0f924dc25ba918617ed66572fd9e9Jun Mukai            }
230cf9933cf39e0f924dc25ba918617ed66572fd9e9Jun Mukai            return true;
231cf9933cf39e0f924dc25ba918617ed66572fd9e9Jun Mukai        }
232cf9933cf39e0f924dc25ba918617ed66572fd9e9Jun Mukai
233b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek        /*
234b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek         * We capture touch events here and update the expand height here in case according to
235b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek         * the users fingers. This also handles multi-touch.
236b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek         *
2375d53df4aede972cfa23d9f2a3f484fb5ee3087dcChris Wren         * If the user just clicks shortly, we show a quick peek of the shade.
238b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek         *
239b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek         * Flinging is also enabled in order to open or close the shade.
240b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek         */
241b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek
242b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek        int pointerIndex = event.findPointerIndex(mTrackingPointer);
243b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek        if (pointerIndex < 0) {
244b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek            pointerIndex = 0;
245b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek            mTrackingPointer = event.getPointerId(pointerIndex);
246b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek        }
247a6310293c5a861cdb54f2c894e90a8d9da87f8d7Jorim Jaggi        final float x = event.getX(pointerIndex);
248547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek        final float y = event.getY(pointerIndex);
249b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek
250b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi        if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
251684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek            mGestureWaitForTouchSlop = isFullyCollapsed() || hasConflictingGestures();
252684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek            mIgnoreXTouchSlop = isFullyCollapsed() || shouldGestureIgnoreXTouchSlop(x, y);
253b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi        }
2544c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek
255b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek        switch (event.getActionMasked()) {
256b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek            case MotionEvent.ACTION_DOWN:
257b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek                startExpandMotion(x, y, false /* startTracking */, mExpandedHeight);
2583857ac4b3f24e13bac255d162249dd8b2ccb63acJorim Jaggi                mJustPeeked = false;
259684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek                mPanelClosedOnDown = isFullyCollapsed();
26031094df5c6e3cb3a4a4faacb091e35eea1f6a5deSelim Cinek                mHasLayoutedSinceDown = false;
26131094df5c6e3cb3a4a4faacb091e35eea1f6a5deSelim Cinek                mUpdateFlingOnLayout = false;
262547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek                mMotionAborted = false;
263b7a3303f807ee01bbe405f4153a2285e55c0b6e3Jorim Jaggi                mPeekTouching = mPanelClosedOnDown;
26419c8c708f16546fc75ae12659aa190f5e3dfbb52Selim Cinek                mTouchAboveFalsingThreshold = false;
26579d79c455beecf7a70460575ab21d9bf49767e2cSelim Cinek                mCollapsedAndHeadsUpOnDown = isFullyCollapsed()
26679d79c455beecf7a70460575ab21d9bf49767e2cSelim Cinek                        && mHeadsUpManager.hasPinnedHeadsUp();
267b7b61ddaef4f2a2ebc79e832fb909fd4dcac8ba5Jorim Jaggi                if (mVelocityTracker == null) {
268b7b61ddaef4f2a2ebc79e832fb909fd4dcac8ba5Jorim Jaggi                    initVelocityTracker();
269b7b61ddaef4f2a2ebc79e832fb909fd4dcac8ba5Jorim Jaggi                }
270b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek                trackMovement(event);
2719db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek                if (!mGestureWaitForTouchSlop || (mHeightAnimator != null && !mHintAnimationRunning) ||
272b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi                        mPeekPending || mPeekAnimator != null) {
273dbbcfbe8aea1944fc0b0ecbf531034bcd5b5770aSelim Cinek                    cancelHeightAnimator();
274b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi                    cancelPeek();
275b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi                    mTouchSlopExceeded = (mHeightAnimator != null && !mHintAnimationRunning)
276b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi                            || mPeekPending || mPeekAnimator != null;
2774c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek                    onTrackingStarted();
2781d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi                }
27979d79c455beecf7a70460575ab21d9bf49767e2cSelim Cinek                if (isFullyCollapsed() && !mHeadsUpManager.hasPinnedHeadsUp()) {
280b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi                    schedulePeek();
281b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek                }
282b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek                break;
283b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek
284b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek            case MotionEvent.ACTION_POINTER_UP:
285b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek                final int upPointer = event.getPointerId(event.getActionIndex());
286b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek                if (mTrackingPointer == upPointer) {
287b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek                    // gesture is ongoing, find a new pointer to track
288b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek                    final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
289b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek                    final float newY = event.getY(newIndex);
290a6310293c5a861cdb54f2c894e90a8d9da87f8d7Jorim Jaggi                    final float newX = event.getX(newIndex);
291b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek                    mTrackingPointer = event.getPointerId(newIndex);
292b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek                    startExpandMotion(newX, newY, true /* startTracking */, mExpandedHeight);
293b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek                }
294b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek                break;
295547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek            case MotionEvent.ACTION_POINTER_DOWN:
296547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek                if (mStatusBar.getBarState() == StatusBarState.KEYGUARD) {
297547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek                    mMotionAborted = true;
298547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek                    endMotionEvent(event, x, y, true /* forceCancel */);
299547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek                    return false;
300547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek                }
301547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek                break;
302b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek            case MotionEvent.ACTION_MOVE:
3034c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek                float h = y - mInitialTouchY;
304b7240136b748e548069c7fe2bd77a7ed4148728eJorim Jaggi
305b7240136b748e548069c7fe2bd77a7ed4148728eJorim Jaggi                // If the panel was collapsed when touching, we only need to check for the
306b7240136b748e548069c7fe2bd77a7ed4148728eJorim Jaggi                // y-component of the gesture, as we have no conflicting horizontal gesture.
307b7240136b748e548069c7fe2bd77a7ed4148728eJorim Jaggi                if (Math.abs(h) > mTouchSlop
308b7240136b748e548069c7fe2bd77a7ed4148728eJorim Jaggi                        && (Math.abs(h) > Math.abs(x - mInitialTouchX)
3099db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek                                || mIgnoreXTouchSlop)) {
3109012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi                    mTouchSlopExceeded = true;
31179d79c455beecf7a70460575ab21d9bf49767e2cSelim Cinek                    if (mGestureWaitForTouchSlop && !mTracking && !mCollapsedAndHeadsUpOnDown) {
3120b1528aac46007f94f0e073143708240b0c7c144Jorim Jaggi                        if (!mJustPeeked && mInitialOffsetOnTouch != 0f) {
313b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek                            startExpandMotion(x, y, false /* startTracking */, mExpandedHeight);
314b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi                            h = 0;
315b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi                        }
316dbbcfbe8aea1944fc0b0ecbf531034bcd5b5770aSelim Cinek                        cancelHeightAnimator();
317b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi                        removeCallbacks(mPeekRunnable);
318b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi                        mPeekPending = false;
3199012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi                        onTrackingStarted();
3204c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek                    }
3214c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek                }
32293439da0ed9213bc54291b3fce4e04dd3a7f9f3aJorim Jaggi                final float newHeight = Math.max(0, h + mInitialOffsetOnTouch);
3234c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek                if (newHeight > mPeekHeight) {
324b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi                    if (mPeekAnimator != null) {
325b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek                        mPeekAnimator.cancel();
326b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek                    }
327b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek                    mJustPeeked = false;
328b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek                }
32929ed3c92ef8a28975606f6213477ce5ee2c99ba9Selim Cinek                if (-h >= getFalsingThreshold()) {
33019c8c708f16546fc75ae12659aa190f5e3dfbb52Selim Cinek                    mTouchAboveFalsingThreshold = true;
3319db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek                    mUpwardsWhenTresholdReached = isDirectionUpwards(x, y);
33219c8c708f16546fc75ae12659aa190f5e3dfbb52Selim Cinek                }
3339db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek                if (!mJustPeeked && (!mGestureWaitForTouchSlop || mTracking) && !isTrackingBlocked()) {
334cc693247dceef098490a4b01f2c0793ba5f948a4Jorim Jaggi                    setExpandedHeightInternal(newHeight);
335b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek                }
336b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek
337b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek                trackMovement(event);
338b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek                break;
339b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek
340b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek            case MotionEvent.ACTION_UP:
341b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek            case MotionEvent.ACTION_CANCEL:
342b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek                trackMovement(event);
343547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek                endMotionEvent(event, x, y, false /* forceCancel */);
344547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek                break;
345547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek        }
3469db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek        return !mGestureWaitForTouchSlop || mTracking;
3479db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek    }
3489db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek
3499db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek    /**
3509db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek     * @return whether the swiping direction is upwards and above a 45 degree angle compared to the
3519db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek     * horizontal direction
3529db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek     */
3539db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek    private boolean isDirectionUpwards(float x, float y) {
3549db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek        float xDiff = x - mInitialTouchX;
3559db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek        float yDiff = y - mInitialTouchY;
3569db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek        if (yDiff >= 0) {
3579db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek            return false;
3589db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek        }
3599db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek        return Math.abs(yDiff) >= Math.abs(xDiff);
360547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek    }
361547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek
362b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek    protected void startExpandMotion(float newX, float newY, boolean startTracking,
363b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek            float expandedHeight) {
364b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek        mInitialOffsetOnTouch = expandedHeight;
365b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek        mInitialTouchY = newY;
366b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek        mInitialTouchX = newX;
367b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek        if (startTracking) {
368b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek            mTouchSlopExceeded = true;
369def35a86530200958384191d43d321dbcda16e2aSelim Cinek            setExpandedHeight(mInitialOffsetOnTouch);
370b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek            onTrackingStarted();
371b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek        }
372b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek    }
373b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek
374547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek    private void endMotionEvent(MotionEvent event, float x, float y, boolean forceCancel) {
375547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek        mTrackingPointer = -1;
376547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek        if ((mTracking && mTouchSlopExceeded)
377547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek                || Math.abs(x - mInitialTouchX) > mTouchSlop
378547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek                || Math.abs(y - mInitialTouchY) > mTouchSlop
379547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek                || event.getActionMasked() == MotionEvent.ACTION_CANCEL
380547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek                || forceCancel) {
381547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek            float vel = 0f;
382547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek            float vectorVel = 0f;
383547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek            if (mVelocityTracker != null) {
384547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek                mVelocityTracker.computeCurrentVelocity(1000);
385547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek                vel = mVelocityTracker.getYVelocity();
386547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek                vectorVel = (float) Math.hypot(
387547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek                        mVelocityTracker.getXVelocity(), mVelocityTracker.getYVelocity());
388547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek            }
3899db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek            boolean expand = flingExpands(vel, vectorVel, x, y)
390547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek                    || event.getActionMasked() == MotionEvent.ACTION_CANCEL
391547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek                    || forceCancel;
392547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek            DozeLog.traceFling(expand, mTouchAboveFalsingThreshold,
393547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek                    mStatusBar.isFalsingThresholdNeeded(),
39450ff3afb01f2ac4a93dba418a71d54ad8adeba9dJorim Jaggi                    mStatusBar.isWakeUpComingFromTouch());
395b018399a3a2762e95126acbe14397eca15bad772Christoph Studer                    // Log collapse gesture if on lock screen.
396b018399a3a2762e95126acbe14397eca15bad772Christoph Studer                    if (!expand && mStatusBar.getBarState() == StatusBarState.KEYGUARD) {
397b018399a3a2762e95126acbe14397eca15bad772Christoph Studer                        float displayDensity = mStatusBar.getDisplayDensity();
398b018399a3a2762e95126acbe14397eca15bad772Christoph Studer                        int heightDp = (int) Math.abs((y - mInitialTouchY) / displayDensity);
399b018399a3a2762e95126acbe14397eca15bad772Christoph Studer                        int velocityDp = (int) Math.abs(vel / displayDensity);
400b018399a3a2762e95126acbe14397eca15bad772Christoph Studer                        EventLogTags.writeSysuiLockscreenGesture(
401b018399a3a2762e95126acbe14397eca15bad772Christoph Studer                                EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_SWIPE_UP_UNLOCK,
402b018399a3a2762e95126acbe14397eca15bad772Christoph Studer                                heightDp, velocityDp);
403b018399a3a2762e95126acbe14397eca15bad772Christoph Studer                    }
4049db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek            fling(vel, expand, isFalseTouch(x, y));
405eb8f11a8657a1509d6c00b3c6f34547f803bbe67Jorim Jaggi            onTrackingStopped(expand);
406547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek            mUpdateFlingOnLayout = expand && mPanelClosedOnDown && !mHasLayoutedSinceDown;
407547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek            if (mUpdateFlingOnLayout) {
408547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek                mUpdateFlingVelocity = vel;
409547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek            }
410547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek        } else {
411547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek            boolean expands = onEmptySpaceClick(mInitialTouchX);
412547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek            onTrackingStopped(expands);
413547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek        }
414dc96d6310c6e13077a563b80f190550d87e95ff9Jorim Jaggi
415547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek        if (mVelocityTracker != null) {
416547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek            mVelocityTracker.recycle();
417547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek            mVelocityTracker = null;
418b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek        }
419547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek        mPeekTouching = false;
420b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek    }
421b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek
42229ed3c92ef8a28975606f6213477ce5ee2c99ba9Selim Cinek    private int getFalsingThreshold() {
42350ff3afb01f2ac4a93dba418a71d54ad8adeba9dJorim Jaggi        float factor = mStatusBar.isWakeUpComingFromTouch() ? 1.5f : 1.0f;
42429ed3c92ef8a28975606f6213477ce5ee2c99ba9Selim Cinek        return (int) (mUnlockFalsingThreshold * factor);
42529ed3c92ef8a28975606f6213477ce5ee2c99ba9Selim Cinek    }
42629ed3c92ef8a28975606f6213477ce5ee2c99ba9Selim Cinek
4274c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek    protected abstract boolean hasConflictingGestures();
4284c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek
4299db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek    protected abstract boolean shouldGestureIgnoreXTouchSlop(float x, float y);
4309db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek
4312fbad7b6a724cf0a5b98b66fe639d58f5ab10af3Jorim Jaggi    protected void onTrackingStopped(boolean expand) {
4324c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek        mTracking = false;
4339f96711e1adf4a28f961c440da1626ad40c03bc8Xiaohui Chen        mBar.onTrackingStopped(expand);
434eb8f11a8657a1509d6c00b3c6f34547f803bbe67Jorim Jaggi        notifyBarPanelExpansionChanged();
4351685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    }
4361685e634fb0b14033bd436af8d7174436699ffecSelim Cinek
4371685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    protected void onTrackingStarted() {
438dbbcfbe8aea1944fc0b0ecbf531034bcd5b5770aSelim Cinek        endClosing();
4394c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek        mTracking = true;
440b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi        mCollapseAfterPeek = false;
4419f96711e1adf4a28f961c440da1626ad40c03bc8Xiaohui Chen        mBar.onTrackingStarted();
442b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi        notifyExpandingStarted();
443eb8f11a8657a1509d6c00b3c6f34547f803bbe67Jorim Jaggi        notifyBarPanelExpansionChanged();
4441685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    }
4451685e634fb0b14033bd436af8d7174436699ffecSelim Cinek
446b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek    @Override
447b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek    public boolean onInterceptTouchEvent(MotionEvent event) {
448547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek        if (mInstantExpanding
449547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek                || (mMotionAborted && event.getActionMasked() != MotionEvent.ACTION_DOWN)) {
4500a27be899c7143df1d8b64ef842b7f6b7fcf0baaJorim Jaggi            return false;
4510a27be899c7143df1d8b64ef842b7f6b7fcf0baaJorim Jaggi        }
452b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek
453b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek        /*
4545d53df4aede972cfa23d9f2a3f484fb5ee3087dcChris Wren         * If the user drags anywhere inside the panel we intercept it if the movement is
455b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek         * upwards. This allows closing the shade from anywhere inside the panel.
456b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek         *
457b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek         * We only do this if the current content is scrolled to the bottom,
458b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek         * i.e isScrolledToBottom() is true and therefore there is no conflicting scrolling gesture
459b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek         * possible.
460b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek         */
461b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek        int pointerIndex = event.findPointerIndex(mTrackingPointer);
462b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek        if (pointerIndex < 0) {
463b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek            pointerIndex = 0;
464b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek            mTrackingPointer = event.getPointerId(pointerIndex);
465b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek        }
466a6310293c5a861cdb54f2c894e90a8d9da87f8d7Jorim Jaggi        final float x = event.getX(pointerIndex);
467b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek        final float y = event.getY(pointerIndex);
468b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek        boolean scrolledToBottom = isScrolledToBottom();
469b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek
470b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek        switch (event.getActionMasked()) {
471b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek            case MotionEvent.ACTION_DOWN:
472b690f0d5023fcf144f2701058d5a6f88d66cc97aJorim Jaggi                mStatusBar.userActivity();
473173f2d0fad8dc889beefff67be96ec865465d1e0Selim Cinek                mAnimatingOnDown = mHeightAnimator != null;
474173f2d0fad8dc889beefff67be96ec865465d1e0Selim Cinek                if (mAnimatingOnDown && mClosing && !mHintAnimationRunning || mPeekPending || mPeekAnimator != null) {
475dbbcfbe8aea1944fc0b0ecbf531034bcd5b5770aSelim Cinek                    cancelHeightAnimator();
476b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi                    cancelPeek();
477b3f0a2ff000ca2481f95ee8f7d7b487e33b87ecaJorim Jaggi                    mTouchSlopExceeded = true;
478172e914178181cf1c5999722fc0817e8ac2097f1Selim Cinek                    return true;
479172e914178181cf1c5999722fc0817e8ac2097f1Selim Cinek                }
480b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek                mInitialTouchY = y;
481a6310293c5a861cdb54f2c894e90a8d9da87f8d7Jorim Jaggi                mInitialTouchX = x;
482ab1dc954b2b97b59f868c96921f2daabc3336034Selim Cinek                mTouchStartedInEmptyArea = !isInContentBounds(x, y);
4839012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi                mTouchSlopExceeded = false;
4843857ac4b3f24e13bac255d162249dd8b2ccb63acJorim Jaggi                mJustPeeked = false;
485547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek                mMotionAborted = false;
486684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek                mPanelClosedOnDown = isFullyCollapsed();
48779d79c455beecf7a70460575ab21d9bf49767e2cSelim Cinek                mCollapsedAndHeadsUpOnDown = false;
48831094df5c6e3cb3a4a4faacb091e35eea1f6a5deSelim Cinek                mHasLayoutedSinceDown = false;
48931094df5c6e3cb3a4a4faacb091e35eea1f6a5deSelim Cinek                mUpdateFlingOnLayout = false;
49019c8c708f16546fc75ae12659aa190f5e3dfbb52Selim Cinek                mTouchAboveFalsingThreshold = false;
491b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek                initVelocityTracker();
492b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek                trackMovement(event);
493b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek                break;
494b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek            case MotionEvent.ACTION_POINTER_UP:
495b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek                final int upPointer = event.getPointerId(event.getActionIndex());
496b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek                if (mTrackingPointer == upPointer) {
497b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek                    // gesture is ongoing, find a new pointer to track
498b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek                    final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
499b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek                    mTrackingPointer = event.getPointerId(newIndex);
500a6310293c5a861cdb54f2c894e90a8d9da87f8d7Jorim Jaggi                    mInitialTouchX = event.getX(newIndex);
501a6310293c5a861cdb54f2c894e90a8d9da87f8d7Jorim Jaggi                    mInitialTouchY = event.getY(newIndex);
502b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek                }
503b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek                break;
504547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek            case MotionEvent.ACTION_POINTER_DOWN:
505547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek                if (mStatusBar.getBarState() == StatusBarState.KEYGUARD) {
506547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek                    mMotionAborted = true;
507547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek                    if (mVelocityTracker != null) {
508547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek                        mVelocityTracker.recycle();
509547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek                        mVelocityTracker = null;
510547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek                    }
511547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek                }
512547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek                break;
513b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek            case MotionEvent.ACTION_MOVE:
514b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek                final float h = y - mInitialTouchY;
515b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek                trackMovement(event);
516173f2d0fad8dc889beefff67be96ec865465d1e0Selim Cinek                if (scrolledToBottom || mTouchStartedInEmptyArea || mAnimatingOnDown) {
517173f2d0fad8dc889beefff67be96ec865465d1e0Selim Cinek                    float hAbs = Math.abs(h);
518173f2d0fad8dc889beefff67be96ec865465d1e0Selim Cinek                    if ((h < -mTouchSlop || (mAnimatingOnDown && hAbs > mTouchSlop))
519173f2d0fad8dc889beefff67be96ec865465d1e0Selim Cinek                            && hAbs > Math.abs(x - mInitialTouchX)) {
520dbbcfbe8aea1944fc0b0ecbf531034bcd5b5770aSelim Cinek                        cancelHeightAnimator();
521b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek                        startExpandMotion(x, y, true /* startTracking */, mExpandedHeight);
522b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek                        return true;
523b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek                    }
524b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek                }
525b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek                break;
52631094df5c6e3cb3a4a4faacb091e35eea1f6a5deSelim Cinek            case MotionEvent.ACTION_CANCEL:
52731094df5c6e3cb3a4a4faacb091e35eea1f6a5deSelim Cinek            case MotionEvent.ACTION_UP:
528547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek                if (mVelocityTracker != null) {
529547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek                    mVelocityTracker.recycle();
530547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek                    mVelocityTracker = null;
531547a06b50fa97cd079851f80d0d5aa5297cbb040Selim Cinek                }
53231094df5c6e3cb3a4a4faacb091e35eea1f6a5deSelim Cinek                break;
533b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek        }
534b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek        return false;
535b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek    }
536b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek
537ab1dc954b2b97b59f868c96921f2daabc3336034Selim Cinek    /**
538ab1dc954b2b97b59f868c96921f2daabc3336034Selim Cinek     * @return Whether a pair of coordinates are inside the visible view content bounds.
539ab1dc954b2b97b59f868c96921f2daabc3336034Selim Cinek     */
540ab1dc954b2b97b59f868c96921f2daabc3336034Selim Cinek    protected abstract boolean isInContentBounds(float x, float y);
541ab1dc954b2b97b59f868c96921f2daabc3336034Selim Cinek
542831941fdd9a800e2838ef60193134763867a333eSelim Cinek    protected void cancelHeightAnimator() {
543dbbcfbe8aea1944fc0b0ecbf531034bcd5b5770aSelim Cinek        if (mHeightAnimator != null) {
544dbbcfbe8aea1944fc0b0ecbf531034bcd5b5770aSelim Cinek            mHeightAnimator.cancel();
545dbbcfbe8aea1944fc0b0ecbf531034bcd5b5770aSelim Cinek        }
546dbbcfbe8aea1944fc0b0ecbf531034bcd5b5770aSelim Cinek        endClosing();
547dbbcfbe8aea1944fc0b0ecbf531034bcd5b5770aSelim Cinek    }
548dbbcfbe8aea1944fc0b0ecbf531034bcd5b5770aSelim Cinek
549dbbcfbe8aea1944fc0b0ecbf531034bcd5b5770aSelim Cinek    private void endClosing() {
550dbbcfbe8aea1944fc0b0ecbf531034bcd5b5770aSelim Cinek        if (mClosing) {
551dbbcfbe8aea1944fc0b0ecbf531034bcd5b5770aSelim Cinek            mClosing = false;
552dbbcfbe8aea1944fc0b0ecbf531034bcd5b5770aSelim Cinek            onClosingFinished();
553dbbcfbe8aea1944fc0b0ecbf531034bcd5b5770aSelim Cinek        }
554dbbcfbe8aea1944fc0b0ecbf531034bcd5b5770aSelim Cinek    }
555dbbcfbe8aea1944fc0b0ecbf531034bcd5b5770aSelim Cinek
556b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek    private void initVelocityTracker() {
557b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek        if (mVelocityTracker != null) {
558b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek            mVelocityTracker.recycle();
559b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek        }
560b7b61ddaef4f2a2ebc79e832fb909fd4dcac8ba5Jorim Jaggi        mVelocityTracker = VelocityTrackerFactory.obtain(getContext());
561b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek    }
562b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek
563b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek    protected boolean isScrolledToBottom() {
564172e914178181cf1c5999722fc0817e8ac2097f1Selim Cinek        return true;
565b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek    }
566b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek
567b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek    protected float getContentHeight() {
568b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek        return mExpandedHeight;
569bf526d14f3252b8a5c123291e4cd8b1c51346560Daniel Sandler    }
570bf526d14f3252b8a5c123291e4cd8b1c51346560Daniel Sandler
57108d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    @Override
57208d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    protected void onFinishInflate() {
57308d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        super.onFinishInflate();
574069cd03740312159faf24a01910ff1daeae93131Jorim Jaggi        loadDimens();
575069cd03740312159faf24a01910ff1daeae93131Jorim Jaggi    }
5760c1b75c17b79979e0f210b5bf03226d1091a4c21Daniel Sandler
577069cd03740312159faf24a01910ff1daeae93131Jorim Jaggi    @Override
578069cd03740312159faf24a01910ff1daeae93131Jorim Jaggi    protected void onConfigurationChanged(Configuration newConfig) {
579069cd03740312159faf24a01910ff1daeae93131Jorim Jaggi        super.onConfigurationChanged(newConfig);
58008d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        loadDimens();
58108d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    }
58208d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler
5832fbad7b6a724cf0a5b98b66fe639d58f5ab10af3Jorim Jaggi    /**
584b7240136b748e548069c7fe2bd77a7ed4148728eJorim Jaggi     * @param vel the current vertical velocity of the motion
585b7240136b748e548069c7fe2bd77a7ed4148728eJorim Jaggi     * @param vectorVel the length of the vectorial velocity
586e29b2dbc762bfa66093d76f5a65f55328d8753c9Jorim Jaggi     * @return whether a fling should expands the panel; contracts otherwise
5872fbad7b6a724cf0a5b98b66fe639d58f5ab10af3Jorim Jaggi     */
5889db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek    protected boolean flingExpands(float vel, float vectorVel, float x, float y) {
5899db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek        if (isFalseTouch(x, y)) {
59019c8c708f16546fc75ae12659aa190f5e3dfbb52Selim Cinek            return true;
59119c8c708f16546fc75ae12659aa190f5e3dfbb52Selim Cinek        }
592b7240136b748e548069c7fe2bd77a7ed4148728eJorim Jaggi        if (Math.abs(vectorVel) < mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
593e29b2dbc762bfa66093d76f5a65f55328d8753c9Jorim Jaggi            return getExpandedFraction() > 0.5f;
5941d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi        } else {
595e29b2dbc762bfa66093d76f5a65f55328d8753c9Jorim Jaggi            return vel > 0;
5961d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi        }
5971d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi    }
59808d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler
5999db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek    /**
6009db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek     * @param x the final x-coordinate when the finger was lifted
6019db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek     * @param y the final y-coordinate when the finger was lifted
6029db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek     * @return whether this motion should be regarded as a false touch
6039db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek     */
6049db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek    private boolean isFalseTouch(float x, float y) {
6059db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek        if (!mStatusBar.isFalsingThresholdNeeded()) {
6069db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek            return false;
6079db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek        }
6086dc59b48c040cf6871d7ff6d8e5242b1a5ddd032Blazej Magnowski        if (mFalsingManager.isClassiferEnabled()) {
6096dc59b48c040cf6871d7ff6d8e5242b1a5ddd032Blazej Magnowski            return mFalsingManager.isFalseTouch();
6100e2ffbd48bbedf47deb7f6aed96bd07e2fc96f53Blazej Magnowski        }
6119db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek        if (!mTouchAboveFalsingThreshold) {
6129db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek            return true;
6139db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek        }
6149db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek        if (mUpwardsWhenTresholdReached) {
6159db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek            return false;
6169db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek        }
6179db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek        return !isDirectionUpwards(x, y);
6185386fb337d3f2bd9b0ea673b5f60483246e5d0cdSelim Cinek    }
6195386fb337d3f2bd9b0ea673b5f60483246e5d0cdSelim Cinek
6201d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi    protected void fling(float vel, boolean expand) {
6219db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek        fling(vel, expand, 1.0f /* collapseSpeedUpFactor */, false);
6229db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek    }
6239db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek
6249db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek    protected void fling(float vel, boolean expand, boolean expandBecauseOfFalsing) {
6259db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek        fling(vel, expand, 1.0f /* collapseSpeedUpFactor */, expandBecauseOfFalsing);
626f3b3bee12994a24b60bd447dede9e8791151fcc9Jorim Jaggi    }
627f3b3bee12994a24b60bd447dede9e8791151fcc9Jorim Jaggi
6289db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek    protected void fling(float vel, boolean expand, float collapseSpeedUpFactor,
6299db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek            boolean expandBecauseOfFalsing) {
6301d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi        cancelPeek();
6311d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi        float target = expand ? getMaxPanelHeight() : 0.0f;
6323e02adb028741938dab9787fa1552f86b2558c9aJorim Jaggi        if (!expand) {
6333e02adb028741938dab9787fa1552f86b2558c9aJorim Jaggi            mClosing = true;
6343e02adb028741938dab9787fa1552f86b2558c9aJorim Jaggi        }
6359db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek        flingToHeight(vel, expand, target, collapseSpeedUpFactor, expandBecauseOfFalsing);
636b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek    }
6374b04a3a1649018e7f0fe11136d0b012a9eeb44eaJorim Jaggi
638f3b3bee12994a24b60bd447dede9e8791151fcc9Jorim Jaggi    protected void flingToHeight(float vel, boolean expand, float target,
6399db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek            float collapseSpeedUpFactor, boolean expandBecauseOfFalsing) {
6404b04a3a1649018e7f0fe11136d0b012a9eeb44eaJorim Jaggi        // Hack to make the expand transition look nice when clear all button is visible - we make
6414b04a3a1649018e7f0fe11136d0b012a9eeb44eaJorim Jaggi        // the animation only to the last notification, and then jump to the maximum panel height so
6424b04a3a1649018e7f0fe11136d0b012a9eeb44eaJorim Jaggi        // clear all just fades in and the decelerating motion is towards the last notification.
6434b04a3a1649018e7f0fe11136d0b012a9eeb44eaJorim Jaggi        final boolean clearAllExpandHack = expand && fullyExpandedClearAllVisible()
6444b04a3a1649018e7f0fe11136d0b012a9eeb44eaJorim Jaggi                && mExpandedHeight < getMaxPanelHeight() - getClearAllHeight()
6454b04a3a1649018e7f0fe11136d0b012a9eeb44eaJorim Jaggi                && !isClearAllVisible();
6464b04a3a1649018e7f0fe11136d0b012a9eeb44eaJorim Jaggi        if (clearAllExpandHack) {
6474b04a3a1649018e7f0fe11136d0b012a9eeb44eaJorim Jaggi            target = getMaxPanelHeight() - getClearAllHeight();
6484b04a3a1649018e7f0fe11136d0b012a9eeb44eaJorim Jaggi        }
64947c85a3525dcd0bbd3168632830e8ab491d18462Jorim Jaggi        if (target == mExpandedHeight || getOverExpansionAmount() > 0f && expand) {
650b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi            notifyExpandingFinished();
6512fbad7b6a724cf0a5b98b66fe639d58f5ab10af3Jorim Jaggi            return;
6522fbad7b6a724cf0a5b98b66fe639d58f5ab10af3Jorim Jaggi        }
65347c85a3525dcd0bbd3168632830e8ab491d18462Jorim Jaggi        mOverExpandedBeforeFling = getOverExpansionAmount() > 0f;
6549012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi        ValueAnimator animator = createHeightAnimator(target);
6551d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi        if (expand) {
6569db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek            if (expandBecauseOfFalsing) {
6575386fb337d3f2bd9b0ea673b5f60483246e5d0cdSelim Cinek                vel = 0;
6585386fb337d3f2bd9b0ea673b5f60483246e5d0cdSelim Cinek            }
6591d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi            mFlingAnimationUtils.apply(animator, mExpandedHeight, target, vel, getHeight());
6606626f54e658e3da44fab8a5cd6d9d3d4852e2cd1Jorim Jaggi            if (vel == 0) {
6615386fb337d3f2bd9b0ea673b5f60483246e5d0cdSelim Cinek                animator.setDuration(350);
6625386fb337d3f2bd9b0ea673b5f60483246e5d0cdSelim Cinek            }
6631685e634fb0b14033bd436af8d7174436699ffecSelim Cinek        } else {
6641d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi            mFlingAnimationUtils.applyDismissing(animator, mExpandedHeight, target, vel,
6651d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi                    getHeight());
6661d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi
6671d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi            // Make it shorter if we run a canned animation
6681d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi            if (vel == 0) {
66930c305ce6283ce1380ad91ef0d221696b32d5a6bJorim Jaggi                animator.setDuration((long)
670f3b3bee12994a24b60bd447dede9e8791151fcc9Jorim Jaggi                        (animator.getDuration() * getCannedFlingDurationFactor()
671f3b3bee12994a24b60bd447dede9e8791151fcc9Jorim Jaggi                                / collapseSpeedUpFactor));
6721d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi            }
67308d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        }
6741d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi        animator.addListener(new AnimatorListenerAdapter() {
675b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi            private boolean mCancelled;
676b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi
677b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi            @Override
678b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi            public void onAnimationCancel(Animator animation) {
679b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi                mCancelled = true;
680b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi            }
681b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi
6821d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi            @Override
6831d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi            public void onAnimationEnd(Animator animation) {
6844b04a3a1649018e7f0fe11136d0b012a9eeb44eaJorim Jaggi                if (clearAllExpandHack && !mCancelled) {
6852ae259df68659fd3c0c3ca070f58ca40b20de8b8Jorim Jaggi                    setExpandedHeightInternal(getMaxPanelHeight());
6862ae259df68659fd3c0c3ca070f58ca40b20de8b8Jorim Jaggi                }
6872ae259df68659fd3c0c3ca070f58ca40b20de8b8Jorim Jaggi                mHeightAnimator = null;
6882ae259df68659fd3c0c3ca070f58ca40b20de8b8Jorim Jaggi                if (!mCancelled) {
6892ae259df68659fd3c0c3ca070f58ca40b20de8b8Jorim Jaggi                    notifyExpandingFinished();
690b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi                }
691eb8f11a8657a1509d6c00b3c6f34547f803bbe67Jorim Jaggi                notifyBarPanelExpansionChanged();
6921d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi            }
6931d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi        });
6941d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi        mHeightAnimator = animator;
69547c85a3525dcd0bbd3168632830e8ab491d18462Jorim Jaggi        animator.start();
69608d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    }
69708d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler
69808d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    @Override
69908d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    protected void onAttachedToWindow() {
70008d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        super.onAttachedToWindow();
701978f853d189c1857190b4a2e200c7a283e31ca14Daniel Sandler        mViewName = getResources().getResourceName(getId());
702978f853d189c1857190b4a2e200c7a283e31ca14Daniel Sandler    }
703978f853d189c1857190b4a2e200c7a283e31ca14Daniel Sandler
704978f853d189c1857190b4a2e200c7a283e31ca14Daniel Sandler    public String getName() {
705978f853d189c1857190b4a2e200c7a283e31ca14Daniel Sandler        return mViewName;
70608d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    }
70708d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler
70808d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    public void setExpandedHeight(float height) {
7099764218ff979f735aee2f1189e3547d5f3b02f83John Spurlock        if (DEBUG) logf("setExpandedHeight(%.1f)", height);
71047c85a3525dcd0bbd3168632830e8ab491d18462Jorim Jaggi        setExpandedHeightInternal(height + getOverExpansionPixels());
71108d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    }
71208d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler
7135050813f15a1d39d49cb8eca5a3aa6df43c4d450Daniel Sandler    @Override
7145050813f15a1d39d49cb8eca5a3aa6df43c4d450Daniel Sandler    protected void onLayout (boolean changed, int left, int top, int right, int bottom) {
7155050813f15a1d39d49cb8eca5a3aa6df43c4d450Daniel Sandler        super.onLayout(changed, left, top, right, bottom);
7165fbc632fefa8e4826d42a2ba43772f9f906153ffSelim Cinek        mStatusBar.onPanelLaidOut();
717b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek        requestPanelHeightUpdate();
71831094df5c6e3cb3a4a4faacb091e35eea1f6a5deSelim Cinek        mHasLayoutedSinceDown = true;
71931094df5c6e3cb3a4a4faacb091e35eea1f6a5deSelim Cinek        if (mUpdateFlingOnLayout) {
72031094df5c6e3cb3a4a4faacb091e35eea1f6a5deSelim Cinek            abortAnimations();
721b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek            fling(mUpdateFlingVelocity, true /* expands */);
72231094df5c6e3cb3a4a4faacb091e35eea1f6a5deSelim Cinek            mUpdateFlingOnLayout = false;
72331094df5c6e3cb3a4a4faacb091e35eea1f6a5deSelim Cinek        }
724b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek    }
725b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek
726b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek    protected void requestPanelHeightUpdate() {
727b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek        float currentMaxPanelHeight = getMaxPanelHeight();
728b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek
729b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek        // If the user isn't actively poking us, let's update the height
73030c305ce6283ce1380ad91ef0d221696b32d5a6bJorim Jaggi        if ((!mTracking || isTrackingBlocked())
73130c305ce6283ce1380ad91ef0d221696b32d5a6bJorim Jaggi                && mHeightAnimator == null
732684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek                && !isFullyCollapsed()
73330c305ce6283ce1380ad91ef0d221696b32d5a6bJorim Jaggi                && currentMaxPanelHeight != mExpandedHeight
73430c305ce6283ce1380ad91ef0d221696b32d5a6bJorim Jaggi                && !mPeekPending
73531094df5c6e3cb3a4a4faacb091e35eea1f6a5deSelim Cinek                && mPeekAnimator == null
736b7a3303f807ee01bbe405f4153a2285e55c0b6e3Jorim Jaggi                && !mPeekTouching) {
73747c85a3525dcd0bbd3168632830e8ab491d18462Jorim Jaggi            setExpandedHeight(currentMaxPanelHeight);
738b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek        }
7395050813f15a1d39d49cb8eca5a3aa6df43c4d450Daniel Sandler    }
7405050813f15a1d39d49cb8eca5a3aa6df43c4d450Daniel Sandler
74108d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    public void setExpandedHeightInternal(float h) {
74247c85a3525dcd0bbd3168632830e8ab491d18462Jorim Jaggi        float fhWithoutOverExpansion = getMaxPanelHeight() - getOverExpansionAmount();
74347c85a3525dcd0bbd3168632830e8ab491d18462Jorim Jaggi        if (mHeightAnimator == null) {
74447c85a3525dcd0bbd3168632830e8ab491d18462Jorim Jaggi            float overExpansionPixels = Math.max(0, h - fhWithoutOverExpansion);
74547c85a3525dcd0bbd3168632830e8ab491d18462Jorim Jaggi            if (getOverExpansionPixels() != overExpansionPixels && mTracking) {
74647c85a3525dcd0bbd3168632830e8ab491d18462Jorim Jaggi                setOverExpansion(overExpansionPixels, true /* isPixels */);
74747c85a3525dcd0bbd3168632830e8ab491d18462Jorim Jaggi            }
74847c85a3525dcd0bbd3168632830e8ab491d18462Jorim Jaggi            mExpandedHeight = Math.min(h, fhWithoutOverExpansion) + getOverExpansionAmount();
74947c85a3525dcd0bbd3168632830e8ab491d18462Jorim Jaggi        } else {
75047c85a3525dcd0bbd3168632830e8ab491d18462Jorim Jaggi            mExpandedHeight = h;
75147c85a3525dcd0bbd3168632830e8ab491d18462Jorim Jaggi            if (mOverExpandedBeforeFling) {
75247c85a3525dcd0bbd3168632830e8ab491d18462Jorim Jaggi                setOverExpansion(Math.max(0, h - fhWithoutOverExpansion), false /* isPixels */);
75347c85a3525dcd0bbd3168632830e8ab491d18462Jorim Jaggi            }
754b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek        }
755b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek
75693439da0ed9213bc54291b3fce4e04dd3a7f9f3aJorim Jaggi        mExpandedHeight = Math.max(0, mExpandedHeight);
75747c85a3525dcd0bbd3168632830e8ab491d18462Jorim Jaggi        mExpandedFraction = Math.min(1f, fhWithoutOverExpansion == 0
75847c85a3525dcd0bbd3168632830e8ab491d18462Jorim Jaggi                ? 0
75947c85a3525dcd0bbd3168632830e8ab491d18462Jorim Jaggi                : mExpandedHeight / fhWithoutOverExpansion);
76006a0c3a4459de084ecf8f1a8920edf36c41ac164Jorim Jaggi        onHeightUpdated(mExpandedHeight);
761b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi        notifyBarPanelExpansionChanged();
76208d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    }
76308d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler
76430c305ce6283ce1380ad91ef0d221696b32d5a6bJorim Jaggi    /**
76530c305ce6283ce1380ad91ef0d221696b32d5a6bJorim Jaggi     * @return true if the panel tracking should be temporarily blocked; this is used when a
76630c305ce6283ce1380ad91ef0d221696b32d5a6bJorim Jaggi     *         conflicting gesture (opening QS) is happening
76730c305ce6283ce1380ad91ef0d221696b32d5a6bJorim Jaggi     */
76830c305ce6283ce1380ad91ef0d221696b32d5a6bJorim Jaggi    protected abstract boolean isTrackingBlocked();
76930c305ce6283ce1380ad91ef0d221696b32d5a6bJorim Jaggi
77047c85a3525dcd0bbd3168632830e8ab491d18462Jorim Jaggi    protected abstract void setOverExpansion(float overExpansion, boolean isPixels);
77124120a5ccf79f6f4844916121bcc1fbad0b7691bSelim Cinek
7729012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi    protected abstract void onHeightUpdated(float expandedHeight);
773b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek
77447c85a3525dcd0bbd3168632830e8ab491d18462Jorim Jaggi    protected abstract float getOverExpansionAmount();
77547c85a3525dcd0bbd3168632830e8ab491d18462Jorim Jaggi
77647c85a3525dcd0bbd3168632830e8ab491d18462Jorim Jaggi    protected abstract float getOverExpansionPixels();
77747c85a3525dcd0bbd3168632830e8ab491d18462Jorim Jaggi
778b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek    /**
779b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek     * This returns the maximum height of the panel. Children should override this if their
780b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek     * desired height is not the full height.
781b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek     *
782b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek     * @return the default implementation simply returns the maximum height.
783b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek     */
78431094df5c6e3cb3a4a4faacb091e35eea1f6a5deSelim Cinek    protected abstract int getMaxPanelHeight();
78508d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler
78608d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    public void setExpandedFraction(float frac) {
787b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek        setExpandedHeight(getMaxPanelHeight() * frac);
78808d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    }
78908d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler
79008d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    public float getExpandedHeight() {
79108d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        return mExpandedHeight;
79208d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    }
79308d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler
79408d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    public float getExpandedFraction() {
79508d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        return mExpandedFraction;
79608d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    }
79708d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler
798b4e56edde684c2a09cb225c99571fddb39b43b34Daniel Sandler    public boolean isFullyExpanded() {
799b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek        return mExpandedHeight >= getMaxPanelHeight();
800b4e56edde684c2a09cb225c99571fddb39b43b34Daniel Sandler    }
801b4e56edde684c2a09cb225c99571fddb39b43b34Daniel Sandler
802b4e56edde684c2a09cb225c99571fddb39b43b34Daniel Sandler    public boolean isFullyCollapsed() {
80367eab79051eea2d4f8fda4a2a698900ffacfb557Daniel Sandler        return mExpandedHeight <= 0;
80467eab79051eea2d4f8fda4a2a698900ffacfb557Daniel Sandler    }
80567eab79051eea2d4f8fda4a2a698900ffacfb557Daniel Sandler
80667eab79051eea2d4f8fda4a2a698900ffacfb557Daniel Sandler    public boolean isCollapsing() {
80767eab79051eea2d4f8fda4a2a698900ffacfb557Daniel Sandler        return mClosing;
808b4e56edde684c2a09cb225c99571fddb39b43b34Daniel Sandler    }
809b4e56edde684c2a09cb225c99571fddb39b43b34Daniel Sandler
810a4b70aff3419b61d2395589b393251da9ddcba3fJohn Spurlock    public boolean isTracking() {
811a4b70aff3419b61d2395589b393251da9ddcba3fJohn Spurlock        return mTracking;
812a4b70aff3419b61d2395589b393251da9ddcba3fJohn Spurlock    }
813a4b70aff3419b61d2395589b393251da9ddcba3fJohn Spurlock
81408d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    public void setBar(PanelBar panelBar) {
81508d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        mBar = panelBar;
81608d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    }
81708d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler
818f3b3bee12994a24b60bd447dede9e8791151fcc9Jorim Jaggi    public void collapse(boolean delayed, float speedUpFactor) {
8199764218ff979f735aee2f1189e3547d5f3b02f83John Spurlock        if (DEBUG) logf("collapse: " + this);
820b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi        if (mPeekPending || mPeekAnimator != null) {
821b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi            mCollapseAfterPeek = true;
822b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi            if (mPeekPending) {
823b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi
824b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi                // We know that the whole gesture is just a peek triggered by a simple click, so
825b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi                // better start it now.
826b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi                removeCallbacks(mPeekRunnable);
827b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi                mPeekRunnable.run();
828b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi            }
82998139559af15d85b8a34c02fe9bc97fba901a4b5Jorim Jaggi        } else if (!isFullyCollapsed() && !mTracking && !mClosing) {
830dbbcfbe8aea1944fc0b0ecbf531034bcd5b5770aSelim Cinek            cancelHeightAnimator();
831b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi            notifyExpandingStarted();
8323b866bee86f742f51a0042985ec7666283dc4406Jorim Jaggi
8333b866bee86f742f51a0042985ec7666283dc4406Jorim Jaggi            // Set after notifyExpandingStarted, as notifyExpandingStarted resets the closing state.
8343b866bee86f742f51a0042985ec7666283dc4406Jorim Jaggi            mClosing = true;
8358de4311c51229efbe2f2d0afbf298982c5cadd96Jorim Jaggi            if (delayed) {
836f3b3bee12994a24b60bd447dede9e8791151fcc9Jorim Jaggi                mNextCollapseSpeedUpFactor = speedUpFactor;
8375cbfe5476b1422c63363c6899d455870bed15663Jorim Jaggi                postDelayed(mFlingCollapseRunnable, 120);
8388de4311c51229efbe2f2d0afbf298982c5cadd96Jorim Jaggi            } else {
8399db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek                fling(0, false /* expand */, speedUpFactor, false /* expandBecauseOfFalsing */);
8408de4311c51229efbe2f2d0afbf298982c5cadd96Jorim Jaggi            }
84108d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        }
84208d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    }
84308d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler
8445cbfe5476b1422c63363c6899d455870bed15663Jorim Jaggi    private final Runnable mFlingCollapseRunnable = new Runnable() {
8455cbfe5476b1422c63363c6899d455870bed15663Jorim Jaggi        @Override
8465cbfe5476b1422c63363c6899d455870bed15663Jorim Jaggi        public void run() {
8479db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek            fling(0, false /* expand */, mNextCollapseSpeedUpFactor,
8489db71054b83a650f3478c9335634b611ddaf53bfSelim Cinek                    false /* expandBecauseOfFalsing */);
8495cbfe5476b1422c63363c6899d455870bed15663Jorim Jaggi        }
8505cbfe5476b1422c63363c6899d455870bed15663Jorim Jaggi    };
8515cbfe5476b1422c63363c6899d455870bed15663Jorim Jaggi
8529764218ff979f735aee2f1189e3547d5f3b02f83John Spurlock    public void cancelPeek() {
853529c5325f0e5cd3cf97fd7431d8dc9e79d7a627fSelim Cinek        boolean cancelled = mPeekPending;
854b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi        if (mPeekAnimator != null) {
855529c5325f0e5cd3cf97fd7431d8dc9e79d7a627fSelim Cinek            cancelled = true;
8569764218ff979f735aee2f1189e3547d5f3b02f83John Spurlock            mPeekAnimator.cancel();
85708d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        }
858b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi        removeCallbacks(mPeekRunnable);
859b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi        mPeekPending = false;
860b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi
861529c5325f0e5cd3cf97fd7431d8dc9e79d7a627fSelim Cinek        if (cancelled) {
862529c5325f0e5cd3cf97fd7431d8dc9e79d7a627fSelim Cinek            // When peeking, we already tell mBar that we expanded ourselves. Make sure that we also
863529c5325f0e5cd3cf97fd7431d8dc9e79d7a627fSelim Cinek            // notify mBar that we might have closed ourselves.
864529c5325f0e5cd3cf97fd7431d8dc9e79d7a627fSelim Cinek            notifyBarPanelExpansionChanged();
865529c5325f0e5cd3cf97fd7431d8dc9e79d7a627fSelim Cinek        }
86608d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    }
86737a38aaecb5045906ade6d1c970f106a028cbaf5Daniel Sandler
8688d3fea15b80ac4fab7abe7a7a07c6368166de5e1Oren Blasberg    public void expand(final boolean animate) {
8698d3fea15b80ac4fab7abe7a7a07c6368166de5e1Oren Blasberg        if (!isFullyCollapsed() && !isCollapsing()) {
8708d3fea15b80ac4fab7abe7a7a07c6368166de5e1Oren Blasberg            return;
8718d3fea15b80ac4fab7abe7a7a07c6368166de5e1Oren Blasberg        }
8728d3fea15b80ac4fab7abe7a7a07c6368166de5e1Oren Blasberg
8730a27be899c7143df1d8b64ef842b7f6b7fcf0baaJorim Jaggi        mInstantExpanding = true;
8746626f54e658e3da44fab8a5cd6d9d3d4852e2cd1Jorim Jaggi        mAnimateAfterExpanding = animate;
8755cbfe5476b1422c63363c6899d455870bed15663Jorim Jaggi        mUpdateFlingOnLayout = false;
8760a27be899c7143df1d8b64ef842b7f6b7fcf0baaJorim Jaggi        abortAnimations();
8775cbfe5476b1422c63363c6899d455870bed15663Jorim Jaggi        cancelPeek();
8780a27be899c7143df1d8b64ef842b7f6b7fcf0baaJorim Jaggi        if (mTracking) {
8790a27be899c7143df1d8b64ef842b7f6b7fcf0baaJorim Jaggi            onTrackingStopped(true /* expands */); // The panel is expanded after this call.
880e62d589bea54e58054ae16265c92e974a8250ff5Jorim Jaggi        }
881e62d589bea54e58054ae16265c92e974a8250ff5Jorim Jaggi        if (mExpanding) {
882b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi            notifyExpandingFinished();
8830a27be899c7143df1d8b64ef842b7f6b7fcf0baaJorim Jaggi        }
884b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek        notifyBarPanelExpansionChanged();
8850a27be899c7143df1d8b64ef842b7f6b7fcf0baaJorim Jaggi
8860a27be899c7143df1d8b64ef842b7f6b7fcf0baaJorim Jaggi        // Wait for window manager to pickup the change, so we know the maximum height of the panel
8870a27be899c7143df1d8b64ef842b7f6b7fcf0baaJorim Jaggi        // then.
8880a27be899c7143df1d8b64ef842b7f6b7fcf0baaJorim Jaggi        getViewTreeObserver().addOnGlobalLayoutListener(
8890a27be899c7143df1d8b64ef842b7f6b7fcf0baaJorim Jaggi                new ViewTreeObserver.OnGlobalLayoutListener() {
8900a27be899c7143df1d8b64ef842b7f6b7fcf0baaJorim Jaggi                    @Override
8910a27be899c7143df1d8b64ef842b7f6b7fcf0baaJorim Jaggi                    public void onGlobalLayout() {
892c5804afa73edbf229e789570d288e66f70b54fa2Jorim Jaggi                        if (!mInstantExpanding) {
893c5804afa73edbf229e789570d288e66f70b54fa2Jorim Jaggi                            getViewTreeObserver().removeOnGlobalLayoutListener(this);
894c5804afa73edbf229e789570d288e66f70b54fa2Jorim Jaggi                            return;
895c5804afa73edbf229e789570d288e66f70b54fa2Jorim Jaggi                        }
8960a27be899c7143df1d8b64ef842b7f6b7fcf0baaJorim Jaggi                        if (mStatusBar.getStatusBarWindow().getHeight()
8970a27be899c7143df1d8b64ef842b7f6b7fcf0baaJorim Jaggi                                != mStatusBar.getStatusBarHeight()) {
8980a27be899c7143df1d8b64ef842b7f6b7fcf0baaJorim Jaggi                            getViewTreeObserver().removeOnGlobalLayoutListener(this);
8996626f54e658e3da44fab8a5cd6d9d3d4852e2cd1Jorim Jaggi                            if (mAnimateAfterExpanding) {
9008d3fea15b80ac4fab7abe7a7a07c6368166de5e1Oren Blasberg                                notifyExpandingStarted();
9018d3fea15b80ac4fab7abe7a7a07c6368166de5e1Oren Blasberg                                fling(0, true /* expand */);
9028d3fea15b80ac4fab7abe7a7a07c6368166de5e1Oren Blasberg                            } else {
9038d3fea15b80ac4fab7abe7a7a07c6368166de5e1Oren Blasberg                                setExpandedFraction(1f);
9048d3fea15b80ac4fab7abe7a7a07c6368166de5e1Oren Blasberg                            }
9050a27be899c7143df1d8b64ef842b7f6b7fcf0baaJorim Jaggi                            mInstantExpanding = false;
9060a27be899c7143df1d8b64ef842b7f6b7fcf0baaJorim Jaggi                        }
9070a27be899c7143df1d8b64ef842b7f6b7fcf0baaJorim Jaggi                    }
9080a27be899c7143df1d8b64ef842b7f6b7fcf0baaJorim Jaggi                });
9090a27be899c7143df1d8b64ef842b7f6b7fcf0baaJorim Jaggi
9100a27be899c7143df1d8b64ef842b7f6b7fcf0baaJorim Jaggi        // Make sure a layout really happens.
9110a27be899c7143df1d8b64ef842b7f6b7fcf0baaJorim Jaggi        requestLayout();
9120a27be899c7143df1d8b64ef842b7f6b7fcf0baaJorim Jaggi    }
9130a27be899c7143df1d8b64ef842b7f6b7fcf0baaJorim Jaggi
9146bb4a9b356bdb141e353a8115e100029bed3eb88Selim Cinek    public void instantCollapse() {
9156bb4a9b356bdb141e353a8115e100029bed3eb88Selim Cinek        abortAnimations();
9166bb4a9b356bdb141e353a8115e100029bed3eb88Selim Cinek        setExpandedFraction(0f);
9176bb4a9b356bdb141e353a8115e100029bed3eb88Selim Cinek        if (mExpanding) {
9186bb4a9b356bdb141e353a8115e100029bed3eb88Selim Cinek            notifyExpandingFinished();
9196bb4a9b356bdb141e353a8115e100029bed3eb88Selim Cinek        }
920c5804afa73edbf229e789570d288e66f70b54fa2Jorim Jaggi        if (mInstantExpanding) {
921c5804afa73edbf229e789570d288e66f70b54fa2Jorim Jaggi            mInstantExpanding = false;
922c5804afa73edbf229e789570d288e66f70b54fa2Jorim Jaggi            notifyBarPanelExpansionChanged();
923c5804afa73edbf229e789570d288e66f70b54fa2Jorim Jaggi        }
9246bb4a9b356bdb141e353a8115e100029bed3eb88Selim Cinek    }
9256bb4a9b356bdb141e353a8115e100029bed3eb88Selim Cinek
9260a27be899c7143df1d8b64ef842b7f6b7fcf0baaJorim Jaggi    private void abortAnimations() {
9270a27be899c7143df1d8b64ef842b7f6b7fcf0baaJorim Jaggi        cancelPeek();
928dbbcfbe8aea1944fc0b0ecbf531034bcd5b5770aSelim Cinek        cancelHeightAnimator();
9295cbfe5476b1422c63363c6899d455870bed15663Jorim Jaggi        removeCallbacks(mPostCollapseRunnable);
9305cbfe5476b1422c63363c6899d455870bed15663Jorim Jaggi        removeCallbacks(mFlingCollapseRunnable);
9310a27be899c7143df1d8b64ef842b7f6b7fcf0baaJorim Jaggi    }
9320a27be899c7143df1d8b64ef842b7f6b7fcf0baaJorim Jaggi
933dbbcfbe8aea1944fc0b0ecbf531034bcd5b5770aSelim Cinek    protected void onClosingFinished() {
934dbbcfbe8aea1944fc0b0ecbf531034bcd5b5770aSelim Cinek        mBar.onClosingFinished();
935dbbcfbe8aea1944fc0b0ecbf531034bcd5b5770aSelim Cinek    }
936dbbcfbe8aea1944fc0b0ecbf531034bcd5b5770aSelim Cinek
937dbbcfbe8aea1944fc0b0ecbf531034bcd5b5770aSelim Cinek
9389012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi    protected void startUnlockHintAnimation() {
9399012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi
9409012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi        // We don't need to hint the user if an animation is already running or the user is changing
9419012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi        // the expansion.
9429012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi        if (mHeightAnimator != null || mTracking) {
9439012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi            return;
9449012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi        }
9459012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi        cancelPeek();
946b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi        notifyExpandingStarted();
947b3f0a2ff000ca2481f95ee8f7d7b487e33b87ecaJorim Jaggi        startUnlockHintAnimationPhase1(new Runnable() {
948b3f0a2ff000ca2481f95ee8f7d7b487e33b87ecaJorim Jaggi            @Override
949b3f0a2ff000ca2481f95ee8f7d7b487e33b87ecaJorim Jaggi            public void run() {
950b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi                notifyExpandingFinished();
951b3f0a2ff000ca2481f95ee8f7d7b487e33b87ecaJorim Jaggi                mStatusBar.onHintFinished();
952b3f0a2ff000ca2481f95ee8f7d7b487e33b87ecaJorim Jaggi                mHintAnimationRunning = false;
953b3f0a2ff000ca2481f95ee8f7d7b487e33b87ecaJorim Jaggi            }
954b3f0a2ff000ca2481f95ee8f7d7b487e33b87ecaJorim Jaggi        });
9559012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi        mStatusBar.onUnlockHintStarted();
956b3f0a2ff000ca2481f95ee8f7d7b487e33b87ecaJorim Jaggi        mHintAnimationRunning = true;
9579012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi    }
9589012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi
9599012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi    /**
9609012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi     * Phase 1: Move everything upwards.
9619012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi     */
962b3f0a2ff000ca2481f95ee8f7d7b487e33b87ecaJorim Jaggi    private void startUnlockHintAnimationPhase1(final Runnable onAnimationFinished) {
9639012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi        float target = Math.max(0, getMaxPanelHeight() - mHintDistance);
9649012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi        ValueAnimator animator = createHeightAnimator(target);
9659012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi        animator.setDuration(250);
966c18010f6720f606003cde3cd376ddacaca30f6e5Selim Cinek        animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
9679012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi        animator.addListener(new AnimatorListenerAdapter() {
9689012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi            private boolean mCancelled;
9699012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi
9709012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi            @Override
9719012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi            public void onAnimationCancel(Animator animation) {
9729012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi                mCancelled = true;
9739012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi            }
9749012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi
9759012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi            @Override
9769012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi            public void onAnimationEnd(Animator animation) {
9779012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi                if (mCancelled) {
9789012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi                    mHeightAnimator = null;
979b3f0a2ff000ca2481f95ee8f7d7b487e33b87ecaJorim Jaggi                    onAnimationFinished.run();
9809012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi                } else {
981b3f0a2ff000ca2481f95ee8f7d7b487e33b87ecaJorim Jaggi                    startUnlockHintAnimationPhase2(onAnimationFinished);
9829012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi                }
9839012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi            }
9849012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi        });
9859012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi        animator.start();
9869012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi        mHeightAnimator = animator;
987f99d0007646781b99a63bc0d2103a45f0f72e724Selim Cinek        mKeyguardBottomArea.getIndicationView().animate()
9885256d93121d03b8d23053eead8c11bb3c43db109Selim Cinek                .translationY(-mHintDistance)
989f99d0007646781b99a63bc0d2103a45f0f72e724Selim Cinek                .setDuration(250)
990c18010f6720f606003cde3cd376ddacaca30f6e5Selim Cinek                .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
991f99d0007646781b99a63bc0d2103a45f0f72e724Selim Cinek                .withEndAction(new Runnable() {
992f99d0007646781b99a63bc0d2103a45f0f72e724Selim Cinek                    @Override
993f99d0007646781b99a63bc0d2103a45f0f72e724Selim Cinek                    public void run() {
994f99d0007646781b99a63bc0d2103a45f0f72e724Selim Cinek                        mKeyguardBottomArea.getIndicationView().animate()
9955256d93121d03b8d23053eead8c11bb3c43db109Selim Cinek                                .translationY(0)
996f99d0007646781b99a63bc0d2103a45f0f72e724Selim Cinek                                .setDuration(450)
997f99d0007646781b99a63bc0d2103a45f0f72e724Selim Cinek                                .setInterpolator(mBounceInterpolator)
998f99d0007646781b99a63bc0d2103a45f0f72e724Selim Cinek                                .start();
999f99d0007646781b99a63bc0d2103a45f0f72e724Selim Cinek                    }
1000f99d0007646781b99a63bc0d2103a45f0f72e724Selim Cinek                })
1001f99d0007646781b99a63bc0d2103a45f0f72e724Selim Cinek                .start();
10029012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi    }
10039012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi
10049012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi    /**
10059012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi     * Phase 2: Bounce down.
10069012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi     */
1007b3f0a2ff000ca2481f95ee8f7d7b487e33b87ecaJorim Jaggi    private void startUnlockHintAnimationPhase2(final Runnable onAnimationFinished) {
10089012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi        ValueAnimator animator = createHeightAnimator(getMaxPanelHeight());
10099012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi        animator.setDuration(450);
10109012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi        animator.setInterpolator(mBounceInterpolator);
10119012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi        animator.addListener(new AnimatorListenerAdapter() {
10129012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi            @Override
10139012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi            public void onAnimationEnd(Animator animation) {
10149012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi                mHeightAnimator = null;
1015b3f0a2ff000ca2481f95ee8f7d7b487e33b87ecaJorim Jaggi                onAnimationFinished.run();
1016eb8f11a8657a1509d6c00b3c6f34547f803bbe67Jorim Jaggi                notifyBarPanelExpansionChanged();
10179012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi            }
10189012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi        });
10199012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi        animator.start();
10209012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi        mHeightAnimator = animator;
10219012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi    }
10229012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi
10239012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi    private ValueAnimator createHeightAnimator(float targetHeight) {
10249012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi        ValueAnimator animator = ValueAnimator.ofFloat(mExpandedHeight, targetHeight);
10259012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
10269012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi            @Override
10279012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi            public void onAnimationUpdate(ValueAnimator animation) {
102847c85a3525dcd0bbd3168632830e8ab491d18462Jorim Jaggi                setExpandedHeightInternal((Float) animation.getAnimatedValue());
10299012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi            }
10309012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi        });
10319012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi        return animator;
10329012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi    }
10339012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi
1034b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek    protected void notifyBarPanelExpansionChanged() {
10359f96711e1adf4a28f961c440da1626ad40c03bc8Xiaohui Chen        mBar.panelExpansionChanged(mExpandedFraction, mExpandedFraction > 0f || mPeekPending
10360fccc729fd3b19a62efd90ae13b207faa3d1e8bbSelim Cinek                || mPeekAnimator != null || mInstantExpanding || isPanelVisibleBecauseOfHeadsUp()
1037eb8f11a8657a1509d6c00b3c6f34547f803bbe67Jorim Jaggi                || mTracking || mHeightAnimator != null);
1038b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi    }
1039b472b347b51f84489217bb5d9c3beeeda1e4e626Jorim Jaggi
10400fccc729fd3b19a62efd90ae13b207faa3d1e8bbSelim Cinek    protected abstract boolean isPanelVisibleBecauseOfHeadsUp();
10410fccc729fd3b19a62efd90ae13b207faa3d1e8bbSelim Cinek
10429012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi    /**
10439012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi     * Gets called when the user performs a click anywhere in the empty area of the panel.
10449012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi     *
10459012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi     * @return whether the panel will be expanded after the action performed by this method
10469012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi     */
10473a9c10a2861404f1be9f06a3a54ae18803c81d1dSelim Cinek    protected boolean onEmptySpaceClick(float x) {
1048b3f0a2ff000ca2481f95ee8f7d7b487e33b87ecaJorim Jaggi        if (mHintAnimationRunning) {
1049b3f0a2ff000ca2481f95ee8f7d7b487e33b87ecaJorim Jaggi            return true;
1050b3f0a2ff000ca2481f95ee8f7d7b487e33b87ecaJorim Jaggi        }
10516746c28b812446e847fbfec0f54025558584e70aSelim Cinek        return onMiddleClicked();
1052b3f0a2ff000ca2481f95ee8f7d7b487e33b87ecaJorim Jaggi    }
1053b3f0a2ff000ca2481f95ee8f7d7b487e33b87ecaJorim Jaggi
10541cf6e101263e17c9469c12b4befe36280c109de0Jorim Jaggi    protected final Runnable mPostCollapseRunnable = new Runnable() {
1055488b792eeeea359ba29addd6a202b5475ad1d18fJorim Jaggi        @Override
1056488b792eeeea359ba29addd6a202b5475ad1d18fJorim Jaggi        public void run() {
1057f3b3bee12994a24b60bd447dede9e8791151fcc9Jorim Jaggi            collapse(false /* delayed */, 1.0f /* speedUpFactor */);
1058488b792eeeea359ba29addd6a202b5475ad1d18fJorim Jaggi        }
1059488b792eeeea359ba29addd6a202b5475ad1d18fJorim Jaggi    };
1060488b792eeeea359ba29addd6a202b5475ad1d18fJorim Jaggi
10611cf6e101263e17c9469c12b4befe36280c109de0Jorim Jaggi    protected abstract boolean onMiddleClicked();
10629012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi
1063d7912d2f106053bf4965d137b436e0b5b863f184Jorim Jaggi    protected abstract boolean isDozing();
1064d7912d2f106053bf4965d137b436e0b5b863f184Jorim Jaggi
106537a38aaecb5045906ade6d1c970f106a028cbaf5Daniel Sandler    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1066a3e5bcb60efdf1202f627d25d30693089f7d535dSelim Cinek        pw.println(String.format("[PanelView(%s): expandedHeight=%f maxPanelHeight=%d closing=%s"
106750d87a7fb4fd146112ce1b080d618f67fe08884bJorim Jaggi                + " tracking=%s justPeeked=%s peekAnim=%s%s timeAnim=%s%s touchDisabled=%s"
106837a38aaecb5045906ade6d1c970f106a028cbaf5Daniel Sandler                + "]",
106937a38aaecb5045906ade6d1c970f106a028cbaf5Daniel Sandler                this.getClass().getSimpleName(),
107037a38aaecb5045906ade6d1c970f106a028cbaf5Daniel Sandler                getExpandedHeight(),
1071b6d85ebfe4f9f5d3b7d7ab7b6123af02a0deb516Selim Cinek                getMaxPanelHeight(),
107237a38aaecb5045906ade6d1c970f106a028cbaf5Daniel Sandler                mClosing?"T":"f",
107337a38aaecb5045906ade6d1c970f106a028cbaf5Daniel Sandler                mTracking?"T":"f",
107437a38aaecb5045906ade6d1c970f106a028cbaf5Daniel Sandler                mJustPeeked?"T":"f",
107537a38aaecb5045906ade6d1c970f106a028cbaf5Daniel Sandler                mPeekAnimator, ((mPeekAnimator!=null && mPeekAnimator.isStarted())?" (started)":""),
107650d87a7fb4fd146112ce1b080d618f67fe08884bJorim Jaggi                mHeightAnimator, ((mHeightAnimator !=null && mHeightAnimator.isStarted())?" (started)":""),
107750d87a7fb4fd146112ce1b080d618f67fe08884bJorim Jaggi                mTouchDisabled?"T":"f"
107837a38aaecb5045906ade6d1c970f106a028cbaf5Daniel Sandler        ));
107937a38aaecb5045906ade6d1c970f106a028cbaf5Daniel Sandler    }
10803c4635c19997748e0b21453f3462e347905534e0Selim Cinek
10813c4635c19997748e0b21453f3462e347905534e0Selim Cinek    public abstract void resetViews();
10822580a976ec93a01ed00fae51364ad872bc591d95Jorim Jaggi
10832580a976ec93a01ed00fae51364ad872bc591d95Jorim Jaggi    protected abstract float getPeekHeight();
108430c305ce6283ce1380ad91ef0d221696b32d5a6bJorim Jaggi
108530c305ce6283ce1380ad91ef0d221696b32d5a6bJorim Jaggi    protected abstract float getCannedFlingDurationFactor();
10864b04a3a1649018e7f0fe11136d0b012a9eeb44eaJorim Jaggi
10874b04a3a1649018e7f0fe11136d0b012a9eeb44eaJorim Jaggi    /**
10884b04a3a1649018e7f0fe11136d0b012a9eeb44eaJorim Jaggi     * @return whether "Clear all" button will be visible when the panel is fully expanded
10894b04a3a1649018e7f0fe11136d0b012a9eeb44eaJorim Jaggi     */
10904b04a3a1649018e7f0fe11136d0b012a9eeb44eaJorim Jaggi    protected abstract boolean fullyExpandedClearAllVisible();
10914b04a3a1649018e7f0fe11136d0b012a9eeb44eaJorim Jaggi
10924b04a3a1649018e7f0fe11136d0b012a9eeb44eaJorim Jaggi    protected abstract boolean isClearAllVisible();
10934b04a3a1649018e7f0fe11136d0b012a9eeb44eaJorim Jaggi
10944b04a3a1649018e7f0fe11136d0b012a9eeb44eaJorim Jaggi    /**
10954b04a3a1649018e7f0fe11136d0b012a9eeb44eaJorim Jaggi     * @return the height of the clear all button, in pixels
10964b04a3a1649018e7f0fe11136d0b012a9eeb44eaJorim Jaggi     */
10974b04a3a1649018e7f0fe11136d0b012a9eeb44eaJorim Jaggi    protected abstract int getClearAllHeight();
1098b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek
1099b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek    public void setHeadsUpManager(HeadsUpManager headsUpManager) {
1100b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek        mHeadsUpManager = headsUpManager;
1101b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek    }
110208d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler}
1103