blob: e30a5c2b50f79bc7a048243035b06dbffa091dcb [file] [log] [blame]
Daniel Sandler08d05e32012-08-08 16:39:54 -04001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.systemui.statusbar.phone;
18
Jorim Jaggid7daab72014-05-06 22:22:20 +020019import android.animation.Animator;
20import android.animation.AnimatorListenerAdapter;
Jorim Jaggi75c95042014-05-16 19:09:59 +020021import android.animation.ObjectAnimator;
Jorim Jaggidbc3dce2014-08-01 01:16:36 +020022import android.animation.PropertyValuesHolder;
Jorim Jaggid7daab72014-05-06 22:22:20 +020023import android.animation.ValueAnimator;
Daniel Sandler08d05e32012-08-08 16:39:54 -040024import android.content.Context;
Selim Cinek4c6969a2014-05-26 19:22:17 +020025import android.content.res.Configuration;
Jorim Jaggi58bef332014-11-21 18:10:32 +010026import android.graphics.Canvas;
27import android.graphics.Color;
28import android.graphics.Paint;
Daniel Sandler08d05e32012-08-08 16:39:54 -040029import android.util.AttributeSet;
Jorim Jaggi3afddce2014-08-14 20:44:43 +020030import android.util.MathUtils;
Daniel Sandler040c2e42012-10-17 00:56:33 -040031import android.view.MotionEvent;
Jorim Jaggid7daab72014-05-06 22:22:20 +020032import android.view.VelocityTracker;
Daniel Sandler13522a22012-09-27 14:46:58 -040033import android.view.View;
Jorim Jaggi75c95042014-05-16 19:09:59 +020034import android.view.ViewTreeObserver;
Casey Burkhardt23b0a4e2013-04-29 12:18:32 -070035import android.view.accessibility.AccessibilityEvent;
Jorim Jaggi75c95042014-05-16 19:09:59 +020036import android.view.animation.AnimationUtils;
37import android.view.animation.Interpolator;
John Spurlock7e6809a2014-08-06 16:03:14 -040038import android.widget.FrameLayout;
Selim Cinekf99d0002014-06-13 07:36:01 +020039import android.widget.TextView;
Jorim Jaggi06d551a2014-09-02 15:55:57 +020040
Jorim Jaggid09def7512014-09-02 18:36:45 +020041import com.android.keyguard.KeyguardStatusView;
Christoph Studerb0183992014-12-22 21:02:26 +010042import com.android.systemui.EventLogTags;
43import com.android.systemui.EventLogConstants;
Chet Haase4d179dc2012-08-22 07:14:42 -070044import com.android.systemui.R;
Jorim Jaggi8bc983e2014-12-10 17:45:50 +010045import com.android.systemui.qs.QSContainer;
Jorim Jaggie65e3102014-07-01 22:00:50 +020046import com.android.systemui.qs.QSPanel;
Jorim Jaggibe565df2014-04-28 17:51:23 +020047import com.android.systemui.statusbar.ExpandableView;
Jorim Jaggi87cd5e72014-05-12 23:29:10 +020048import com.android.systemui.statusbar.FlingAnimationUtils;
Daniel Sandler151f00d2012-10-02 22:33:08 -040049import com.android.systemui.statusbar.GestureRecorder;
Selim Cinekbaa23272014-07-08 18:01:07 +020050import com.android.systemui.statusbar.KeyguardAffordanceView;
Jorim Jaggiecbab362014-04-23 16:13:15 +020051import com.android.systemui.statusbar.StatusBarState;
Jorim Jaggibf1899e2014-08-07 02:04:18 +020052import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
Selim Cinekb6d85eb2014-03-28 20:21:01 +010053import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
Jorim Jaggi75c95042014-05-16 19:09:59 +020054import com.android.systemui.statusbar.stack.StackStateAnimator;
Daniel Sandler08d05e32012-08-08 16:39:54 -040055
Jorim Jaggibe565df2014-04-28 17:51:23 +020056public class NotificationPanelView extends PanelView implements
Jorim Jaggid7daab72014-05-06 22:22:20 +020057 ExpandableView.OnHeightChangedListener, ObservableScrollView.Listener,
Jorim Jaggi290600a2014-05-30 17:02:20 +020058 View.OnClickListener, NotificationStackScrollLayout.OnOverscrollTopChangedListener,
Selim Cinek3a9c10a2014-10-28 14:21:10 +010059 KeyguardAffordanceHelper.Callback, NotificationStackScrollLayout.OnEmptySpaceClickListener {
Chet Haase4d179dc2012-08-22 07:14:42 -070060
Jorim Jaggi58bef332014-11-21 18:10:32 +010061 private static final boolean DEBUG = false;
62
Selim Cinekf99d0002014-06-13 07:36:01 +020063 // Cap and total height of Roboto font. Needs to be adjusted when font for the big clock is
64 // changed.
65 private static final int CAP_HEIGHT = 1456;
66 private static final int FONT_HEIGHT = 2163;
67
Jorim Jaggi1d49ec92014-08-25 18:44:01 +020068 private static final float HEADER_RUBBERBAND_FACTOR = 2.05f;
Jorim Jaggi8dd95e02014-06-03 16:19:33 +020069 private static final float LOCK_ICON_ACTIVE_SCALE = 1.2f;
Selim Cineka02fe522014-05-30 17:01:21 +020070
Jorim Jaggi16423aa2014-10-28 11:42:58 +010071 public static final long DOZE_ANIMATION_DURATION = 700;
John Spurlock8b12f222014-09-09 11:54:11 -040072
Selim Cinekbaa23272014-07-08 18:01:07 +020073 private KeyguardAffordanceHelper mAfforanceHelper;
Jorim Jaggid7daab72014-05-06 22:22:20 +020074 private StatusBarHeaderView mHeader;
Jorim Jaggibf1899e2014-08-07 02:04:18 +020075 private KeyguardUserSwitcher mKeyguardUserSwitcher;
Jorim Jaggi4538027d2014-07-30 15:43:13 +020076 private KeyguardStatusBarView mKeyguardStatusBar;
Jorim Jaggi8bc983e2014-12-10 17:45:50 +010077 private QSContainer mQsContainer;
Jorim Jaggie65e3102014-07-01 22:00:50 +020078 private QSPanel mQsPanel;
Jorim Jaggid09def7512014-09-02 18:36:45 +020079 private KeyguardStatusView mKeyguardStatusView;
Jorim Jaggid7daab72014-05-06 22:22:20 +020080 private ObservableScrollView mScrollView;
Selim Cinekf99d0002014-06-13 07:36:01 +020081 private TextView mClockView;
Jorim Jaggi54045422014-07-03 18:30:40 +020082 private View mReserveNotificationSpace;
Jorim Jaggidd5b8862014-08-05 21:04:39 +020083 private View mQsNavbarScrim;
John Spurlock7e6809a2014-08-06 16:03:14 -040084 private View mNotificationContainerParent;
Selim Cinekb6d85eb2014-03-28 20:21:01 +010085 private NotificationStackScrollLayout mNotificationStackScroller;
Jorim Jaggi8c1a44b2014-04-29 19:04:02 +020086 private int mNotificationTopPadding;
Jorim Jaggi98fb09c2014-05-01 22:40:56 +020087 private boolean mAnimateNextTopPaddingChange;
Chet Haase4d179dc2012-08-22 07:14:42 -070088
Jorim Jaggid7daab72014-05-06 22:22:20 +020089 private int mTrackingPointer;
90 private VelocityTracker mVelocityTracker;
Selim Cinek4c6969a2014-05-26 19:22:17 +020091 private boolean mQsTracking;
Jorim Jaggifc1a8242014-05-12 19:30:05 +020092
93 /**
Brian Colonnad45c6d42014-08-01 18:04:40 -040094 * Handles launching the secure camera properly even when other applications may be using the
95 * camera hardware.
96 */
97 private SecureCameraLaunchManager mSecureCameraLaunchManager;
98
99 /**
Jorim Jaggidc96d632014-07-01 18:48:52 +0200100 * If set, the ongoing touch gesture might both trigger the expansion in {@link PanelView} and
101 * the expansion for quick settings.
102 */
103 private boolean mConflictingQsExpansionGesture;
104
105 /**
Jorim Jaggifc1a8242014-05-12 19:30:05 +0200106 * Whether we are currently handling a motion gesture in #onInterceptTouchEvent, but haven't
107 * intercepted yet.
108 */
109 private boolean mIntercepting;
Jorim Jaggid7daab72014-05-06 22:22:20 +0200110 private boolean mQsExpanded;
Jorim Jaggi30c305c2014-07-01 23:34:41 +0200111 private boolean mQsExpandedWhenExpandingStarted;
John Spurlockbc3a5e92014-05-30 16:20:05 -0400112 private boolean mQsFullyExpanded;
Jorim Jaggif62f2bb2014-05-25 22:28:41 +0200113 private boolean mKeyguardShowing;
John Spurlockd54da8a2014-08-03 23:23:52 -0400114 private boolean mDozing;
Jorim Jaggi56306252014-07-03 00:40:09 +0200115 private int mStatusBarState;
Jorim Jaggid7daab72014-05-06 22:22:20 +0200116 private float mInitialHeightOnTouch;
117 private float mInitialTouchX;
118 private float mInitialTouchY;
Jorim Jaggifc1a8242014-05-12 19:30:05 +0200119 private float mLastTouchX;
120 private float mLastTouchY;
Jorim Jaggid7daab72014-05-06 22:22:20 +0200121 private float mQsExpansionHeight;
122 private int mQsMinExpansionHeight;
123 private int mQsMaxExpansionHeight;
Jorim Jaggif62f2bb2014-05-25 22:28:41 +0200124 private int mQsPeekHeight;
Jorim Jaggi290600a2014-05-30 17:02:20 +0200125 private boolean mStackScrollerOverscrolling;
Jorim Jaggi475b21d2014-07-01 18:13:24 +0200126 private boolean mQsExpansionFromOverscroll;
Jorim Jaggi11c071a2014-08-14 19:17:11 +0200127 private float mLastOverscroll;
Jorim Jaggid7daab72014-05-06 22:22:20 +0200128 private boolean mQsExpansionEnabled = true;
129 private ValueAnimator mQsExpansionAnimator;
Jorim Jaggi87cd5e72014-05-12 23:29:10 +0200130 private FlingAnimationUtils mFlingAnimationUtils;
Selim Cinek9dbbca82014-05-15 15:23:37 +0200131 private int mStatusBarMinHeight;
Jorim Jaggi8dd95e02014-06-03 16:19:33 +0200132 private boolean mUnlockIconActive;
Jorim Jaggi457cc352014-06-02 22:47:42 +0200133 private int mNotificationsHeaderCollideDistance;
Jorim Jaggi8dd95e02014-06-03 16:19:33 +0200134 private int mUnlockMoveDistance;
Jorim Jaggi48bc36a2014-07-25 23:16:04 +0200135 private float mEmptyDragAmount;
John Spurlock3e04cc82014-05-30 12:34:03 -0400136
Jorim Jaggi75c95042014-05-16 19:09:59 +0200137 private Interpolator mFastOutSlowInInterpolator;
Jorim Jaggi457cc352014-06-02 22:47:42 +0200138 private Interpolator mFastOutLinearInterpolator;
Jorim Jaggi16423aa2014-10-28 11:42:58 +0100139 private Interpolator mDozeAnimationInterpolator;
Jorim Jaggi75c95042014-05-16 19:09:59 +0200140 private ObjectAnimator mClockAnimator;
141 private int mClockAnimationTarget = -1;
Jorim Jaggi7d16bb12014-05-22 04:24:50 +0200142 private int mTopPaddingAdjustment;
143 private KeyguardClockPositionAlgorithm mClockPositionAlgorithm =
144 new KeyguardClockPositionAlgorithm();
145 private KeyguardClockPositionAlgorithm.Result mClockPositionResult =
146 new KeyguardClockPositionAlgorithm.Result();
Selim Cinek4c6969a2014-05-26 19:22:17 +0200147 private boolean mIsExpanding;
Selim Cinekf99d0002014-06-13 07:36:01 +0200148
Selim Cinek4c6969a2014-05-26 19:22:17 +0200149 private boolean mBlockTouches;
Selim Cinekf54090e2014-06-17 17:24:51 -0700150 private int mNotificationScrimWaitDistance;
Jorim Jaggi1e2554b2014-07-10 23:07:00 +0200151 private boolean mTwoFingerQsExpand;
152 private boolean mTwoFingerQsExpandPossible;
Jorim Jaggi56306252014-07-03 00:40:09 +0200153
154 /**
155 * If we are in a panel collapsing motion, we reset scrollY of our scroll view but still
156 * need to take this into account in our panel height calculation.
157 */
158 private int mScrollYOverride = -1;
Jorim Jaggibd003102014-07-04 00:02:42 +0200159 private boolean mQsAnimatorExpand;
Selim Cinekbaa23272014-07-08 18:01:07 +0200160 private boolean mIsLaunchTransitionFinished;
161 private boolean mIsLaunchTransitionRunning;
162 private Runnable mLaunchAnimationEndRunnable;
163 private boolean mOnlyAffordanceInThisMotion;
Jorim Jaggi6ff837a2014-07-31 21:46:39 +0200164 private boolean mKeyguardStatusViewAnimating;
Jorim Jaggidbc3dce2014-08-01 01:16:36 +0200165 private boolean mHeaderAnimatingIn;
166 private ObjectAnimator mQsContainerAnimator;
Jorim Jaggi8bc983e2014-12-10 17:45:50 +0100167 private ValueAnimator mQsSizeChangeAnimator;
Jorim Jaggi069cd032014-05-15 03:09:01 +0200168
Jorim Jaggia2052ea2014-08-05 16:22:30 +0200169 private boolean mShadeEmpty;
170
Jorim Jaggidd5b8862014-08-05 21:04:39 +0200171 private boolean mQsScrimEnabled = true;
Selim Cinek90c94652014-08-18 16:46:22 +0200172 private boolean mLastAnnouncementWasQuickSettings;
Selim Cinek19c8c702014-08-25 22:09:19 +0200173 private boolean mQsTouchAboveFalsingThreshold;
174 private int mQsFalsingThreshold;
Jorim Jaggidd5b8862014-08-05 21:04:39 +0200175
Jorim Jaggi16423aa2014-10-28 11:42:58 +0100176 private float mKeyguardStatusBarAnimateAlpha = 1f;
Jorim Jaggi0a818222014-11-10 19:04:34 +0100177 private int mOldLayoutDirection;
Jorim Jaggi16423aa2014-10-28 11:42:58 +0100178
Daniel Sandler08d05e32012-08-08 16:39:54 -0400179 public NotificationPanelView(Context context, AttributeSet attrs) {
180 super(context, attrs);
Jorim Jaggi58bef332014-11-21 18:10:32 +0100181 setWillNotDraw(!DEBUG);
Daniel Sandler13522a22012-09-27 14:46:58 -0400182 }
Chet Haase4d179dc2012-08-22 07:14:42 -0700183
Daniel Sandler040c2e42012-10-17 00:56:33 -0400184 public void setStatusBar(PhoneStatusBar bar) {
185 mStatusBar = bar;
186 }
187
Daniel Sandler13522a22012-09-27 14:46:58 -0400188 @Override
189 protected void onFinishInflate() {
190 super.onFinishInflate();
Jorim Jaggid7daab72014-05-06 22:22:20 +0200191 mHeader = (StatusBarHeaderView) findViewById(R.id.header);
Jorim Jaggi853b0702014-07-05 04:31:14 +0200192 mHeader.setOnClickListener(this);
Jorim Jaggi4538027d2014-07-30 15:43:13 +0200193 mKeyguardStatusBar = (KeyguardStatusBarView) findViewById(R.id.keyguard_header);
Jorim Jaggid09def7512014-09-02 18:36:45 +0200194 mKeyguardStatusView = (KeyguardStatusView) findViewById(R.id.keyguard_status_view);
Jorim Jaggi8bc983e2014-12-10 17:45:50 +0100195 mQsContainer = (QSContainer) findViewById(R.id.quick_settings_container);
Jorim Jaggie65e3102014-07-01 22:00:50 +0200196 mQsPanel = (QSPanel) findViewById(R.id.quick_settings_panel);
Selim Cinekf99d0002014-06-13 07:36:01 +0200197 mClockView = (TextView) findViewById(R.id.clock_view);
Jorim Jaggid7daab72014-05-06 22:22:20 +0200198 mScrollView = (ObservableScrollView) findViewById(R.id.scroll_view);
199 mScrollView.setListener(this);
Selim Cineke32010a2014-08-20 23:50:41 +0200200 mScrollView.setFocusable(false);
Jorim Jaggi54045422014-07-03 18:30:40 +0200201 mReserveNotificationSpace = findViewById(R.id.reserve_notification_space);
John Spurlock7e6809a2014-08-06 16:03:14 -0400202 mNotificationContainerParent = findViewById(R.id.notification_container_parent);
Selim Cinekb6d85eb2014-03-28 20:21:01 +0100203 mNotificationStackScroller = (NotificationStackScrollLayout)
204 findViewById(R.id.notification_stack_scroller);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200205 mNotificationStackScroller.setOnHeightChangedListener(this);
Jorim Jaggi290600a2014-05-30 17:02:20 +0200206 mNotificationStackScroller.setOverscrollTopChangedListener(this);
Selim Cinek3a9c10a2014-10-28 14:21:10 +0100207 mNotificationStackScroller.setOnEmptySpaceClickListener(this);
Jorim Jaggi56306252014-07-03 00:40:09 +0200208 mNotificationStackScroller.setScrollView(mScrollView);
Jorim Jaggi75c95042014-05-16 19:09:59 +0200209 mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(),
210 android.R.interpolator.fast_out_slow_in);
Jorim Jaggi457cc352014-06-02 22:47:42 +0200211 mFastOutLinearInterpolator = AnimationUtils.loadInterpolator(getContext(),
212 android.R.interpolator.fast_out_linear_in);
Jorim Jaggi16423aa2014-10-28 11:42:58 +0100213 mDozeAnimationInterpolator = AnimationUtils.loadInterpolator(getContext(),
214 android.R.interpolator.linear_out_slow_in);
Selim Cinek4c6969a2014-05-26 19:22:17 +0200215 mKeyguardBottomArea = (KeyguardBottomAreaView) findViewById(R.id.keyguard_bottom_area);
Jorim Jaggidd5b8862014-08-05 21:04:39 +0200216 mQsNavbarScrim = findViewById(R.id.qs_navbar_scrim);
Selim Cinekbaa23272014-07-08 18:01:07 +0200217 mAfforanceHelper = new KeyguardAffordanceHelper(this, getContext());
Brian Colonnad45c6d42014-08-01 18:04:40 -0400218 mSecureCameraLaunchManager =
219 new SecureCameraLaunchManager(getContext(), mKeyguardBottomArea);
John Spurlockbceed062014-08-10 18:04:16 -0400220
221 // recompute internal state when qspanel height changes
222 mQsContainer.addOnLayoutChangeListener(new OnLayoutChangeListener() {
223 @Override
224 public void onLayoutChange(View v, int left, int top, int right,
225 int bottom, int oldLeft, int oldTop, int oldRight,
226 int oldBottom) {
227 final int height = bottom - top;
228 final int oldHeight = oldBottom - oldTop;
229 if (height != oldHeight) {
230 onScrollChanged();
231 }
232 }
233 });
Jorim Jaggi069cd032014-05-15 03:09:01 +0200234 }
235
236 @Override
237 protected void loadDimens() {
238 super.loadDimens();
Jorim Jaggi8c1a44b2014-04-29 19:04:02 +0200239 mNotificationTopPadding = getResources().getDimensionPixelSize(
240 R.dimen.notifications_top_padding);
Jorim Jaggi1d480692014-05-20 19:41:58 +0200241 mFlingAnimationUtils = new FlingAnimationUtils(getContext(), 0.4f);
Selim Cinek9dbbca82014-05-15 15:23:37 +0200242 mStatusBarMinHeight = getResources().getDimensionPixelSize(
243 com.android.internal.R.dimen.status_bar_height);
Jorim Jaggif62f2bb2014-05-25 22:28:41 +0200244 mQsPeekHeight = getResources().getDimensionPixelSize(R.dimen.qs_peek_height);
Jorim Jaggi457cc352014-06-02 22:47:42 +0200245 mNotificationsHeaderCollideDistance =
246 getResources().getDimensionPixelSize(R.dimen.header_notifications_collide_distance);
Jorim Jaggi8dd95e02014-06-03 16:19:33 +0200247 mUnlockMoveDistance = getResources().getDimensionPixelOffset(R.dimen.unlock_move_distance);
Jorim Jaggi7d16bb12014-05-22 04:24:50 +0200248 mClockPositionAlgorithm.loadDimens(getResources());
Selim Cinekf54090e2014-06-17 17:24:51 -0700249 mNotificationScrimWaitDistance =
250 getResources().getDimensionPixelSize(R.dimen.notification_scrim_wait_distance);
Selim Cinek19c8c702014-08-25 22:09:19 +0200251 mQsFalsingThreshold = getResources().getDimensionPixelSize(
252 R.dimen.qs_falsing_threshold);
Jorim Jaggi8c1a44b2014-04-29 19:04:02 +0200253 }
254
John Spurlock7e6809a2014-08-06 16:03:14 -0400255 public void updateResources() {
256 int panelWidth = getResources().getDimensionPixelSize(R.dimen.notification_panel_width);
257 int panelGravity = getResources().getInteger(R.integer.notification_panel_layout_gravity);
258 FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mHeader.getLayoutParams();
259 if (lp.width != panelWidth) {
260 lp.width = panelWidth;
261 lp.gravity = panelGravity;
262 mHeader.setLayoutParams(lp);
263 mHeader.post(mUpdateHeader);
264 }
265
Jorim Jaggibf1899e2014-08-07 02:04:18 +0200266 lp = (FrameLayout.LayoutParams) mNotificationStackScroller.getLayoutParams();
John Spurlock7e6809a2014-08-06 16:03:14 -0400267 if (lp.width != panelWidth) {
268 lp.width = panelWidth;
269 lp.gravity = panelGravity;
Jorim Jaggibf1899e2014-08-07 02:04:18 +0200270 mNotificationStackScroller.setLayoutParams(lp);
271 }
272
273 lp = (FrameLayout.LayoutParams) mScrollView.getLayoutParams();
274 if (lp.width != panelWidth) {
275 lp.width = panelWidth;
276 lp.gravity = panelGravity;
277 mScrollView.setLayoutParams(lp);
John Spurlock7e6809a2014-08-06 16:03:14 -0400278 }
279 }
280
Jorim Jaggi8c1a44b2014-04-29 19:04:02 +0200281 @Override
282 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
283 super.onLayout(changed, left, top, right, bottom);
Jorim Jaggid7daab72014-05-06 22:22:20 +0200284
Selim Cinekf99d0002014-06-13 07:36:01 +0200285 // Update Clock Pivot
286 mKeyguardStatusView.setPivotX(getWidth() / 2);
Jorim Jaggi4538027d2014-07-30 15:43:13 +0200287 mKeyguardStatusView.setPivotY((FONT_HEIGHT - CAP_HEIGHT) / 2048f * mClockView.getTextSize());
Selim Cinekf99d0002014-06-13 07:36:01 +0200288
Jorim Jaggid7daab72014-05-06 22:22:20 +0200289 // Calculate quick setting heights.
Jorim Jaggi8bc983e2014-12-10 17:45:50 +0100290 int oldMaxHeight = mQsMaxExpansionHeight;
Jorim Jaggi61d37f62014-07-30 17:26:55 +0200291 mQsMinExpansionHeight = mKeyguardShowing ? 0 : mHeader.getCollapsedHeight() + mQsPeekHeight;
Jorim Jaggi8bc983e2014-12-10 17:45:50 +0100292 mQsMaxExpansionHeight = mHeader.getExpandedHeight() + mQsContainer.getDesiredHeight();
Selim Cinek237a7012014-09-10 18:12:18 +0200293 positionClockAndNotifications();
Jorim Jaggi8bc983e2014-12-10 17:45:50 +0100294 if (mQsExpanded && mQsFullyExpanded) {
295 mQsExpansionHeight = mQsMaxExpansionHeight;
296 requestScrollerTopPaddingUpdate(false /* animate */);
297 requestPanelHeightUpdate();
298
299 // Size has changed, start an animation.
300 if (mQsMaxExpansionHeight != oldMaxHeight) {
301 startQsSizeChangeAnimation(oldMaxHeight, mQsMaxExpansionHeight);
John Spurlockbc3a5e92014-05-30 16:20:05 -0400302 }
Jorim Jaggi8bc983e2014-12-10 17:45:50 +0100303 } else if (!mQsExpanded) {
Jorim Jaggi11c071a2014-08-14 19:17:11 +0200304 setQsExpansion(mQsMinExpansionHeight + mLastOverscroll);
Jorim Jaggid7daab72014-05-06 22:22:20 +0200305 }
Jorim Jaggi8bc983e2014-12-10 17:45:50 +0100306 mNotificationStackScroller.setStackHeight(getExpandedHeight());
Jorim Jaggi0bc49172014-11-03 15:52:13 +0100307 updateHeader();
Selim Cinek3afd00e2014-08-11 22:32:57 +0200308 mNotificationStackScroller.updateIsSmallScreen(
309 mHeader.getCollapsedHeight() + mQsPeekHeight);
Jorim Jaggi8bc983e2014-12-10 17:45:50 +0100310
311 // If we are running a size change animation, the animation takes care of the height of
312 // the container. However, if we are not animating, we always need to make the QS container
313 // the desired height so when closing the QS detail, it stays smaller after the size change
314 // animation is finished but the detail view is still being animated away (this animation
315 // takes longer than the size change animation).
316 if (mQsSizeChangeAnimator == null) {
317 mQsContainer.setHeightOverride(mQsContainer.getDesiredHeight());
318 }
Jorim Jaggi98fb09c2014-05-01 22:40:56 +0200319 }
320
Brian Colonnad45c6d42014-08-01 18:04:40 -0400321 @Override
322 public void onAttachedToWindow() {
323 mSecureCameraLaunchManager.create();
324 }
325
326 @Override
327 public void onDetachedFromWindow() {
328 mSecureCameraLaunchManager.destroy();
329 }
330
Jorim Jaggi8bc983e2014-12-10 17:45:50 +0100331 private void startQsSizeChangeAnimation(int oldHeight, final int newHeight) {
332 if (mQsSizeChangeAnimator != null) {
333 oldHeight = (int) mQsSizeChangeAnimator.getAnimatedValue();
334 mQsSizeChangeAnimator.cancel();
335 }
336 mQsSizeChangeAnimator = ValueAnimator.ofInt(oldHeight, newHeight);
337 mQsSizeChangeAnimator.setDuration(300);
338 mQsSizeChangeAnimator.setInterpolator(mFastOutSlowInInterpolator);
339 mQsSizeChangeAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
340 @Override
341 public void onAnimationUpdate(ValueAnimator animation) {
342 requestScrollerTopPaddingUpdate(false /* animate */);
343 requestPanelHeightUpdate();
344 int height = (int) mQsSizeChangeAnimator.getAnimatedValue();
345 mQsContainer.setHeightOverride(height - mHeader.getExpandedHeight());
346 }
347 });
348 mQsSizeChangeAnimator.addListener(new AnimatorListenerAdapter() {
349 @Override
350 public void onAnimationEnd(Animator animation) {
351 mQsSizeChangeAnimator = null;
352 }
353 });
354 mQsSizeChangeAnimator.start();
355 }
356
Jorim Jaggi069cd032014-05-15 03:09:01 +0200357 /**
358 * Positions the clock and notifications dynamically depending on how many notifications are
359 * showing.
360 */
361 private void positionClockAndNotifications() {
Selim Cinekf99d0002014-06-13 07:36:01 +0200362 boolean animate = mNotificationStackScroller.isAddOrRemoveAnimationPending();
Selim Cinek1408eb52014-06-02 14:45:38 +0200363 int stackScrollerPadding;
Jorim Jaggi4538027d2014-07-30 15:43:13 +0200364 if (mStatusBarState != StatusBarState.KEYGUARD) {
Jorim Jaggi2580a9762014-06-25 03:08:25 +0200365 int bottom = mHeader.getCollapsedHeight();
Jorim Jaggi4538027d2014-07-30 15:43:13 +0200366 stackScrollerPadding = mStatusBarState == StatusBarState.SHADE
367 ? bottom + mQsPeekHeight + mNotificationTopPadding
368 : mKeyguardStatusBar.getHeight() + mNotificationTopPadding;
Jorim Jaggi7d16bb12014-05-22 04:24:50 +0200369 mTopPaddingAdjustment = 0;
Jorim Jaggi069cd032014-05-15 03:09:01 +0200370 } else {
Jorim Jaggi7d16bb12014-05-22 04:24:50 +0200371 mClockPositionAlgorithm.setup(
372 mStatusBar.getMaxKeyguardNotifications(),
373 getMaxPanelHeight(),
374 getExpandedHeight(),
375 mNotificationStackScroller.getNotGoneChildCount(),
376 getHeight(),
Jorim Jaggi48bc36a2014-07-25 23:16:04 +0200377 mKeyguardStatusView.getHeight(),
378 mEmptyDragAmount);
Jorim Jaggi7d16bb12014-05-22 04:24:50 +0200379 mClockPositionAlgorithm.run(mClockPositionResult);
Selim Cinekf99d0002014-06-13 07:36:01 +0200380 if (animate || mClockAnimator != null) {
Jorim Jaggi7d16bb12014-05-22 04:24:50 +0200381 startClockAnimation(mClockPositionResult.clockY);
Jorim Jaggi75c95042014-05-16 19:09:59 +0200382 } else {
Jorim Jaggi7d16bb12014-05-22 04:24:50 +0200383 mKeyguardStatusView.setY(mClockPositionResult.clockY);
Jorim Jaggi75c95042014-05-16 19:09:59 +0200384 }
Selim Cinekf99d0002014-06-13 07:36:01 +0200385 updateClock(mClockPositionResult.clockAlpha, mClockPositionResult.clockScale);
Selim Cinek1408eb52014-06-02 14:45:38 +0200386 stackScrollerPadding = mClockPositionResult.stackScrollerPadding;
Jorim Jaggi7d16bb12014-05-22 04:24:50 +0200387 mTopPaddingAdjustment = mClockPositionResult.stackScrollerPaddingAdjustment;
Jorim Jaggi069cd032014-05-15 03:09:01 +0200388 }
Selim Cinek1408eb52014-06-02 14:45:38 +0200389 mNotificationStackScroller.setIntrinsicPadding(stackScrollerPadding);
Selim Cinekf99d0002014-06-13 07:36:01 +0200390 requestScrollerTopPaddingUpdate(animate);
Jorim Jaggi069cd032014-05-15 03:09:01 +0200391 }
392
Jorim Jaggi75c95042014-05-16 19:09:59 +0200393 private void startClockAnimation(int y) {
394 if (mClockAnimationTarget == y) {
395 return;
396 }
397 mClockAnimationTarget = y;
398 getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
399 @Override
400 public boolean onPreDraw() {
401 getViewTreeObserver().removeOnPreDrawListener(this);
402 if (mClockAnimator != null) {
403 mClockAnimator.removeAllListeners();
404 mClockAnimator.cancel();
405 }
Jorim Jaggia1b1c7a2014-06-03 16:29:05 +0200406 mClockAnimator = ObjectAnimator
407 .ofFloat(mKeyguardStatusView, View.Y, mClockAnimationTarget);
Jorim Jaggi75c95042014-05-16 19:09:59 +0200408 mClockAnimator.setInterpolator(mFastOutSlowInInterpolator);
409 mClockAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
410 mClockAnimator.addListener(new AnimatorListenerAdapter() {
411 @Override
412 public void onAnimationEnd(Animator animation) {
413 mClockAnimator = null;
414 mClockAnimationTarget = -1;
415 }
416 });
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200417 mClockAnimator.start();
Jorim Jaggi75c95042014-05-16 19:09:59 +0200418 return true;
419 }
420 });
421 }
422
Selim Cinekf99d0002014-06-13 07:36:01 +0200423 private void updateClock(float alpha, float scale) {
Jorim Jaggi6ff837a2014-07-31 21:46:39 +0200424 if (!mKeyguardStatusViewAnimating) {
425 mKeyguardStatusView.setAlpha(alpha);
426 }
Selim Cinekf99d0002014-06-13 07:36:01 +0200427 mKeyguardStatusView.setScaleX(scale);
428 mKeyguardStatusView.setScaleY(scale);
Jorim Jaggi069cd032014-05-15 03:09:01 +0200429 }
430
Jorim Jaggidbc3dce2014-08-01 01:16:36 +0200431 public void animateToFullShade(long delay) {
Jorim Jaggi98fb09c2014-05-01 22:40:56 +0200432 mAnimateNextTopPaddingChange = true;
Jorim Jaggidbc3dce2014-08-01 01:16:36 +0200433 mNotificationStackScroller.goToFullShade(delay);
Jorim Jaggi98fb09c2014-05-01 22:40:56 +0200434 requestLayout();
Daniel Sandler08d05e32012-08-08 16:39:54 -0400435 }
436
Jorim Jaggid7daab72014-05-06 22:22:20 +0200437 public void setQsExpansionEnabled(boolean qsExpansionEnabled) {
438 mQsExpansionEnabled = qsExpansionEnabled;
Jorim Jaggi18bd04f2014-08-15 00:03:09 +0200439 mHeader.setClickable(qsExpansionEnabled);
Jorim Jaggid7daab72014-05-06 22:22:20 +0200440 }
441
Selim Cinek3c4635c2014-05-29 02:12:47 +0200442 @Override
Selim Cinek4c6969a2014-05-26 19:22:17 +0200443 public void resetViews() {
Selim Cinekbaa23272014-07-08 18:01:07 +0200444 mIsLaunchTransitionFinished = false;
Selim Cinek4c6969a2014-05-26 19:22:17 +0200445 mBlockTouches = false;
Jorim Jaggi8dd95e02014-06-03 16:19:33 +0200446 mUnlockIconActive = false;
Selim Cinekbaa23272014-07-08 18:01:07 +0200447 mAfforanceHelper.reset(true);
Selim Cinek4c6969a2014-05-26 19:22:17 +0200448 closeQs();
Dan Sandlere9a4e902014-07-31 01:06:43 -0400449 mStatusBar.dismissPopups();
Jorim Jaggidbbf45e2014-06-25 21:54:48 +0200450 mNotificationStackScroller.setOverScrollAmount(0f, true /* onTop */, false /* animate */,
451 true /* cancelAnimators */);
Selim Cinek4c6969a2014-05-26 19:22:17 +0200452 }
453
Jorim Jaggid7daab72014-05-06 22:22:20 +0200454 public void closeQs() {
455 cancelAnimation();
456 setQsExpansion(mQsMinExpansionHeight);
457 }
458
Jorim Jaggibd003102014-07-04 00:02:42 +0200459 public void animateCloseQs() {
460 if (mQsExpansionAnimator != null) {
461 if (!mQsAnimatorExpand) {
462 return;
463 }
464 float height = mQsExpansionHeight;
465 mQsExpansionAnimator.cancel();
466 setQsExpansion(height);
467 }
468 flingSettings(0 /* vel */, false);
469 }
470
Jorim Jaggid7daab72014-05-06 22:22:20 +0200471 public void openQs() {
472 cancelAnimation();
473 if (mQsExpansionEnabled) {
474 setQsExpansion(mQsMaxExpansionHeight);
475 }
476 }
477
Daniel Sandler08d05e32012-08-08 16:39:54 -0400478 @Override
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200479 public void fling(float vel, boolean expand) {
Daniel Sandler151f00d2012-10-02 22:33:08 -0400480 GestureRecorder gr = ((PhoneStatusBarView) mBar).mBar.getGestureRecorder();
481 if (gr != null) {
Selim Cinek4c6969a2014-05-26 19:22:17 +0200482 gr.tag("fling " + ((vel > 0) ? "open" : "closed"), "notifications,v=" + vel);
Daniel Sandler151f00d2012-10-02 22:33:08 -0400483 }
Jorim Jaggi8de4311c2014-08-11 22:36:20 +0200484 super.fling(vel, expand);
Daniel Sandler08d05e32012-08-08 16:39:54 -0400485 }
Chet Haase4d179dc2012-08-22 07:14:42 -0700486
Casey Burkhardt23b0a4e2013-04-29 12:18:32 -0700487 @Override
488 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
489 if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
Selim Cinek90c94652014-08-18 16:46:22 +0200490 event.getText().add(getKeyguardOrLockScreenString());
491 mLastAnnouncementWasQuickSettings = false;
Casey Burkhardt23b0a4e2013-04-29 12:18:32 -0700492 return true;
493 }
494
495 return super.dispatchPopulateAccessibilityEvent(event);
496 }
497
Daniel Sandler040c2e42012-10-17 00:56:33 -0400498 @Override
John Spurlock73203eb2014-04-15 16:14:46 -0400499 public boolean onInterceptTouchEvent(MotionEvent event) {
Selim Cinek4c6969a2014-05-26 19:22:17 +0200500 if (mBlockTouches) {
501 return false;
502 }
Selim Cinekbaa23272014-07-08 18:01:07 +0200503 resetDownStates(event);
Jorim Jaggid7daab72014-05-06 22:22:20 +0200504 int pointerIndex = event.findPointerIndex(mTrackingPointer);
505 if (pointerIndex < 0) {
506 pointerIndex = 0;
507 mTrackingPointer = event.getPointerId(pointerIndex);
John Spurlock73203eb2014-04-15 16:14:46 -0400508 }
Jorim Jaggid7daab72014-05-06 22:22:20 +0200509 final float x = event.getX(pointerIndex);
510 final float y = event.getY(pointerIndex);
511
512 switch (event.getActionMasked()) {
513 case MotionEvent.ACTION_DOWN:
Jorim Jaggifc1a8242014-05-12 19:30:05 +0200514 mIntercepting = true;
Jorim Jaggid7daab72014-05-06 22:22:20 +0200515 mInitialTouchY = y;
516 mInitialTouchX = x;
517 initVelocityTracker();
518 trackMovement(event);
Selim Cinek4c6969a2014-05-26 19:22:17 +0200519 if (shouldQuickSettingsIntercept(mInitialTouchX, mInitialTouchY, 0)) {
Jorim Jaggid7daab72014-05-06 22:22:20 +0200520 getParent().requestDisallowInterceptTouchEvent(true);
521 }
Jorim Jaggi54045422014-07-03 18:30:40 +0200522 if (mQsExpansionAnimator != null) {
523 onQsExpansionStarted();
524 mInitialHeightOnTouch = mQsExpansionHeight;
525 mQsTracking = true;
526 mIntercepting = false;
527 mNotificationStackScroller.removeLongPressCallback();
528 }
Jorim Jaggid7daab72014-05-06 22:22:20 +0200529 break;
530 case MotionEvent.ACTION_POINTER_UP:
531 final int upPointer = event.getPointerId(event.getActionIndex());
532 if (mTrackingPointer == upPointer) {
533 // gesture is ongoing, find a new pointer to track
534 final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
535 mTrackingPointer = event.getPointerId(newIndex);
536 mInitialTouchX = event.getX(newIndex);
537 mInitialTouchY = event.getY(newIndex);
538 }
539 break;
540
541 case MotionEvent.ACTION_MOVE:
542 final float h = y - mInitialTouchY;
543 trackMovement(event);
Selim Cinek4c6969a2014-05-26 19:22:17 +0200544 if (mQsTracking) {
Jorim Jaggifc1a8242014-05-12 19:30:05 +0200545
546 // Already tracking because onOverscrolled was called. We need to update here
547 // so we don't stop for a frame until the next touch event gets handled in
548 // onTouchEvent.
549 setQsExpansion(h + mInitialHeightOnTouch);
550 trackMovement(event);
551 mIntercepting = false;
552 return true;
553 }
Jorim Jaggid7daab72014-05-06 22:22:20 +0200554 if (Math.abs(h) > mTouchSlop && Math.abs(h) > Math.abs(x - mInitialTouchX)
Selim Cinek4c6969a2014-05-26 19:22:17 +0200555 && shouldQuickSettingsIntercept(mInitialTouchX, mInitialTouchY, h)) {
Jorim Jaggi58bef332014-11-21 18:10:32 +0100556 mQsTracking = true;
Jorim Jaggid7daab72014-05-06 22:22:20 +0200557 onQsExpansionStarted();
558 mInitialHeightOnTouch = mQsExpansionHeight;
559 mInitialTouchY = y;
560 mInitialTouchX = x;
Jorim Jaggifc1a8242014-05-12 19:30:05 +0200561 mIntercepting = false;
Selim Cinek1408eb52014-06-02 14:45:38 +0200562 mNotificationStackScroller.removeLongPressCallback();
Jorim Jaggid7daab72014-05-06 22:22:20 +0200563 return true;
564 }
565 break;
Jorim Jaggifc1a8242014-05-12 19:30:05 +0200566
567 case MotionEvent.ACTION_CANCEL:
568 case MotionEvent.ACTION_UP:
Jorim Jaggic9a52ab2014-05-12 23:46:19 +0200569 trackMovement(event);
Selim Cinek4c6969a2014-05-26 19:22:17 +0200570 if (mQsTracking) {
Jorim Jaggiaea80f42014-11-10 22:41:54 +0100571 flingQsWithCurrentVelocity(
572 event.getActionMasked() == MotionEvent.ACTION_CANCEL);
Selim Cinek4c6969a2014-05-26 19:22:17 +0200573 mQsTracking = false;
Jorim Jaggic9a52ab2014-05-12 23:46:19 +0200574 }
Jorim Jaggifc1a8242014-05-12 19:30:05 +0200575 mIntercepting = false;
576 break;
Jorim Jaggid7daab72014-05-06 22:22:20 +0200577 }
Jorim Jaggi06a0c3a2014-10-29 17:17:21 +0100578 return super.onInterceptTouchEvent(event);
John Spurlock73203eb2014-04-15 16:14:46 -0400579 }
580
Selim Cinekab1dc952014-10-30 20:20:29 +0100581 @Override
582 protected boolean isInContentBounds(float x, float y) {
583 float yTransformed = y - mNotificationStackScroller.getY();
584 float stackScrollerX = mNotificationStackScroller.getX();
585 return mNotificationStackScroller.isInContentBounds(yTransformed) && stackScrollerX < x
586 && x < stackScrollerX + mNotificationStackScroller.getWidth();
587 }
588
Selim Cinekbaa23272014-07-08 18:01:07 +0200589 private void resetDownStates(MotionEvent event) {
590 if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
591 mOnlyAffordanceInThisMotion = false;
Selim Cinek19c8c702014-08-25 22:09:19 +0200592 mQsTouchAboveFalsingThreshold = mQsFullyExpanded;
Selim Cinekbaa23272014-07-08 18:01:07 +0200593 }
594 }
595
John Spurlock73203eb2014-04-15 16:14:46 -0400596 @Override
Jorim Jaggifc1a8242014-05-12 19:30:05 +0200597 public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
598
Jorim Jaggice50b812014-05-24 16:29:57 +0200599 // Block request when interacting with the scroll view so we can still intercept the
600 // scrolling when QS is expanded.
Jorim Jaggi3f48f462014-07-08 16:53:29 +0200601 if (mScrollView.isHandlingTouchEvent()) {
Jorim Jaggice50b812014-05-24 16:29:57 +0200602 return;
Jorim Jaggifc1a8242014-05-12 19:30:05 +0200603 }
Jorim Jaggice50b812014-05-24 16:29:57 +0200604 super.requestDisallowInterceptTouchEvent(disallowIntercept);
Jorim Jaggifc1a8242014-05-12 19:30:05 +0200605 }
606
Jorim Jaggiaea80f42014-11-10 22:41:54 +0100607 private void flingQsWithCurrentVelocity(boolean isCancelMotionEvent) {
Jorim Jaggic9a52ab2014-05-12 23:46:19 +0200608 float vel = getCurrentVelocity();
Jorim Jaggiaea80f42014-11-10 22:41:54 +0100609 flingSettings(vel, flingExpandsQs(vel) && !isCancelMotionEvent);
Jorim Jaggic9a52ab2014-05-12 23:46:19 +0200610 }
611
Jorim Jaggidc96d632014-07-01 18:48:52 +0200612 private boolean flingExpandsQs(float vel) {
Selim Cinek5386fb32014-09-03 16:37:36 +0200613 if (isBelowFalsingThreshold()) {
Selim Cinek19c8c702014-08-25 22:09:19 +0200614 return false;
615 }
Jorim Jaggidc96d632014-07-01 18:48:52 +0200616 if (Math.abs(vel) < mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
617 return getQsExpansionFraction() > 0.5f;
618 } else {
619 return vel > 0;
620 }
621 }
622
Selim Cinek5386fb32014-09-03 16:37:36 +0200623 private boolean isBelowFalsingThreshold() {
Selim Cinekcb2b6732014-09-05 16:17:22 +0200624 return !mQsTouchAboveFalsingThreshold && mStatusBarState == StatusBarState.KEYGUARD;
Selim Cinek5386fb32014-09-03 16:37:36 +0200625 }
626
Jorim Jaggidc96d632014-07-01 18:48:52 +0200627 private float getQsExpansionFraction() {
Jorim Jaggi11c071a2014-08-14 19:17:11 +0200628 return Math.min(1f, (mQsExpansionHeight - mQsMinExpansionHeight)
629 / (getTempQsMaxExpansion() - mQsMinExpansionHeight));
Jorim Jaggidc96d632014-07-01 18:48:52 +0200630 }
Jorim Jaggi54045422014-07-03 18:30:40 +0200631
Jorim Jaggifc1a8242014-05-12 19:30:05 +0200632 @Override
Daniel Sandler040c2e42012-10-17 00:56:33 -0400633 public boolean onTouchEvent(MotionEvent event) {
Selim Cinek4c6969a2014-05-26 19:22:17 +0200634 if (mBlockTouches) {
635 return false;
636 }
Selim Cinekbaa23272014-07-08 18:01:07 +0200637 resetDownStates(event);
Jorim Jaggib3f0a2f2014-06-02 19:29:39 +0200638 if ((!mIsExpanding || mHintAnimationRunning)
639 && !mQsExpanded
640 && mStatusBar.getBarState() != StatusBarState.SHADE) {
Selim Cinekbaa23272014-07-08 18:01:07 +0200641 mAfforanceHelper.onTouchEvent(event);
642 }
643 if (mOnlyAffordanceInThisMotion) {
644 return true;
Selim Cinek4c6969a2014-05-26 19:22:17 +0200645 }
Jorim Jaggidc96d632014-07-01 18:48:52 +0200646 if (event.getActionMasked() == MotionEvent.ACTION_DOWN && getExpandedFraction() == 1f
Jorim Jaggi18bd04f2014-08-15 00:03:09 +0200647 && mStatusBar.getBarState() != StatusBarState.KEYGUARD && !mQsExpanded
648 && mQsExpansionEnabled) {
Jorim Jaggid7daab72014-05-06 22:22:20 +0200649
Jorim Jaggidc96d632014-07-01 18:48:52 +0200650 // Down in the empty area while fully expanded - go to QS.
651 mQsTracking = true;
652 mConflictingQsExpansionGesture = true;
653 onQsExpansionStarted();
654 mInitialHeightOnTouch = mQsExpansionHeight;
655 mInitialTouchY = event.getX();
656 mInitialTouchX = event.getY();
657 }
Jorim Jaggi853b0702014-07-05 04:31:14 +0200658 if (mExpandedHeight != 0) {
659 handleQsDown(event);
660 }
Jorim Jaggie0640dd2014-08-05 23:12:40 +0200661 if (!mTwoFingerQsExpand && mQsTracking) {
Jorim Jaggidc96d632014-07-01 18:48:52 +0200662 onQsTouch(event);
663 if (!mConflictingQsExpansionGesture) {
664 return true;
665 }
666 }
667 if (event.getActionMasked() == MotionEvent.ACTION_CANCEL
668 || event.getActionMasked() == MotionEvent.ACTION_UP) {
669 mConflictingQsExpansionGesture = false;
670 }
Jorim Jaggi18bd04f2014-08-15 00:03:09 +0200671 if (event.getActionMasked() == MotionEvent.ACTION_DOWN && mExpandedHeight == 0
672 && mQsExpansionEnabled) {
Jorim Jaggi1e2554b2014-07-10 23:07:00 +0200673 mTwoFingerQsExpandPossible = true;
674 }
675 if (mTwoFingerQsExpandPossible && event.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN
676 && event.getPointerCount() == 2
677 && event.getY(event.getActionIndex()) < mStatusBarMinHeight) {
678 mTwoFingerQsExpand = true;
679 requestPanelHeightUpdate();
Jorim Jaggi8599a332014-08-14 21:44:23 +0200680
681 // Normally, we start listening when the panel is expanded, but here we need to start
682 // earlier so the state is already up to date when dragging down.
683 setListening(true);
Jorim Jaggi1e2554b2014-07-10 23:07:00 +0200684 }
Selim Cinek4c6969a2014-05-26 19:22:17 +0200685 super.onTouchEvent(event);
686 return true;
687 }
688
Jorim Jaggie0640dd2014-08-05 23:12:40 +0200689 private boolean isInQsArea(float x, float y) {
Jorim Jaggi06a0c3a2014-10-29 17:17:21 +0100690 return (x >= mScrollView.getLeft() && x <= mScrollView.getRight()) &&
691 (y <= mNotificationStackScroller.getBottomMostNotificationBottom()
692 || y <= mQsContainer.getY() + mQsContainer.getHeight());
Jorim Jaggie0640dd2014-08-05 23:12:40 +0200693 }
694
Jorim Jaggi853b0702014-07-05 04:31:14 +0200695 private void handleQsDown(MotionEvent event) {
696 if (event.getActionMasked() == MotionEvent.ACTION_DOWN
Jorim Jaggie0640dd2014-08-05 23:12:40 +0200697 && shouldQuickSettingsIntercept(event.getX(), event.getY(), -1)) {
Jorim Jaggi853b0702014-07-05 04:31:14 +0200698 mQsTracking = true;
699 onQsExpansionStarted();
700 mInitialHeightOnTouch = mQsExpansionHeight;
701 mInitialTouchY = event.getX();
702 mInitialTouchX = event.getY();
Jorim Jaggi8599a332014-08-14 21:44:23 +0200703
704 // If we interrupt an expansion gesture here, make sure to update the state correctly.
705 if (mIsExpanding) {
706 onExpandingFinished();
707 }
Jorim Jaggi853b0702014-07-05 04:31:14 +0200708 }
709 }
710
Selim Cinek4c6969a2014-05-26 19:22:17 +0200711 @Override
Jorim Jaggidc96d632014-07-01 18:48:52 +0200712 protected boolean flingExpands(float vel, float vectorVel) {
713 boolean expands = super.flingExpands(vel, vectorVel);
714
715 // If we are already running a QS expansion, make sure that we keep the panel open.
716 if (mQsExpansionAnimator != null) {
717 expands = true;
718 }
719 return expands;
720 }
721
722 @Override
Selim Cinek4c6969a2014-05-26 19:22:17 +0200723 protected boolean hasConflictingGestures() {
724 return mStatusBar.getBarState() != StatusBarState.SHADE;
725 }
726
Jorim Jaggidc96d632014-07-01 18:48:52 +0200727 private void onQsTouch(MotionEvent event) {
Selim Cinek4c6969a2014-05-26 19:22:17 +0200728 int pointerIndex = event.findPointerIndex(mTrackingPointer);
729 if (pointerIndex < 0) {
730 pointerIndex = 0;
731 mTrackingPointer = event.getPointerId(pointerIndex);
732 }
733 final float y = event.getY(pointerIndex);
734 final float x = event.getX(pointerIndex);
735
736 switch (event.getActionMasked()) {
737 case MotionEvent.ACTION_DOWN:
738 mQsTracking = true;
739 mInitialTouchY = y;
740 mInitialTouchX = x;
741 onQsExpansionStarted();
742 mInitialHeightOnTouch = mQsExpansionHeight;
743 initVelocityTracker();
744 trackMovement(event);
745 break;
746
747 case MotionEvent.ACTION_POINTER_UP:
748 final int upPointer = event.getPointerId(event.getActionIndex());
749 if (mTrackingPointer == upPointer) {
750 // gesture is ongoing, find a new pointer to track
751 final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
752 final float newY = event.getY(newIndex);
753 final float newX = event.getX(newIndex);
754 mTrackingPointer = event.getPointerId(newIndex);
755 mInitialHeightOnTouch = mQsExpansionHeight;
756 mInitialTouchY = newY;
757 mInitialTouchX = newX;
758 }
759 break;
760
761 case MotionEvent.ACTION_MOVE:
762 final float h = y - mInitialTouchY;
763 setQsExpansion(h + mInitialHeightOnTouch);
Selim Cinek34cf5c42014-09-26 15:39:00 +0200764 if (h >= getFalsingThreshold()) {
Selim Cinek19c8c702014-08-25 22:09:19 +0200765 mQsTouchAboveFalsingThreshold = true;
766 }
Selim Cinek4c6969a2014-05-26 19:22:17 +0200767 trackMovement(event);
768 break;
769
770 case MotionEvent.ACTION_UP:
771 case MotionEvent.ACTION_CANCEL:
772 mQsTracking = false;
773 mTrackingPointer = -1;
774 trackMovement(event);
Jorim Jaggidc96d632014-07-01 18:48:52 +0200775 float fraction = getQsExpansionFraction();
776 if ((fraction != 0f || y >= mInitialTouchY)
777 && (fraction != 1f || y <= mInitialTouchY)) {
Jorim Jaggiaea80f42014-11-10 22:41:54 +0100778 flingQsWithCurrentVelocity(
779 event.getActionMasked() == MotionEvent.ACTION_CANCEL);
Jorim Jaggi54045422014-07-03 18:30:40 +0200780 } else {
781 mScrollYOverride = -1;
Jorim Jaggidc96d632014-07-01 18:48:52 +0200782 }
Selim Cinek4c6969a2014-05-26 19:22:17 +0200783 if (mVelocityTracker != null) {
784 mVelocityTracker.recycle();
785 mVelocityTracker = null;
786 }
787 break;
788 }
Jorim Jaggid7daab72014-05-06 22:22:20 +0200789 }
790
Selim Cinek34cf5c42014-09-26 15:39:00 +0200791 private int getFalsingThreshold() {
792 float factor = mStatusBar.isScreenOnComingFromTouch() ? 1.5f : 1.0f;
793 return (int) (mQsFalsingThreshold * factor);
794 }
795
Jorim Jaggifc1a8242014-05-12 19:30:05 +0200796 @Override
Jorim Jaggie0640dd2014-08-05 23:12:40 +0200797 public void onOverscrolled(float lastTouchX, float lastTouchY, int amount) {
798 if (mIntercepting && shouldQuickSettingsIntercept(lastTouchX, lastTouchY,
799 -1 /* yDiff: Not relevant here */)) {
Jorim Jaggi58bef332014-11-21 18:10:32 +0100800 mQsTracking = true;
Jorim Jaggifc1a8242014-05-12 19:30:05 +0200801 onQsExpansionStarted(amount);
802 mInitialHeightOnTouch = mQsExpansionHeight;
803 mInitialTouchY = mLastTouchY;
804 mInitialTouchX = mLastTouchX;
Jorim Jaggifc1a8242014-05-12 19:30:05 +0200805 }
806 }
807
Jorim Jaggi290600a2014-05-30 17:02:20 +0200808 @Override
Jorim Jaggi475b21d2014-07-01 18:13:24 +0200809 public void onOverscrollTopChanged(float amount, boolean isRubberbanded) {
Jorim Jaggi290600a2014-05-30 17:02:20 +0200810 cancelAnimation();
Jorim Jaggi18bd04f2014-08-15 00:03:09 +0200811 if (!mQsExpansionEnabled) {
812 amount = 0f;
813 }
Jorim Jaggi290600a2014-05-30 17:02:20 +0200814 float rounded = amount >= 1f ? amount : 0f;
Jorim Jaggi475b21d2014-07-01 18:13:24 +0200815 mStackScrollerOverscrolling = rounded != 0f && isRubberbanded;
816 mQsExpansionFromOverscroll = rounded != 0f;
Jorim Jaggi11c071a2014-08-14 19:17:11 +0200817 mLastOverscroll = rounded;
Jorim Jaggi290600a2014-05-30 17:02:20 +0200818 updateQsState();
Jorim Jaggi90e0df22014-07-30 01:10:35 +0200819 setQsExpansion(mQsMinExpansionHeight + rounded);
Jorim Jaggi290600a2014-05-30 17:02:20 +0200820 }
821
Selim Cinek1408eb52014-06-02 14:45:38 +0200822 @Override
823 public void flingTopOverscroll(float velocity, boolean open) {
Jorim Jaggib7a33032014-08-20 16:21:36 +0200824 mLastOverscroll = 0f;
Selim Cinek1408eb52014-06-02 14:45:38 +0200825 setQsExpansion(mQsExpansionHeight);
Jorim Jaggi18bd04f2014-08-15 00:03:09 +0200826 flingSettings(!mQsExpansionEnabled && open ? 0f : velocity, open && mQsExpansionEnabled,
827 new Runnable() {
Jorim Jaggi475b21d2014-07-01 18:13:24 +0200828 @Override
829 public void run() {
830 mStackScrollerOverscrolling = false;
831 mQsExpansionFromOverscroll = false;
Jorim Jaggi56306252014-07-03 00:40:09 +0200832 updateQsState();
Jorim Jaggi475b21d2014-07-01 18:13:24 +0200833 }
834 });
Selim Cinek1408eb52014-06-02 14:45:38 +0200835 }
836
Jorim Jaggid7daab72014-05-06 22:22:20 +0200837 private void onQsExpansionStarted() {
Jorim Jaggifc1a8242014-05-12 19:30:05 +0200838 onQsExpansionStarted(0);
839 }
840
841 private void onQsExpansionStarted(int overscrollAmount) {
Jorim Jaggid7daab72014-05-06 22:22:20 +0200842 cancelAnimation();
843
844 // Reset scroll position and apply that position to the expanded height.
Jorim Jaggifc1a8242014-05-12 19:30:05 +0200845 float height = mQsExpansionHeight - mScrollView.getScrollY() - overscrollAmount;
Jorim Jaggi54045422014-07-03 18:30:40 +0200846 if (mScrollView.getScrollY() != 0) {
847 mScrollYOverride = mScrollView.getScrollY();
848 }
Jorim Jaggid7daab72014-05-06 22:22:20 +0200849 mScrollView.scrollTo(0, 0);
850 setQsExpansion(height);
Jorim Jaggi58bef332014-11-21 18:10:32 +0100851 requestPanelHeightUpdate();
Jorim Jaggid7daab72014-05-06 22:22:20 +0200852 }
853
Jorim Jaggif62f2bb2014-05-25 22:28:41 +0200854 private void setQsExpanded(boolean expanded) {
855 boolean changed = mQsExpanded != expanded;
856 if (changed) {
857 mQsExpanded = expanded;
858 updateQsState();
Jorim Jaggi30c305c2014-07-01 23:34:41 +0200859 requestPanelHeightUpdate();
Jorim Jaggi56306252014-07-03 00:40:09 +0200860 mNotificationStackScroller.setInterceptDelegateEnabled(expanded);
Jorim Jaggib690f0d2014-07-03 23:25:44 +0200861 mStatusBar.setQsExpanded(expanded);
Adrian Roos74558c32014-10-17 20:14:23 +0200862 mQsPanel.setExpanded(expanded);
Jorim Jaggif62f2bb2014-05-25 22:28:41 +0200863 }
Jorim Jaggid7daab72014-05-06 22:22:20 +0200864 }
865
Jorim Jaggidbc3dce2014-08-01 01:16:36 +0200866 public void setBarState(int statusBarState, boolean keyguardFadingAway,
867 boolean goingToFullShade) {
Jorim Jaggi56306252014-07-03 00:40:09 +0200868 boolean keyguardShowing = statusBarState == StatusBarState.KEYGUARD
869 || statusBarState == StatusBarState.SHADE_LOCKED;
Jorim Jaggi2580a9762014-06-25 03:08:25 +0200870 if (!mKeyguardShowing && keyguardShowing) {
871 setQsTranslation(mQsExpansionHeight);
872 mHeader.setTranslationY(0f);
873 }
Jorim Jaggidbc3dce2014-08-01 01:16:36 +0200874 setKeyguardStatusViewVisibility(statusBarState, keyguardFadingAway, goingToFullShade);
875 setKeyguardBottomAreaVisibility(statusBarState, goingToFullShade);
876 if (goingToFullShade) {
877 animateKeyguardStatusBarOut();
878 } else {
879 mKeyguardStatusBar.setAlpha(1f);
880 mKeyguardStatusBar.setVisibility(keyguardShowing ? View.VISIBLE : View.INVISIBLE);
881 }
Jorim Jaggi56306252014-07-03 00:40:09 +0200882 mStatusBarState = statusBarState;
Jorim Jaggif62f2bb2014-05-25 22:28:41 +0200883 mKeyguardShowing = keyguardShowing;
884 updateQsState();
Jorim Jaggidbc3dce2014-08-01 01:16:36 +0200885 if (goingToFullShade) {
886 animateHeaderSlidingIn();
887 }
Jorim Jaggif62f2bb2014-05-25 22:28:41 +0200888 }
889
Jorim Jaggi6ff837a2014-07-31 21:46:39 +0200890 private final Runnable mAnimateKeyguardStatusViewInvisibleEndRunnable = new Runnable() {
891 @Override
892 public void run() {
893 mKeyguardStatusViewAnimating = false;
894 mKeyguardStatusView.setVisibility(View.GONE);
895 }
896 };
897
898 private final Runnable mAnimateKeyguardStatusViewVisibleEndRunnable = new Runnable() {
899 @Override
900 public void run() {
901 mKeyguardStatusViewAnimating = false;
902 }
903 };
904
Jorim Jaggidbc3dce2014-08-01 01:16:36 +0200905 private final Animator.AnimatorListener mAnimateHeaderSlidingInListener
906 = new AnimatorListenerAdapter() {
907 @Override
908 public void onAnimationEnd(Animator animation) {
909 mHeaderAnimatingIn = false;
910 mQsContainerAnimator = null;
911 mQsContainer.removeOnLayoutChangeListener(mQsContainerAnimatorUpdater);
912 }
913 };
914
915 private final OnLayoutChangeListener mQsContainerAnimatorUpdater
916 = new OnLayoutChangeListener() {
917 @Override
918 public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
919 int oldTop, int oldRight, int oldBottom) {
920 int oldHeight = oldBottom - oldTop;
921 int height = bottom - top;
922 if (height != oldHeight && mQsContainerAnimator != null) {
923 PropertyValuesHolder[] values = mQsContainerAnimator.getValues();
924 float newEndValue = mHeader.getCollapsedHeight() + mQsPeekHeight - height - top;
925 float newStartValue = -height - top;
926 values[0].setFloatValues(newStartValue, newEndValue);
927 mQsContainerAnimator.setCurrentPlayTime(mQsContainerAnimator.getCurrentPlayTime());
928 }
929 }
930 };
931
932 private final ViewTreeObserver.OnPreDrawListener mStartHeaderSlidingIn
933 = new ViewTreeObserver.OnPreDrawListener() {
934 @Override
935 public boolean onPreDraw() {
936 getViewTreeObserver().removeOnPreDrawListener(this);
937 mHeader.setTranslationY(-mHeader.getCollapsedHeight() - mQsPeekHeight);
938 mHeader.animate()
939 .translationY(0f)
940 .setStartDelay(mStatusBar.calculateGoingToFullShadeDelay())
941 .setDuration(StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE)
942 .setInterpolator(mFastOutSlowInInterpolator)
943 .start();
944 mQsContainer.setY(-mQsContainer.getHeight());
945 mQsContainerAnimator = ObjectAnimator.ofFloat(mQsContainer, View.TRANSLATION_Y,
946 mQsContainer.getTranslationY(),
947 mHeader.getCollapsedHeight() + mQsPeekHeight - mQsContainer.getHeight()
948 - mQsContainer.getTop());
949 mQsContainerAnimator.setStartDelay(mStatusBar.calculateGoingToFullShadeDelay());
950 mQsContainerAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE);
951 mQsContainerAnimator.setInterpolator(mFastOutSlowInInterpolator);
952 mQsContainerAnimator.addListener(mAnimateHeaderSlidingInListener);
953 mQsContainerAnimator.start();
954 mQsContainer.addOnLayoutChangeListener(mQsContainerAnimatorUpdater);
955 return true;
956 }
957 };
958
959 private void animateHeaderSlidingIn() {
960 mHeaderAnimatingIn = true;
961 getViewTreeObserver().addOnPreDrawListener(mStartHeaderSlidingIn);
962
963 }
964
965 private final Runnable mAnimateKeyguardStatusBarInvisibleEndRunnable = new Runnable() {
966 @Override
967 public void run() {
968 mKeyguardStatusBar.setVisibility(View.INVISIBLE);
Jorim Jaggi16423aa2014-10-28 11:42:58 +0100969 mKeyguardStatusBar.setAlpha(1f);
970 mKeyguardStatusBarAnimateAlpha = 1f;
Jorim Jaggidbc3dce2014-08-01 01:16:36 +0200971 }
972 };
973
974 private void animateKeyguardStatusBarOut() {
975 mKeyguardStatusBar.animate()
976 .alpha(0f)
977 .setStartDelay(mStatusBar.getKeyguardFadingAwayDelay())
978 .setDuration(mStatusBar.getKeyguardFadingAwayDuration()/2)
979 .setInterpolator(PhoneStatusBar.ALPHA_OUT)
Jorim Jaggi16423aa2014-10-28 11:42:58 +0100980 .setUpdateListener(mStatusBarAnimateAlphaListener)
Jorim Jaggidbc3dce2014-08-01 01:16:36 +0200981 .withEndAction(mAnimateKeyguardStatusBarInvisibleEndRunnable)
982 .start();
983 }
984
Jorim Jaggi16423aa2014-10-28 11:42:58 +0100985 private final ValueAnimator.AnimatorUpdateListener mStatusBarAnimateAlphaListener =
986 new ValueAnimator.AnimatorUpdateListener() {
987 @Override
988 public void onAnimationUpdate(ValueAnimator animation) {
989 mKeyguardStatusBarAnimateAlpha = mKeyguardStatusBar.getAlpha();
990 }
991 };
992
993 private void animateKeyguardStatusBarIn() {
994 mKeyguardStatusBar.setVisibility(View.VISIBLE);
995 mKeyguardStatusBar.setAlpha(0f);
996 mKeyguardStatusBar.animate()
997 .alpha(1f)
998 .setStartDelay(0)
999 .setDuration(DOZE_ANIMATION_DURATION)
1000 .setInterpolator(mDozeAnimationInterpolator)
1001 .setUpdateListener(mStatusBarAnimateAlphaListener)
1002 .start();
1003 }
1004
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001005 private final Runnable mAnimateKeyguardBottomAreaInvisibleEndRunnable = new Runnable() {
1006 @Override
1007 public void run() {
1008 mKeyguardBottomArea.setVisibility(View.GONE);
1009 }
1010 };
1011
1012 private void setKeyguardBottomAreaVisibility(int statusBarState,
1013 boolean goingToFullShade) {
1014 if (goingToFullShade) {
1015 mKeyguardBottomArea.animate().cancel();
1016 mKeyguardBottomArea.animate()
1017 .alpha(0f)
1018 .setStartDelay(mStatusBar.getKeyguardFadingAwayDelay())
1019 .setDuration(mStatusBar.getKeyguardFadingAwayDuration()/2)
1020 .setInterpolator(PhoneStatusBar.ALPHA_OUT)
1021 .withEndAction(mAnimateKeyguardBottomAreaInvisibleEndRunnable)
1022 .start();
1023 } else if (statusBarState == StatusBarState.KEYGUARD
1024 || statusBarState == StatusBarState.SHADE_LOCKED) {
1025 mKeyguardBottomArea.animate().cancel();
1026 mKeyguardBottomArea.setVisibility(View.VISIBLE);
1027 mKeyguardBottomArea.setAlpha(1f);
1028 } else {
1029 mKeyguardBottomArea.animate().cancel();
1030 mKeyguardBottomArea.setVisibility(View.GONE);
1031 mKeyguardBottomArea.setAlpha(1f);
1032 }
1033 }
1034
1035 private void setKeyguardStatusViewVisibility(int statusBarState, boolean keyguardFadingAway,
1036 boolean goingToFullShade) {
1037 if ((!keyguardFadingAway && mStatusBarState == StatusBarState.KEYGUARD
1038 && statusBarState != StatusBarState.KEYGUARD) || goingToFullShade) {
Jorim Jaggi6ff837a2014-07-31 21:46:39 +02001039 mKeyguardStatusView.animate().cancel();
1040 mKeyguardStatusViewAnimating = true;
1041 mKeyguardStatusView.animate()
1042 .alpha(0f)
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001043 .setStartDelay(0)
Jorim Jaggi6ff837a2014-07-31 21:46:39 +02001044 .setDuration(160)
1045 .setInterpolator(PhoneStatusBar.ALPHA_OUT)
1046 .withEndAction(mAnimateKeyguardStatusViewInvisibleEndRunnable);
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001047 if (keyguardFadingAway) {
1048 mKeyguardStatusView.animate()
1049 .setStartDelay(mStatusBar.getKeyguardFadingAwayDelay())
1050 .setDuration(mStatusBar.getKeyguardFadingAwayDuration()/2)
1051 .start();
1052 }
Jorim Jaggi6ff837a2014-07-31 21:46:39 +02001053 } else if (mStatusBarState == StatusBarState.SHADE_LOCKED
1054 && statusBarState == StatusBarState.KEYGUARD) {
1055 mKeyguardStatusView.animate().cancel();
1056 mKeyguardStatusView.setVisibility(View.VISIBLE);
1057 mKeyguardStatusViewAnimating = true;
1058 mKeyguardStatusView.setAlpha(0f);
1059 mKeyguardStatusView.animate()
1060 .alpha(1f)
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001061 .setStartDelay(0)
Jorim Jaggi6ff837a2014-07-31 21:46:39 +02001062 .setDuration(320)
1063 .setInterpolator(PhoneStatusBar.ALPHA_IN)
1064 .withEndAction(mAnimateKeyguardStatusViewVisibleEndRunnable);
1065 } else if (statusBarState == StatusBarState.KEYGUARD) {
1066 mKeyguardStatusView.animate().cancel();
Jorim Jaggi5e08e692014-10-03 15:17:20 -07001067 mKeyguardStatusViewAnimating = false;
Jorim Jaggi6ff837a2014-07-31 21:46:39 +02001068 mKeyguardStatusView.setVisibility(View.VISIBLE);
1069 mKeyguardStatusView.setAlpha(1f);
1070 } else {
1071 mKeyguardStatusView.animate().cancel();
Jorim Jaggi5e08e692014-10-03 15:17:20 -07001072 mKeyguardStatusViewAnimating = false;
Jorim Jaggi6ff837a2014-07-31 21:46:39 +02001073 mKeyguardStatusView.setVisibility(View.GONE);
1074 mKeyguardStatusView.setAlpha(1f);
1075 }
1076 }
1077
Jorim Jaggif62f2bb2014-05-25 22:28:41 +02001078 private void updateQsState() {
Jorim Jaggi290600a2014-05-30 17:02:20 +02001079 boolean expandVisually = mQsExpanded || mStackScrollerOverscrolling;
Jorim Jaggi4538027d2014-07-30 15:43:13 +02001080 mHeader.setVisibility((mQsExpanded || !mKeyguardShowing) ? View.VISIBLE : View.INVISIBLE);
Jorim Jaggi61d37f62014-07-30 17:26:55 +02001081 mHeader.setExpanded(mKeyguardShowing || (mQsExpanded && !mStackScrollerOverscrolling));
Jorim Jaggi4538027d2014-07-30 15:43:13 +02001082 mNotificationStackScroller.setScrollingEnabled(
1083 mStatusBarState != StatusBarState.KEYGUARD && (!mQsExpanded
1084 || mQsExpansionFromOverscroll));
Jorim Jaggi290600a2014-05-30 17:02:20 +02001085 mQsPanel.setVisibility(expandVisually ? View.VISIBLE : View.INVISIBLE);
Jorim Jaggi475b21d2014-07-01 18:13:24 +02001086 mQsContainer.setVisibility(
1087 mKeyguardShowing && !expandVisually ? View.INVISIBLE : View.VISIBLE);
Jorim Jaggif62f2bb2014-05-25 22:28:41 +02001088 mScrollView.setTouchEnabled(mQsExpanded);
Jorim Jaggia2052ea2014-08-05 16:22:30 +02001089 updateEmptyShadeView();
Jorim Jaggidd5b8862014-08-05 21:04:39 +02001090 mQsNavbarScrim.setVisibility(mStatusBarState == StatusBarState.SHADE && mQsExpanded
1091 && !mStackScrollerOverscrolling && mQsScrimEnabled
1092 ? View.VISIBLE
1093 : View.INVISIBLE);
Jorim Jaggibf1899e2014-08-07 02:04:18 +02001094 if (mKeyguardUserSwitcher != null && mQsExpanded && !mStackScrollerOverscrolling) {
Adrian Roos2d1ef302014-10-24 18:42:51 +02001095 mKeyguardUserSwitcher.hideIfNotSimple(true /* animate */);
Jorim Jaggibf1899e2014-08-07 02:04:18 +02001096 }
Jorim Jaggid7daab72014-05-06 22:22:20 +02001097 }
1098
1099 private void setQsExpansion(float height) {
1100 height = Math.min(Math.max(height, mQsMinExpansionHeight), mQsMaxExpansionHeight);
John Spurlockbc3a5e92014-05-30 16:20:05 -04001101 mQsFullyExpanded = height == mQsMaxExpansionHeight;
Jorim Jaggi290600a2014-05-30 17:02:20 +02001102 if (height > mQsMinExpansionHeight && !mQsExpanded && !mStackScrollerOverscrolling) {
Jorim Jaggif62f2bb2014-05-25 22:28:41 +02001103 setQsExpanded(true);
Jorim Jaggid7daab72014-05-06 22:22:20 +02001104 } else if (height <= mQsMinExpansionHeight && mQsExpanded) {
Jorim Jaggif62f2bb2014-05-25 22:28:41 +02001105 setQsExpanded(false);
Selim Cinek90c94652014-08-18 16:46:22 +02001106 if (mLastAnnouncementWasQuickSettings && !mTracking) {
1107 announceForAccessibility(getKeyguardOrLockScreenString());
1108 mLastAnnouncementWasQuickSettings = false;
1109 }
John Spurlock73203eb2014-04-15 16:14:46 -04001110 }
Jorim Jaggid7daab72014-05-06 22:22:20 +02001111 mQsExpansionHeight = height;
Jorim Jaggi61d37f62014-07-30 17:26:55 +02001112 mHeader.setExpansion(getHeaderExpansionFraction());
Jorim Jaggid7daab72014-05-06 22:22:20 +02001113 setQsTranslation(height);
Selim Cinek1408eb52014-06-02 14:45:38 +02001114 requestScrollerTopPaddingUpdate(false /* animate */);
Selim Cinekf54090e2014-06-17 17:24:51 -07001115 updateNotificationScrim(height);
Jorim Jaggi61d37f62014-07-30 17:26:55 +02001116 if (mKeyguardShowing) {
Jorim Jaggi3afddce2014-08-14 20:44:43 +02001117 updateHeaderKeyguard();
Jorim Jaggi61d37f62014-07-30 17:26:55 +02001118 }
Jorim Jaggidd5b8862014-08-05 21:04:39 +02001119 if (mStatusBarState == StatusBarState.SHADE && mQsExpanded
1120 && !mStackScrollerOverscrolling && mQsScrimEnabled) {
1121 mQsNavbarScrim.setAlpha(getQsExpansionFraction());
1122 }
Selim Cinek90c94652014-08-18 16:46:22 +02001123
1124 // Upon initialisation when we are not layouted yet we don't want to announce that we are
1125 // fully expanded, hence the != 0.0f check.
1126 if (height != 0.0f && mQsFullyExpanded && !mLastAnnouncementWasQuickSettings) {
1127 announceForAccessibility(getContext().getString(
1128 R.string.accessibility_desc_quick_settings));
1129 mLastAnnouncementWasQuickSettings = true;
1130 }
Jorim Jaggi58bef332014-11-21 18:10:32 +01001131 if (DEBUG) {
1132 invalidate();
1133 }
Selim Cinek90c94652014-08-18 16:46:22 +02001134 }
1135
1136 private String getKeyguardOrLockScreenString() {
1137 if (mStatusBarState == StatusBarState.KEYGUARD) {
1138 return getContext().getString(R.string.accessibility_desc_lock_screen);
1139 } else {
1140 return getContext().getString(R.string.accessibility_desc_notification_shade);
1141 }
Jorim Jaggid7daab72014-05-06 22:22:20 +02001142 }
1143
Selim Cinekf54090e2014-06-17 17:24:51 -07001144 private void updateNotificationScrim(float height) {
1145 int startDistance = mQsMinExpansionHeight + mNotificationScrimWaitDistance;
1146 float progress = (height - startDistance) / (mQsMaxExpansionHeight - startDistance);
1147 progress = Math.max(0.0f, Math.min(progress, 1.0f));
Selim Cinekf54090e2014-06-17 17:24:51 -07001148 }
1149
Jorim Jaggi61d37f62014-07-30 17:26:55 +02001150 private float getHeaderExpansionFraction() {
1151 if (!mKeyguardShowing) {
1152 return getQsExpansionFraction();
1153 } else {
1154 return 1f;
1155 }
1156 }
1157
Jorim Jaggid7daab72014-05-06 22:22:20 +02001158 private void setQsTranslation(float height) {
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001159 if (!mHeaderAnimatingIn) {
Jorim Jaggi8bc983e2014-12-10 17:45:50 +01001160 mQsContainer.setY(height - mQsContainer.getDesiredHeight() + getHeaderTranslation());
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001161 }
Jorim Jaggi61d37f62014-07-30 17:26:55 +02001162 if (mKeyguardShowing) {
1163 mHeader.setY(interpolate(getQsExpansionFraction(), -mHeader.getHeight(), 0));
1164 }
1165 }
1166
1167 private float calculateQsTopPadding() {
Jorim Jaggi06a0c3a2014-10-29 17:17:21 +01001168 if (mKeyguardShowing
1169 && (mTwoFingerQsExpand || mIsExpanding && mQsExpandedWhenExpandingStarted)) {
1170
1171 // Either QS pushes the notifications down when fully expanded, or QS is fully above the
1172 // notifications (mostly on tablets). maxNotifications denotes the normal top padding
1173 // on Keyguard, maxQs denotes the top padding from the quick settings panel. We need to
1174 // take the maximum and linearly interpolate with the panel expansion for a nice motion.
1175 int maxNotifications = mClockPositionResult.stackScrollerPadding
1176 - mClockPositionResult.stackScrollerPaddingAdjustment
1177 - mNotificationTopPadding;
1178 int maxQs = getTempQsMaxExpansion();
1179 int max = mStatusBarState == StatusBarState.KEYGUARD
1180 ? Math.max(maxNotifications, maxQs)
1181 : maxQs;
1182 return (int) interpolate(getExpandedFraction(),
1183 mQsMinExpansionHeight, max);
Jorim Jaggi8bc983e2014-12-10 17:45:50 +01001184 } else if (mQsSizeChangeAnimator != null) {
1185 return (int) mQsSizeChangeAnimator.getAnimatedValue();
Jorim Jaggi06a0c3a2014-10-29 17:17:21 +01001186 } else if (mKeyguardShowing && mScrollYOverride == -1) {
1187
1188 // We can only do the smoother transition on Keyguard when we also are not collapsing
1189 // from a scrolled quick settings.
Jorim Jaggi61d37f62014-07-30 17:26:55 +02001190 return interpolate(getQsExpansionFraction(),
1191 mNotificationStackScroller.getIntrinsicPadding() - mNotificationTopPadding,
1192 mQsMaxExpansionHeight);
1193 } else {
1194 return mQsExpansionHeight;
1195 }
Jorim Jaggid7daab72014-05-06 22:22:20 +02001196 }
1197
Selim Cinek1408eb52014-06-02 14:45:38 +02001198 private void requestScrollerTopPaddingUpdate(boolean animate) {
Jorim Jaggi61d37f62014-07-30 17:26:55 +02001199 mNotificationStackScroller.updateTopPadding(calculateQsTopPadding(),
Selim Cinek1408eb52014-06-02 14:45:38 +02001200 mScrollView.getScrollY(),
Jorim Jaggi06a0c3a2014-10-29 17:17:21 +01001201 mAnimateNextTopPaddingChange || animate,
1202 mKeyguardShowing
1203 && (mTwoFingerQsExpand || mIsExpanding && mQsExpandedWhenExpandingStarted));
Selim Cinek758afb12014-06-04 18:46:12 +02001204 mAnimateNextTopPaddingChange = false;
Jorim Jaggid7daab72014-05-06 22:22:20 +02001205 }
1206
1207 private void trackMovement(MotionEvent event) {
1208 if (mVelocityTracker != null) mVelocityTracker.addMovement(event);
Jorim Jaggifc1a8242014-05-12 19:30:05 +02001209 mLastTouchX = event.getX();
1210 mLastTouchY = event.getY();
Jorim Jaggid7daab72014-05-06 22:22:20 +02001211 }
1212
1213 private void initVelocityTracker() {
1214 if (mVelocityTracker != null) {
1215 mVelocityTracker.recycle();
1216 }
1217 mVelocityTracker = VelocityTracker.obtain();
1218 }
1219
1220 private float getCurrentVelocity() {
1221 if (mVelocityTracker == null) {
1222 return 0;
1223 }
1224 mVelocityTracker.computeCurrentVelocity(1000);
1225 return mVelocityTracker.getYVelocity();
1226 }
1227
1228 private void cancelAnimation() {
1229 if (mQsExpansionAnimator != null) {
1230 mQsExpansionAnimator.cancel();
1231 }
1232 }
Jorim Jaggi475b21d2014-07-01 18:13:24 +02001233
Jorim Jaggid7daab72014-05-06 22:22:20 +02001234 private void flingSettings(float vel, boolean expand) {
Jorim Jaggi475b21d2014-07-01 18:13:24 +02001235 flingSettings(vel, expand, null);
1236 }
1237
1238 private void flingSettings(float vel, boolean expand, final Runnable onFinishRunnable) {
Jorim Jaggid7daab72014-05-06 22:22:20 +02001239 float target = expand ? mQsMaxExpansionHeight : mQsMinExpansionHeight;
Jorim Jaggi9cd731a2014-05-22 14:26:06 +02001240 if (target == mQsExpansionHeight) {
Jorim Jaggi54045422014-07-03 18:30:40 +02001241 mScrollYOverride = -1;
Jorim Jaggi475b21d2014-07-01 18:13:24 +02001242 if (onFinishRunnable != null) {
1243 onFinishRunnable.run();
1244 }
Jorim Jaggi9cd731a2014-05-22 14:26:06 +02001245 return;
1246 }
Selim Cinek5386fb32014-09-03 16:37:36 +02001247 boolean belowFalsingThreshold = isBelowFalsingThreshold();
1248 if (belowFalsingThreshold) {
1249 vel = 0;
1250 }
Jorim Jaggi11c071a2014-08-14 19:17:11 +02001251 mScrollView.setBlockFlinging(true);
Jorim Jaggid7daab72014-05-06 22:22:20 +02001252 ValueAnimator animator = ValueAnimator.ofFloat(mQsExpansionHeight, target);
Jorim Jaggi87cd5e72014-05-12 23:29:10 +02001253 mFlingAnimationUtils.apply(animator, mQsExpansionHeight, target, vel);
Selim Cinek5386fb32014-09-03 16:37:36 +02001254 if (belowFalsingThreshold) {
1255 animator.setDuration(350);
1256 }
Jorim Jaggid7daab72014-05-06 22:22:20 +02001257 animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
1258 @Override
1259 public void onAnimationUpdate(ValueAnimator animation) {
1260 setQsExpansion((Float) animation.getAnimatedValue());
1261 }
1262 });
1263 animator.addListener(new AnimatorListenerAdapter() {
1264 @Override
1265 public void onAnimationEnd(Animator animation) {
Jorim Jaggi11c071a2014-08-14 19:17:11 +02001266 mScrollView.setBlockFlinging(false);
Jorim Jaggi54045422014-07-03 18:30:40 +02001267 mScrollYOverride = -1;
Jorim Jaggid7daab72014-05-06 22:22:20 +02001268 mQsExpansionAnimator = null;
Jorim Jaggi475b21d2014-07-01 18:13:24 +02001269 if (onFinishRunnable != null) {
1270 onFinishRunnable.run();
1271 }
Jorim Jaggid7daab72014-05-06 22:22:20 +02001272 }
1273 });
1274 animator.start();
1275 mQsExpansionAnimator = animator;
Jorim Jaggibd003102014-07-04 00:02:42 +02001276 mQsAnimatorExpand = expand;
Jorim Jaggid7daab72014-05-06 22:22:20 +02001277 }
1278
1279 /**
1280 * @return Whether we should intercept a gesture to open Quick Settings.
1281 */
Selim Cinek4c6969a2014-05-26 19:22:17 +02001282 private boolean shouldQuickSettingsIntercept(float x, float y, float yDiff) {
Jorim Jaggid7daab72014-05-06 22:22:20 +02001283 if (!mQsExpansionEnabled) {
1284 return false;
1285 }
Jorim Jaggi61d37f62014-07-30 17:26:55 +02001286 View header = mKeyguardShowing ? mKeyguardStatusBar : mHeader;
1287 boolean onHeader = x >= header.getLeft() && x <= header.getRight()
1288 && y >= header.getTop() && y <= header.getBottom();
Jorim Jaggid7daab72014-05-06 22:22:20 +02001289 if (mQsExpanded) {
Jorim Jaggie0640dd2014-08-05 23:12:40 +02001290 return onHeader || (mScrollView.isScrolledToBottom() && yDiff < 0) && isInQsArea(x, y);
Jorim Jaggid7daab72014-05-06 22:22:20 +02001291 } else {
1292 return onHeader;
1293 }
Selim Cinekb6d85eb2014-03-28 20:21:01 +01001294 }
1295
1296 @Override
1297 protected boolean isScrolledToBottom() {
1298 if (!isInSettings()) {
Jorim Jaggi58bef332014-11-21 18:10:32 +01001299 return mStatusBar.getBarState() == StatusBarState.KEYGUARD
1300 || mNotificationStackScroller.isScrolledToBottom();
Jorim Jaggie0640dd2014-08-05 23:12:40 +02001301 } else {
1302 return mScrollView.isScrolledToBottom();
Chris Wren64161cc2012-12-17 16:49:30 -05001303 }
Selim Cinekb6d85eb2014-03-28 20:21:01 +01001304 }
1305
1306 @Override
1307 protected int getMaxPanelHeight() {
Jorim Jaggi30c305c2014-07-01 23:34:41 +02001308 int min = mStatusBarMinHeight;
Jorim Jaggi2580a9762014-06-25 03:08:25 +02001309 if (mStatusBar.getBarState() != StatusBarState.KEYGUARD
1310 && mNotificationStackScroller.getNotGoneChildCount() == 0) {
Jorim Jaggi30c305c2014-07-01 23:34:41 +02001311 int minHeight = (int) ((mQsMinExpansionHeight + getOverExpansionAmount())
Jorim Jaggi2580a9762014-06-25 03:08:25 +02001312 * HEADER_RUBBERBAND_FACTOR);
Jorim Jaggi30c305c2014-07-01 23:34:41 +02001313 min = Math.max(min, minHeight);
Jorim Jaggi2580a9762014-06-25 03:08:25 +02001314 }
Jorim Jaggi30c305c2014-07-01 23:34:41 +02001315 int maxHeight;
Jorim Jaggi1e2554b2014-07-10 23:07:00 +02001316 if (mTwoFingerQsExpand || mQsExpanded || mIsExpanding && mQsExpandedWhenExpandingStarted) {
Jorim Jaggi58bef332014-11-21 18:10:32 +01001317 maxHeight = calculatePanelHeightQsExpanded();
Jorim Jaggi30c305c2014-07-01 23:34:41 +02001318 } else {
Jorim Jaggi61d37f62014-07-30 17:26:55 +02001319 maxHeight = calculatePanelHeightShade();
Jorim Jaggi30c305c2014-07-01 23:34:41 +02001320 }
1321 maxHeight = Math.max(maxHeight, min);
Jorim Jaggi1d480692014-05-20 19:41:58 +02001322 return maxHeight;
Selim Cinekb6d85eb2014-03-28 20:21:01 +01001323 }
1324
1325 private boolean isInSettings() {
Jorim Jaggid7daab72014-05-06 22:22:20 +02001326 return mQsExpanded;
Selim Cinekb6d85eb2014-03-28 20:21:01 +01001327 }
1328
1329 @Override
1330 protected void onHeightUpdated(float expandedHeight) {
Jorim Jaggi06a0c3a2014-10-29 17:17:21 +01001331 if (!mQsExpanded || mTwoFingerQsExpand || mIsExpanding && mQsExpandedWhenExpandingStarted) {
Jorim Jaggi7d16bb12014-05-22 04:24:50 +02001332 positionClockAndNotifications();
1333 }
Jorim Jaggi1e2554b2014-07-10 23:07:00 +02001334 if (mTwoFingerQsExpand || mQsExpanded && !mQsTracking && mQsExpansionAnimator == null
Jorim Jaggi30c305c2014-07-01 23:34:41 +02001335 && !mQsExpansionFromOverscroll) {
Jorim Jaggi06a0c3a2014-10-29 17:17:21 +01001336 float t;
1337 if (mKeyguardShowing) {
Jorim Jaggi54045422014-07-03 18:30:40 +02001338
Jorim Jaggi06a0c3a2014-10-29 17:17:21 +01001339 // On Keyguard, interpolate the QS expansion linearly to the panel expansion
1340 t = expandedHeight / getMaxPanelHeight();
1341 } else {
1342
1343 // In Shade, interpolate linearly such that QS is closed whenever panel height is
1344 // minimum QS expansion + minStackHeight
1345 float panelHeightQsCollapsed = mNotificationStackScroller.getIntrinsicPadding()
Jorim Jaggi58bef332014-11-21 18:10:32 +01001346 + mNotificationStackScroller.getMinStackHeight();
Jorim Jaggi06a0c3a2014-10-29 17:17:21 +01001347 float panelHeightQsExpanded = calculatePanelHeightQsExpanded();
1348 t = (expandedHeight - panelHeightQsCollapsed)
1349 / (panelHeightQsExpanded - panelHeightQsCollapsed);
1350 }
Jorim Jaggi30c305c2014-07-01 23:34:41 +02001351 setQsExpansion(mQsMinExpansionHeight
Jorim Jaggi54045422014-07-03 18:30:40 +02001352 + t * (getTempQsMaxExpansion() - mQsMinExpansionHeight));
Jorim Jaggi30c305c2014-07-01 23:34:41 +02001353 }
Jorim Jaggi8c1a44b2014-04-29 19:04:02 +02001354 mNotificationStackScroller.setStackHeight(expandedHeight);
Jorim Jaggi2580a9762014-06-25 03:08:25 +02001355 updateHeader();
Jorim Jaggi8dd95e02014-06-03 16:19:33 +02001356 updateUnlockIcon();
Jorim Jaggi2580a9762014-06-25 03:08:25 +02001357 updateNotificationTranslucency();
Jorim Jaggi58bef332014-11-21 18:10:32 +01001358 if (DEBUG) {
1359 invalidate();
1360 }
Jorim Jaggi2580a9762014-06-25 03:08:25 +02001361 }
1362
Jorim Jaggi54045422014-07-03 18:30:40 +02001363 /**
1364 * @return a temporary override of {@link #mQsMaxExpansionHeight}, which is needed when
1365 * collapsing QS / the panel when QS was scrolled
1366 */
1367 private int getTempQsMaxExpansion() {
1368 int qsTempMaxExpansion = mQsMaxExpansionHeight;
1369 if (mScrollYOverride != -1) {
1370 qsTempMaxExpansion -= mScrollYOverride;
1371 }
1372 return qsTempMaxExpansion;
1373 }
1374
Jorim Jaggi61d37f62014-07-30 17:26:55 +02001375 private int calculatePanelHeightShade() {
1376 int emptyBottomMargin = mNotificationStackScroller.getEmptyBottomMargin();
1377 int maxHeight = mNotificationStackScroller.getHeight() - emptyBottomMargin
1378 - mTopPaddingAdjustment;
1379 maxHeight += mNotificationStackScroller.getTopPaddingOverflow();
1380 return maxHeight;
1381 }
1382
1383 private int calculatePanelHeightQsExpanded() {
Jorim Jaggi30c305c2014-07-01 23:34:41 +02001384 float notificationHeight = mNotificationStackScroller.getHeight()
1385 - mNotificationStackScroller.getEmptyBottomMargin()
1386 - mNotificationStackScroller.getTopPadding();
Jorim Jaggi0cce70c2014-11-04 16:13:41 +01001387
1388 // When only empty shade view is visible in QS collapsed state, simulate that we would have
1389 // it in expanded QS state as well so we don't run into troubles when fading the view in/out
1390 // and expanding/collapsing the whole panel from/to quick settings.
1391 if (mNotificationStackScroller.getNotGoneChildCount() == 0
1392 && mShadeEmpty) {
1393 notificationHeight = mNotificationStackScroller.getEmptyShadeViewHeight()
1394 + mNotificationStackScroller.getBottomStackPeekSize()
1395 + mNotificationStackScroller.getCollapseSecondCardPadding();
1396 }
Jorim Jaggi8bc983e2014-12-10 17:45:50 +01001397 int maxQsHeight = mQsMaxExpansionHeight;
1398
1399 // If an animation is changing the size of the QS panel, take the animated value.
1400 if (mQsSizeChangeAnimator != null) {
1401 maxQsHeight = (int) mQsSizeChangeAnimator.getAnimatedValue();
1402 }
Jorim Jaggi06a0c3a2014-10-29 17:17:21 +01001403 float totalHeight = Math.max(
Jorim Jaggi8bc983e2014-12-10 17:45:50 +01001404 maxQsHeight + mNotificationStackScroller.getNotificationTopPadding(),
Jorim Jaggi58bef332014-11-21 18:10:32 +01001405 mStatusBarState == StatusBarState.KEYGUARD
1406 ? mClockPositionResult.stackScrollerPadding - mTopPaddingAdjustment
1407 : 0)
Jorim Jaggi06a0c3a2014-10-29 17:17:21 +01001408 + notificationHeight;
Jorim Jaggi30c305c2014-07-01 23:34:41 +02001409 if (totalHeight > mNotificationStackScroller.getHeight()) {
Jorim Jaggi8bc983e2014-12-10 17:45:50 +01001410 float fullyCollapsedHeight = maxQsHeight
Jorim Jaggi30c305c2014-07-01 23:34:41 +02001411 + mNotificationStackScroller.getMinStackHeight()
Jorim Jaggi56306252014-07-03 00:40:09 +02001412 + mNotificationStackScroller.getNotificationTopPadding()
1413 - getScrollViewScrollY();
Jorim Jaggi30c305c2014-07-01 23:34:41 +02001414 totalHeight = Math.max(fullyCollapsedHeight, mNotificationStackScroller.getHeight());
1415 }
Jorim Jaggi61d37f62014-07-30 17:26:55 +02001416 return (int) totalHeight;
Jorim Jaggi30c305c2014-07-01 23:34:41 +02001417 }
1418
Jorim Jaggi56306252014-07-03 00:40:09 +02001419 private int getScrollViewScrollY() {
Jorim Jaggi58bef332014-11-21 18:10:32 +01001420 if (mScrollYOverride != -1 && !mQsTracking) {
Jorim Jaggi56306252014-07-03 00:40:09 +02001421 return mScrollYOverride;
1422 } else {
1423 return mScrollView.getScrollY();
1424 }
1425 }
Jorim Jaggi2580a9762014-06-25 03:08:25 +02001426 private void updateNotificationTranslucency() {
Jorim Jaggiad46ffef2014-07-04 18:05:06 +02001427 float alpha = (getNotificationsTopY() + mNotificationStackScroller.getItemHeight())
Jorim Jaggi5ad92c52014-07-28 21:07:32 +02001428 / (mQsMinExpansionHeight + mNotificationStackScroller.getBottomStackPeekSize()
Jorim Jaggi12a67822014-09-05 16:01:00 +02001429 - mNotificationStackScroller.getCollapseSecondCardPadding());
Jorim Jaggi2580a9762014-06-25 03:08:25 +02001430 alpha = Math.max(0, Math.min(alpha, 1));
1431 alpha = (float) Math.pow(alpha, 0.75);
Jorim Jaggi5ad92c52014-07-28 21:07:32 +02001432 if (alpha != 1f && mNotificationStackScroller.getLayerType() != LAYER_TYPE_HARDWARE) {
1433 mNotificationStackScroller.setLayerType(LAYER_TYPE_HARDWARE, null);
1434 } else if (alpha == 1f
1435 && mNotificationStackScroller.getLayerType() == LAYER_TYPE_HARDWARE) {
1436 mNotificationStackScroller.setLayerType(LAYER_TYPE_NONE, null);
1437 }
Jorim Jaggi2580a9762014-06-25 03:08:25 +02001438 mNotificationStackScroller.setAlpha(alpha);
Jorim Jaggi8dd95e02014-06-03 16:19:33 +02001439 }
1440
Jorim Jaggi47c85a32014-06-05 17:25:40 +02001441 @Override
1442 protected float getOverExpansionAmount() {
1443 return mNotificationStackScroller.getCurrentOverScrollAmount(true /* top */);
1444 }
1445
1446 @Override
1447 protected float getOverExpansionPixels() {
1448 return mNotificationStackScroller.getCurrentOverScrolledPixels(true /* top */);
1449 }
1450
Jorim Jaggi8dd95e02014-06-03 16:19:33 +02001451 private void updateUnlockIcon() {
1452 if (mStatusBar.getBarState() == StatusBarState.KEYGUARD
1453 || mStatusBar.getBarState() == StatusBarState.SHADE_LOCKED) {
1454 boolean active = getMaxPanelHeight() - getExpandedHeight() > mUnlockMoveDistance;
Selim Cinekbaa23272014-07-08 18:01:07 +02001455 KeyguardAffordanceView lockIcon = mKeyguardBottomArea.getLockIcon();
Jorim Jaggi8dd95e02014-06-03 16:19:33 +02001456 if (active && !mUnlockIconActive && mTracking) {
Selim Cinekbaa23272014-07-08 18:01:07 +02001457 lockIcon.setImageAlpha(1.0f, true, 150, mFastOutLinearInterpolator, null);
1458 lockIcon.setImageScale(LOCK_ICON_ACTIVE_SCALE, true, 150,
1459 mFastOutLinearInterpolator);
Jorim Jaggi8dd95e02014-06-03 16:19:33 +02001460 } else if (!active && mUnlockIconActive && mTracking) {
Selim Cinekbaa23272014-07-08 18:01:07 +02001461 lockIcon.setImageAlpha(KeyguardAffordanceHelper.SWIPE_RESTING_ALPHA_AMOUNT, true,
1462 150, mFastOutLinearInterpolator, null);
1463 lockIcon.setImageScale(1.0f, true, 150,
1464 mFastOutLinearInterpolator);
Jorim Jaggi8dd95e02014-06-03 16:19:33 +02001465 }
1466 mUnlockIconActive = active;
1467 }
Jorim Jaggi457cc352014-06-02 22:47:42 +02001468 }
1469
1470 /**
1471 * Hides the header when notifications are colliding with it.
1472 */
Jorim Jaggi2580a9762014-06-25 03:08:25 +02001473 private void updateHeader() {
Jorim Jaggi457cc352014-06-02 22:47:42 +02001474 if (mStatusBar.getBarState() == StatusBarState.KEYGUARD
1475 || mStatusBar.getBarState() == StatusBarState.SHADE_LOCKED) {
Jorim Jaggi2580a9762014-06-25 03:08:25 +02001476 updateHeaderKeyguard();
Jorim Jaggi457cc352014-06-02 22:47:42 +02001477 } else {
Jorim Jaggi2580a9762014-06-25 03:08:25 +02001478 updateHeaderShade();
Jorim Jaggi457cc352014-06-02 22:47:42 +02001479 }
1480
Selim Cinekb6d85eb2014-03-28 20:21:01 +01001481 }
1482
Jorim Jaggi2580a9762014-06-25 03:08:25 +02001483 private void updateHeaderShade() {
Jorim Jaggidbc3dce2014-08-01 01:16:36 +02001484 if (!mHeaderAnimatingIn) {
1485 mHeader.setTranslationY(getHeaderTranslation());
1486 }
Jorim Jaggi2580a9762014-06-25 03:08:25 +02001487 setQsTranslation(mQsExpansionHeight);
1488 }
1489
1490 private float getHeaderTranslation() {
1491 if (mStatusBar.getBarState() == StatusBarState.KEYGUARD
1492 || mStatusBar.getBarState() == StatusBarState.SHADE_LOCKED) {
1493 return 0;
1494 }
1495 if (mNotificationStackScroller.getNotGoneChildCount() == 0) {
1496 if (mExpandedHeight / HEADER_RUBBERBAND_FACTOR >= mQsMinExpansionHeight) {
1497 return 0;
1498 } else {
1499 return mExpandedHeight / HEADER_RUBBERBAND_FACTOR - mQsMinExpansionHeight;
1500 }
1501 }
1502 return Math.min(0, mNotificationStackScroller.getTranslationY()) / HEADER_RUBBERBAND_FACTOR;
1503 }
1504
1505 private void updateHeaderKeyguard() {
Jorim Jaggi3afddce2014-08-14 20:44:43 +02001506 float alphaNotifications;
Jorim Jaggi2580a9762014-06-25 03:08:25 +02001507 if (mStatusBar.getBarState() == StatusBarState.KEYGUARD) {
1508
1509 // When on Keyguard, we hide the header as soon as the top card of the notification
1510 // stack scroller is close enough (collision distance) to the bottom of the header.
Jorim Jaggi3afddce2014-08-14 20:44:43 +02001511 alphaNotifications = getNotificationsTopY()
Jorim Jaggi2580a9762014-06-25 03:08:25 +02001512 /
Jorim Jaggi3afddce2014-08-14 20:44:43 +02001513 (mKeyguardStatusBar.getHeight() + mNotificationsHeaderCollideDistance);
Jorim Jaggi2580a9762014-06-25 03:08:25 +02001514 } else {
1515
1516 // In SHADE_LOCKED, the top card is already really close to the header. Hide it as
1517 // soon as we start translating the stack.
Jorim Jaggi3afddce2014-08-14 20:44:43 +02001518 alphaNotifications = getNotificationsTopY() / mKeyguardStatusBar.getHeight();
Jorim Jaggi2580a9762014-06-25 03:08:25 +02001519 }
Jorim Jaggi3afddce2014-08-14 20:44:43 +02001520 alphaNotifications = MathUtils.constrain(alphaNotifications, 0, 1);
1521 alphaNotifications = (float) Math.pow(alphaNotifications, 0.75);
1522 float alphaQsExpansion = 1 - Math.min(1, getQsExpansionFraction() * 2);
Jorim Jaggi16423aa2014-10-28 11:42:58 +01001523 mKeyguardStatusBar.setAlpha(Math.min(alphaNotifications, alphaQsExpansion)
1524 * mKeyguardStatusBarAnimateAlpha);
Jorim Jaggi3afddce2014-08-14 20:44:43 +02001525 mKeyguardBottomArea.setAlpha(Math.min(1 - getQsExpansionFraction(), alphaNotifications));
Jorim Jaggi2580a9762014-06-25 03:08:25 +02001526 setQsTranslation(mQsExpansionHeight);
1527 }
1528
Jorim Jaggiad46ffef2014-07-04 18:05:06 +02001529 private float getNotificationsTopY() {
1530 if (mNotificationStackScroller.getNotGoneChildCount() == 0) {
1531 return getExpandedHeight();
1532 }
1533 return mNotificationStackScroller.getNotificationsTopY();
1534 }
1535
Selim Cinekb6d85eb2014-03-28 20:21:01 +01001536 @Override
Selim Cinek1685e632014-04-08 02:27:49 +02001537 protected void onExpandingStarted() {
1538 super.onExpandingStarted();
1539 mNotificationStackScroller.onExpansionStarted();
Selim Cinek4c6969a2014-05-26 19:22:17 +02001540 mIsExpanding = true;
Jorim Jaggi06a0c3a2014-10-29 17:17:21 +01001541 mQsExpandedWhenExpandingStarted = mQsFullyExpanded;
Jorim Jaggi56306252014-07-03 00:40:09 +02001542 if (mQsExpanded) {
Jorim Jaggi56306252014-07-03 00:40:09 +02001543 onQsExpansionStarted();
1544 }
Selim Cinek1685e632014-04-08 02:27:49 +02001545 }
1546
1547 @Override
1548 protected void onExpandingFinished() {
1549 super.onExpandingFinished();
1550 mNotificationStackScroller.onExpansionStopped();
Selim Cinek4c6969a2014-05-26 19:22:17 +02001551 mIsExpanding = false;
Jorim Jaggi56306252014-07-03 00:40:09 +02001552 mScrollYOverride = -1;
Jorim Jaggie65e3102014-07-01 22:00:50 +02001553 if (mExpandedHeight == 0f) {
Jorim Jaggi4538027d2014-07-30 15:43:13 +02001554 setListening(false);
Jorim Jaggie65e3102014-07-01 22:00:50 +02001555 } else {
Jorim Jaggi4538027d2014-07-30 15:43:13 +02001556 setListening(true);
Jorim Jaggie65e3102014-07-01 22:00:50 +02001557 }
Jorim Jaggi1e2554b2014-07-10 23:07:00 +02001558 mTwoFingerQsExpand = false;
1559 mTwoFingerQsExpandPossible = false;
Jorim Jaggie65e3102014-07-01 22:00:50 +02001560 }
1561
Jorim Jaggi4538027d2014-07-30 15:43:13 +02001562 private void setListening(boolean listening) {
1563 mHeader.setListening(listening);
1564 mKeyguardStatusBar.setListening(listening);
1565 mQsPanel.setListening(listening);
1566 }
1567
Jorim Jaggie65e3102014-07-01 22:00:50 +02001568 @Override
1569 public void instantExpand() {
1570 super.instantExpand();
Jorim Jaggi4538027d2014-07-30 15:43:13 +02001571 setListening(true);
Selim Cinek1685e632014-04-08 02:27:49 +02001572 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001573
1574 @Override
Jorim Jaggi47c85a32014-06-05 17:25:40 +02001575 protected void setOverExpansion(float overExpansion, boolean isPixels) {
Jorim Jaggi1e2554b2014-07-10 23:07:00 +02001576 if (mConflictingQsExpansionGesture || mTwoFingerQsExpand) {
Jorim Jaggidc96d632014-07-01 18:48:52 +02001577 return;
1578 }
Selim Cinek1408eb52014-06-02 14:45:38 +02001579 if (mStatusBar.getBarState() != StatusBarState.KEYGUARD) {
Jorim Jaggi47c85a32014-06-05 17:25:40 +02001580 mNotificationStackScroller.setOnHeightChangedListener(null);
1581 if (isPixels) {
1582 mNotificationStackScroller.setOverScrolledPixels(
1583 overExpansion, true /* onTop */, false /* animate */);
1584 } else {
1585 mNotificationStackScroller.setOverScrollAmount(
1586 overExpansion, true /* onTop */, false /* animate */);
1587 }
1588 mNotificationStackScroller.setOnHeightChangedListener(this);
Selim Cinek1408eb52014-06-02 14:45:38 +02001589 }
Selim Cinek24120a52014-05-26 10:05:42 +02001590 }
1591
1592 @Override
Jorim Jaggi282a6152014-06-02 23:37:53 +02001593 protected void onTrackingStarted() {
1594 super.onTrackingStarted();
Jorim Jaggi06a0c3a2014-10-29 17:17:21 +01001595 if (mQsFullyExpanded) {
1596 mTwoFingerQsExpand = true;
1597 }
Jorim Jaggi282a6152014-06-02 23:37:53 +02001598 if (mStatusBar.getBarState() == StatusBarState.KEYGUARD
1599 || mStatusBar.getBarState() == StatusBarState.SHADE_LOCKED) {
Selim Cinekbaa23272014-07-08 18:01:07 +02001600 mAfforanceHelper.animateHideLeftRightIcon();
Jorim Jaggie0640dd2014-08-05 23:12:40 +02001601 }
Jorim Jaggi282a6152014-06-02 23:37:53 +02001602 }
1603
1604 @Override
Jorim Jaggi2fbad7b2014-05-26 22:38:00 +02001605 protected void onTrackingStopped(boolean expand) {
1606 super.onTrackingStopped(expand);
Jorim Jaggi47c85a32014-06-05 17:25:40 +02001607 if (expand) {
1608 mNotificationStackScroller.setOverScrolledPixels(
1609 0.0f, true /* onTop */, true /* animate */);
1610 }
Jorim Jaggi282a6152014-06-02 23:37:53 +02001611 if (expand && (mStatusBar.getBarState() == StatusBarState.KEYGUARD
1612 || mStatusBar.getBarState() == StatusBarState.SHADE_LOCKED)) {
Selim Cinekbaa23272014-07-08 18:01:07 +02001613 if (!mHintAnimationRunning) {
1614 mAfforanceHelper.reset(true);
1615 }
Jorim Jaggi282a6152014-06-02 23:37:53 +02001616 }
Jorim Jaggi8dd95e02014-06-03 16:19:33 +02001617 if (!expand && (mStatusBar.getBarState() == StatusBarState.KEYGUARD
1618 || mStatusBar.getBarState() == StatusBarState.SHADE_LOCKED)) {
Selim Cinekbaa23272014-07-08 18:01:07 +02001619 KeyguardAffordanceView lockIcon = mKeyguardBottomArea.getLockIcon();
1620 lockIcon.setImageAlpha(0.0f, true, 100, mFastOutLinearInterpolator, null);
1621 lockIcon.setImageScale(2.0f, true, 100, mFastOutLinearInterpolator);
Jorim Jaggi8dd95e02014-06-03 16:19:33 +02001622 }
Selim Cinek24120a52014-05-26 10:05:42 +02001623 }
1624
Selim Cinek24120a52014-05-26 10:05:42 +02001625 @Override
Jorim Jaggibe565df2014-04-28 17:51:23 +02001626 public void onHeightChanged(ExpandableView view) {
Jorim Jaggi30c305c2014-07-01 23:34:41 +02001627
1628 // Block update if we are in quick settings and just the top padding changed
1629 // (i.e. view == null).
1630 if (view == null && mQsExpanded) {
1631 return;
1632 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001633 requestPanelHeightUpdate();
1634 }
Jorim Jaggid7daab72014-05-06 22:22:20 +02001635
1636 @Override
Selim Cineka5e211b2014-08-11 17:35:48 +02001637 public void onReset(ExpandableView view) {
1638 }
1639
1640 @Override
Jorim Jaggid7daab72014-05-06 22:22:20 +02001641 public void onScrollChanged() {
1642 if (mQsExpanded) {
Selim Cinek1408eb52014-06-02 14:45:38 +02001643 requestScrollerTopPaddingUpdate(false /* animate */);
Jorim Jaggi56306252014-07-03 00:40:09 +02001644 requestPanelHeightUpdate();
Jorim Jaggid7daab72014-05-06 22:22:20 +02001645 }
1646 }
1647
1648 @Override
Selim Cinek4c6969a2014-05-26 19:22:17 +02001649 protected void onConfigurationChanged(Configuration newConfig) {
1650 super.onConfigurationChanged(newConfig);
Selim Cinekbaa23272014-07-08 18:01:07 +02001651 mAfforanceHelper.onConfigurationChanged();
Selim Cinek4c6969a2014-05-26 19:22:17 +02001652 }
1653
1654 @Override
Jorim Jaggi0a818222014-11-10 19:04:34 +01001655 public void onRtlPropertiesChanged(int layoutDirection) {
1656 if (layoutDirection != mOldLayoutDirection) {
1657 mAfforanceHelper.onRtlPropertiesChanged();
1658 mOldLayoutDirection = layoutDirection;
1659 }
1660 }
1661
1662 @Override
Jorim Jaggid7daab72014-05-06 22:22:20 +02001663 public void onClick(View v) {
Jorim Jaggi853b0702014-07-05 04:31:14 +02001664 if (v == mHeader) {
Jorim Jaggid7daab72014-05-06 22:22:20 +02001665 onQsExpansionStarted();
1666 if (mQsExpanded) {
1667 flingSettings(0 /* vel */, false /* expand */);
1668 } else if (mQsExpansionEnabled) {
1669 flingSettings(0 /* vel */, true /* expand */);
1670 }
1671 }
1672 }
Selim Cinek4c6969a2014-05-26 19:22:17 +02001673
1674 @Override
Christoph Studerb0183992014-12-22 21:02:26 +01001675 public void onAnimationToSideStarted(boolean rightPage, float translation, float vel) {
Jorim Jaggib3f0a2f2014-06-02 19:29:39 +02001676 boolean start = getLayoutDirection() == LAYOUT_DIRECTION_RTL ? rightPage : !rightPage;
Selim Cinekbaa23272014-07-08 18:01:07 +02001677 mIsLaunchTransitionRunning = true;
1678 mLaunchAnimationEndRunnable = null;
Christoph Studerb0183992014-12-22 21:02:26 +01001679 float displayDensity = mStatusBar.getDisplayDensity();
1680 int lengthDp = Math.abs((int) (translation / displayDensity));
1681 int velocityDp = Math.abs((int) (vel / displayDensity));
Jorim Jaggib3f0a2f2014-06-02 19:29:39 +02001682 if (start) {
Christoph Studerb0183992014-12-22 21:02:26 +01001683 EventLogTags.writeSysuiLockscreenGesture(
1684 EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_SWIPE_DIALER, lengthDp, velocityDp);
Selim Cinek4c6969a2014-05-26 19:22:17 +02001685 mKeyguardBottomArea.launchPhone();
Jorim Jaggib3f0a2f2014-06-02 19:29:39 +02001686 } else {
Christoph Studerb0183992014-12-22 21:02:26 +01001687 EventLogTags.writeSysuiLockscreenGesture(
1688 EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_SWIPE_CAMERA, lengthDp, velocityDp);
Brian Colonnad45c6d42014-08-01 18:04:40 -04001689 mSecureCameraLaunchManager.startSecureCameraLaunch();
Selim Cinek4c6969a2014-05-26 19:22:17 +02001690 }
Jorim Jaggi826730a2014-12-08 21:05:13 +01001691 mStatusBar.startLaunchTransitionTimeout();
Selim Cinek4c6969a2014-05-26 19:22:17 +02001692 mBlockTouches = true;
1693 }
1694
Jorim Jaggib3f0a2f2014-06-02 19:29:39 +02001695 @Override
Selim Cinekbaa23272014-07-08 18:01:07 +02001696 public void onAnimationToSideEnded() {
1697 mIsLaunchTransitionRunning = false;
1698 mIsLaunchTransitionFinished = true;
1699 if (mLaunchAnimationEndRunnable != null) {
1700 mLaunchAnimationEndRunnable.run();
1701 mLaunchAnimationEndRunnable = null;
1702 }
1703 }
1704
1705 @Override
Jorim Jaggib3f0a2f2014-06-02 19:29:39 +02001706 protected void onEdgeClicked(boolean right) {
1707 if ((right && getRightIcon().getVisibility() != View.VISIBLE)
Jorim Jaggid7912d22014-09-30 17:38:19 +02001708 || (!right && getLeftIcon().getVisibility() != View.VISIBLE)
1709 || isDozing()) {
Jorim Jaggib3f0a2f2014-06-02 19:29:39 +02001710 return;
1711 }
1712 mHintAnimationRunning = true;
Selim Cinekbaa23272014-07-08 18:01:07 +02001713 mAfforanceHelper.startHintAnimation(right, new Runnable() {
Jorim Jaggib3f0a2f2014-06-02 19:29:39 +02001714 @Override
1715 public void run() {
1716 mHintAnimationRunning = false;
1717 mStatusBar.onHintFinished();
1718 }
1719 });
1720 boolean start = getLayoutDirection() == LAYOUT_DIRECTION_RTL ? right : !right;
1721 if (start) {
1722 mStatusBar.onPhoneHintStarted();
1723 } else {
1724 mStatusBar.onCameraHintStarted();
1725 }
1726 }
Selim Cinek4c6969a2014-05-26 19:22:17 +02001727
1728 @Override
Jorim Jaggi93a2bb22014-06-02 19:57:28 +02001729 protected void startUnlockHintAnimation() {
1730 super.startUnlockHintAnimation();
1731 startHighlightIconAnimation(getCenterIcon());
1732 }
1733
1734 /**
1735 * Starts the highlight (making it fully opaque) animation on an icon.
1736 */
Selim Cinekbaa23272014-07-08 18:01:07 +02001737 private void startHighlightIconAnimation(final KeyguardAffordanceView icon) {
1738 icon.setImageAlpha(1.0f, true, KeyguardAffordanceHelper.HINT_PHASE1_DURATION,
1739 mFastOutSlowInInterpolator, new Runnable() {
Jorim Jaggi93a2bb22014-06-02 19:57:28 +02001740 @Override
1741 public void run() {
Selim Cinekbaa23272014-07-08 18:01:07 +02001742 icon.setImageAlpha(KeyguardAffordanceHelper.SWIPE_RESTING_ALPHA_AMOUNT,
1743 true, KeyguardAffordanceHelper.HINT_PHASE1_DURATION,
1744 mFastOutSlowInInterpolator, null);
Jorim Jaggi93a2bb22014-06-02 19:57:28 +02001745 }
1746 });
1747 }
1748
1749 @Override
Selim Cinek4c6969a2014-05-26 19:22:17 +02001750 public float getPageWidth() {
1751 return getWidth();
1752 }
1753
1754 @Override
Selim Cinekbaa23272014-07-08 18:01:07 +02001755 public void onSwipingStarted() {
Brian Colonnad45c6d42014-08-01 18:04:40 -04001756 mSecureCameraLaunchManager.onSwipingStarted();
Selim Cinekbaa23272014-07-08 18:01:07 +02001757 requestDisallowInterceptTouchEvent(true);
1758 mOnlyAffordanceInThisMotion = true;
Selim Cinek4c6969a2014-05-26 19:22:17 +02001759 }
1760
1761 @Override
Selim Cinekbaa23272014-07-08 18:01:07 +02001762 public KeyguardAffordanceView getLeftIcon() {
Jorim Jaggib3f0a2f2014-06-02 19:29:39 +02001763 return getLayoutDirection() == LAYOUT_DIRECTION_RTL
Selim Cinekbaa23272014-07-08 18:01:07 +02001764 ? mKeyguardBottomArea.getCameraView()
1765 : mKeyguardBottomArea.getPhoneView();
Selim Cinek4c6969a2014-05-26 19:22:17 +02001766 }
1767
1768 @Override
Selim Cinekbaa23272014-07-08 18:01:07 +02001769 public KeyguardAffordanceView getCenterIcon() {
Selim Cinek4c6969a2014-05-26 19:22:17 +02001770 return mKeyguardBottomArea.getLockIcon();
1771 }
1772
1773 @Override
Selim Cinekbaa23272014-07-08 18:01:07 +02001774 public KeyguardAffordanceView getRightIcon() {
Jorim Jaggib3f0a2f2014-06-02 19:29:39 +02001775 return getLayoutDirection() == LAYOUT_DIRECTION_RTL
Selim Cinekbaa23272014-07-08 18:01:07 +02001776 ? mKeyguardBottomArea.getPhoneView()
1777 : mKeyguardBottomArea.getCameraView();
Selim Cinek4c6969a2014-05-26 19:22:17 +02001778 }
Jorim Jaggi2580a9762014-06-25 03:08:25 +02001779
1780 @Override
Jorim Jaggib6cdcbc2014-07-25 21:58:29 +02001781 public View getLeftPreview() {
1782 return getLayoutDirection() == LAYOUT_DIRECTION_RTL
1783 ? mKeyguardBottomArea.getCameraPreview()
1784 : mKeyguardBottomArea.getPhonePreview();
1785 }
1786
1787 @Override
1788 public View getRightPreview() {
1789 return getLayoutDirection() == LAYOUT_DIRECTION_RTL
1790 ? mKeyguardBottomArea.getPhonePreview()
1791 : mKeyguardBottomArea.getCameraPreview();
1792 }
1793
1794 @Override
Selim Cinek34cf5c42014-09-26 15:39:00 +02001795 public float getAffordanceFalsingFactor() {
1796 return mStatusBar.isScreenOnComingFromTouch() ? 1.5f : 1.0f;
1797 }
1798
1799 @Override
Jorim Jaggi2580a9762014-06-25 03:08:25 +02001800 protected float getPeekHeight() {
1801 if (mNotificationStackScroller.getNotGoneChildCount() > 0) {
1802 return mNotificationStackScroller.getPeekHeight();
1803 } else {
Jorim Jaggib472b3472014-06-30 19:56:24 +02001804 return mQsMinExpansionHeight * HEADER_RUBBERBAND_FACTOR;
Jorim Jaggi2580a9762014-06-25 03:08:25 +02001805 }
1806 }
Jorim Jaggi30c305c2014-07-01 23:34:41 +02001807
1808 @Override
1809 protected float getCannedFlingDurationFactor() {
1810 if (mQsExpanded) {
1811 return 0.7f;
1812 } else {
1813 return 0.6f;
1814 }
1815 }
1816
1817 @Override
Jorim Jaggi4b04a3a2014-07-28 17:43:56 +02001818 protected boolean fullyExpandedClearAllVisible() {
1819 return mNotificationStackScroller.isDismissViewNotGone()
Jorim Jaggi1d49ec92014-08-25 18:44:01 +02001820 && mNotificationStackScroller.isScrolledToBottom() && !mTwoFingerQsExpand;
Jorim Jaggi4b04a3a2014-07-28 17:43:56 +02001821 }
1822
1823 @Override
1824 protected boolean isClearAllVisible() {
1825 return mNotificationStackScroller.isDismissViewVisible();
1826 }
1827
1828 @Override
1829 protected int getClearAllHeight() {
1830 return mNotificationStackScroller.getDismissViewHeight();
1831 }
1832
1833 @Override
Jorim Jaggi30c305c2014-07-01 23:34:41 +02001834 protected boolean isTrackingBlocked() {
1835 return mConflictingQsExpansionGesture && mQsExpanded;
1836 }
Jorim Jaggi54045422014-07-03 18:30:40 +02001837
1838 public void notifyVisibleChildrenChanged() {
1839 if (mNotificationStackScroller.getNotGoneChildCount() != 0) {
1840 mReserveNotificationSpace.setVisibility(View.VISIBLE);
1841 } else {
1842 mReserveNotificationSpace.setVisibility(View.GONE);
1843 }
1844 }
Jorim Jaggibd003102014-07-04 00:02:42 +02001845
1846 public boolean isQsExpanded() {
1847 return mQsExpanded;
1848 }
Jorim Jaggi853b0702014-07-05 04:31:14 +02001849
John Spurlockf7ae4422014-08-01 12:45:18 -04001850 public boolean isQsDetailShowing() {
1851 return mQsPanel.isShowingDetail();
1852 }
1853
1854 public void closeQsDetail() {
1855 mQsPanel.closeDetail();
1856 }
1857
Jorim Jaggi853b0702014-07-05 04:31:14 +02001858 @Override
1859 public boolean shouldDelayChildPressedState() {
1860 return true;
1861 }
Selim Cinekbaa23272014-07-08 18:01:07 +02001862
1863 public boolean isLaunchTransitionFinished() {
1864 return mIsLaunchTransitionFinished;
1865 }
1866
1867 public boolean isLaunchTransitionRunning() {
1868 return mIsLaunchTransitionRunning;
1869 }
1870
1871 public void setLaunchTransitionEndRunnable(Runnable r) {
1872 mLaunchAnimationEndRunnable = r;
1873 }
Jorim Jaggi48bc36a2014-07-25 23:16:04 +02001874
1875 public void setEmptyDragAmount(float amount) {
Selim Cinek5386fb32014-09-03 16:37:36 +02001876 float factor = 0.8f;
Jorim Jaggi48bc36a2014-07-25 23:16:04 +02001877 if (mNotificationStackScroller.getNotGoneChildCount() > 0) {
Selim Cinek5386fb32014-09-03 16:37:36 +02001878 factor = 0.4f;
Christoph Studerc8db24b2014-07-25 17:50:30 +02001879 } else if (!mStatusBar.hasActiveNotifications()) {
Jorim Jaggi48bc36a2014-07-25 23:16:04 +02001880 factor = 0.4f;
1881 }
1882 mEmptyDragAmount = amount * factor;
1883 positionClockAndNotifications();
1884 }
Jorim Jaggi61d37f62014-07-30 17:26:55 +02001885
1886 private static float interpolate(float t, float start, float end) {
1887 return (1 - t) * start + t * end;
1888 }
John Spurlockd54da8a2014-08-03 23:23:52 -04001889
Jorim Jaggi16423aa2014-10-28 11:42:58 +01001890 public void setDozing(boolean dozing, boolean animate) {
John Spurlockd54da8a2014-08-03 23:23:52 -04001891 if (dozing == mDozing) return;
1892 mDozing = dozing;
1893 if (mDozing) {
Jorim Jaggi16423aa2014-10-28 11:42:58 +01001894 mKeyguardStatusBar.setVisibility(View.INVISIBLE);
1895 mKeyguardBottomArea.setVisibility(View.INVISIBLE);
John Spurlockd54da8a2014-08-03 23:23:52 -04001896 } else {
Jorim Jaggi16423aa2014-10-28 11:42:58 +01001897 mKeyguardBottomArea.setVisibility(View.VISIBLE);
1898 mKeyguardStatusBar.setVisibility(View.VISIBLE);
1899 if (animate) {
1900 animateKeyguardStatusBarIn();
1901 mKeyguardBottomArea.startFinishDozeAnimation();
1902 }
John Spurlockd54da8a2014-08-03 23:23:52 -04001903 }
John Spurlockd54da8a2014-08-03 23:23:52 -04001904 }
Jorim Jaggia2052ea2014-08-05 16:22:30 +02001905
Jorim Jaggid7912d22014-09-30 17:38:19 +02001906 @Override
John Spurlockcf5d3c92014-09-21 17:55:01 -04001907 public boolean isDozing() {
1908 return mDozing;
1909 }
1910
Jorim Jaggia2052ea2014-08-05 16:22:30 +02001911 public void setShadeEmpty(boolean shadeEmpty) {
1912 mShadeEmpty = shadeEmpty;
1913 updateEmptyShadeView();
1914 }
1915
1916 private void updateEmptyShadeView() {
1917
1918 // Hide "No notifications" in QS.
1919 mNotificationStackScroller.updateEmptyShadeView(mShadeEmpty && !mQsExpanded);
1920 }
Jorim Jaggidd5b8862014-08-05 21:04:39 +02001921
1922 public void setQsScrimEnabled(boolean qsScrimEnabled) {
1923 boolean changed = mQsScrimEnabled != qsScrimEnabled;
1924 mQsScrimEnabled = qsScrimEnabled;
1925 if (changed) {
1926 updateQsState();
1927 }
1928 }
John Spurlock7e6809a2014-08-06 16:03:14 -04001929
Jorim Jaggibf1899e2014-08-07 02:04:18 +02001930 public void setKeyguardUserSwitcher(KeyguardUserSwitcher keyguardUserSwitcher) {
1931 mKeyguardUserSwitcher = keyguardUserSwitcher;
1932 }
1933
John Spurlock7e6809a2014-08-06 16:03:14 -04001934 private final Runnable mUpdateHeader = new Runnable() {
1935 @Override
1936 public void run() {
1937 mHeader.updateEverything();
1938 }
1939 };
Jorim Jaggid09def7512014-09-02 18:36:45 +02001940
1941 public void onScreenTurnedOn() {
1942 mKeyguardStatusView.refreshTime();
1943 }
Selim Cinek3a9c10a2014-10-28 14:21:10 +01001944
1945 @Override
1946 public void onEmptySpaceClicked(float x, float y) {
1947 onEmptySpaceClick(x);
1948 }
Jorim Jaggi58bef332014-11-21 18:10:32 +01001949
1950 @Override
1951 protected void dispatchDraw(Canvas canvas) {
1952 super.dispatchDraw(canvas);
1953 if (DEBUG) {
1954 Paint p = new Paint();
1955 p.setColor(Color.RED);
1956 p.setStrokeWidth(2);
1957 p.setStyle(Paint.Style.STROKE);
1958 canvas.drawLine(0, getMaxPanelHeight(), getWidth(), getMaxPanelHeight(), p);
1959 p.setColor(Color.BLUE);
1960 canvas.drawLine(0, getExpandedHeight(), getWidth(), getExpandedHeight(), p);
1961 p.setColor(Color.GREEN);
1962 canvas.drawLine(0, calculatePanelHeightQsExpanded(), getWidth(),
1963 calculatePanelHeightQsExpanded(), p);
1964 p.setColor(Color.YELLOW);
1965 canvas.drawLine(0, calculatePanelHeightShade(), getWidth(),
1966 calculatePanelHeightShade(), p);
1967 p.setColor(Color.MAGENTA);
1968 canvas.drawLine(0, calculateQsTopPadding(), getWidth(),
1969 calculateQsTopPadding(), p);
1970 p.setColor(Color.CYAN);
1971 canvas.drawLine(0, mNotificationStackScroller.getTopPadding(), getWidth(),
1972 mNotificationStackScroller.getTopPadding(), p);
1973 }
1974 }
Daniel Sandler08d05e32012-08-08 16:39:54 -04001975}