blob: 14c447c8bdaac16a023f3738f15c14fcb98e6335 [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 Jaggid7daab72014-05-06 22:22:20 +020022import android.animation.ValueAnimator;
Daniel Sandler08d05e32012-08-08 16:39:54 -040023import android.content.Context;
Selim Cinek4c6969a2014-05-26 19:22:17 +020024import android.content.res.Configuration;
Daniel Sandler08d05e32012-08-08 16:39:54 -040025import android.util.AttributeSet;
Jorim Jaggi457cc352014-06-02 22:47:42 +020026import android.util.Log;
Daniel Sandler040c2e42012-10-17 00:56:33 -040027import android.view.MotionEvent;
Jorim Jaggid7daab72014-05-06 22:22:20 +020028import android.view.VelocityTracker;
Daniel Sandler13522a22012-09-27 14:46:58 -040029import android.view.View;
Jorim Jaggi0d74eeb2014-05-09 22:05:24 +020030import android.view.ViewGroup;
Jorim Jaggi75c95042014-05-16 19:09:59 +020031import android.view.ViewTreeObserver;
Casey Burkhardt23b0a4e2013-04-29 12:18:32 -070032import android.view.accessibility.AccessibilityEvent;
Jorim Jaggi75c95042014-05-16 19:09:59 +020033import android.view.animation.AnimationUtils;
34import android.view.animation.Interpolator;
Jorim Jaggi93a2bb22014-06-02 19:57:28 +020035import android.view.animation.LinearInterpolator;
Jorim Jaggi0d74eeb2014-05-09 22:05:24 +020036import android.widget.LinearLayout;
Daniel Sandler13522a22012-09-27 14:46:58 -040037
Chet Haase4d179dc2012-08-22 07:14:42 -070038import com.android.systemui.R;
Jorim Jaggibe565df2014-04-28 17:51:23 +020039import com.android.systemui.statusbar.ExpandableView;
Jorim Jaggi87cd5e72014-05-12 23:29:10 +020040import com.android.systemui.statusbar.FlingAnimationUtils;
Daniel Sandler151f00d2012-10-02 22:33:08 -040041import com.android.systemui.statusbar.GestureRecorder;
Jorim Jaggiecbab362014-04-23 16:13:15 +020042import com.android.systemui.statusbar.StatusBarState;
Selim Cinekb6d85eb2014-03-28 20:21:01 +010043import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
Jorim Jaggi75c95042014-05-16 19:09:59 +020044import com.android.systemui.statusbar.stack.StackStateAnimator;
Daniel Sandler08d05e32012-08-08 16:39:54 -040045
Selim Cinek4c6969a2014-05-26 19:22:17 +020046import java.util.ArrayList;
47
Jorim Jaggibe565df2014-04-28 17:51:23 +020048public class NotificationPanelView extends PanelView implements
Jorim Jaggid7daab72014-05-06 22:22:20 +020049 ExpandableView.OnHeightChangedListener, ObservableScrollView.Listener,
Jorim Jaggi290600a2014-05-30 17:02:20 +020050 View.OnClickListener, NotificationStackScrollLayout.OnOverscrollTopChangedListener,
51 KeyguardPageSwipeHelper.Callback {
Chet Haase4d179dc2012-08-22 07:14:42 -070052
Jorim Jaggi290600a2014-05-30 17:02:20 +020053 private static float EXPANSION_RUBBER_BAND_EXTRA_FACTOR = 0.6f;
Selim Cineka02fe522014-05-30 17:01:21 +020054
Selim Cinek4c6969a2014-05-26 19:22:17 +020055 private KeyguardPageSwipeHelper mPageSwiper;
Jorim Jaggid7daab72014-05-06 22:22:20 +020056 private StatusBarHeaderView mHeader;
John Spurlockaf8d6c42014-05-07 17:49:08 -040057 private View mQsContainer;
John Spurlock3e04cc82014-05-30 12:34:03 -040058 private View mQsPanel;
John Spurlock73203eb2014-04-15 16:14:46 -040059 private View mKeyguardStatusView;
Jorim Jaggid7daab72014-05-06 22:22:20 +020060 private ObservableScrollView mScrollView;
61 private View mStackScrollerContainer;
John Spurlock73203eb2014-04-15 16:14:46 -040062
Selim Cinekb6d85eb2014-03-28 20:21:01 +010063 private NotificationStackScrollLayout mNotificationStackScroller;
Jorim Jaggi8c1a44b2014-04-29 19:04:02 +020064 private int mNotificationTopPadding;
Jorim Jaggi98fb09c2014-05-01 22:40:56 +020065 private boolean mAnimateNextTopPaddingChange;
Chet Haase4d179dc2012-08-22 07:14:42 -070066
Jorim Jaggid7daab72014-05-06 22:22:20 +020067 private int mTrackingPointer;
68 private VelocityTracker mVelocityTracker;
Selim Cinek4c6969a2014-05-26 19:22:17 +020069 private boolean mQsTracking;
Jorim Jaggifc1a8242014-05-12 19:30:05 +020070
71 /**
72 * Whether we are currently handling a motion gesture in #onInterceptTouchEvent, but haven't
73 * intercepted yet.
74 */
75 private boolean mIntercepting;
Jorim Jaggid7daab72014-05-06 22:22:20 +020076 private boolean mQsExpanded;
John Spurlockbc3a5e92014-05-30 16:20:05 -040077 private boolean mQsFullyExpanded;
Jorim Jaggif62f2bb2014-05-25 22:28:41 +020078 private boolean mKeyguardShowing;
Jorim Jaggid7daab72014-05-06 22:22:20 +020079 private float mInitialHeightOnTouch;
80 private float mInitialTouchX;
81 private float mInitialTouchY;
Jorim Jaggifc1a8242014-05-12 19:30:05 +020082 private float mLastTouchX;
83 private float mLastTouchY;
Jorim Jaggid7daab72014-05-06 22:22:20 +020084 private float mQsExpansionHeight;
85 private int mQsMinExpansionHeight;
86 private int mQsMaxExpansionHeight;
87 private int mMinStackHeight;
Jorim Jaggif62f2bb2014-05-25 22:28:41 +020088 private int mQsPeekHeight;
Jorim Jaggid7daab72014-05-06 22:22:20 +020089 private float mNotificationTranslation;
90 private int mStackScrollerIntrinsicPadding;
Jorim Jaggi290600a2014-05-30 17:02:20 +020091 private boolean mStackScrollerOverscrolling;
Jorim Jaggid7daab72014-05-06 22:22:20 +020092 private boolean mQsExpansionEnabled = true;
93 private ValueAnimator mQsExpansionAnimator;
Jorim Jaggi87cd5e72014-05-12 23:29:10 +020094 private FlingAnimationUtils mFlingAnimationUtils;
Selim Cinek9dbbca82014-05-15 15:23:37 +020095 private int mStatusBarMinHeight;
Jorim Jaggi457cc352014-06-02 22:47:42 +020096 private boolean mHeaderHidden;
97 private int mNotificationsHeaderCollideDistance;
John Spurlock3e04cc82014-05-30 12:34:03 -040098
Jorim Jaggi75c95042014-05-16 19:09:59 +020099 private Interpolator mFastOutSlowInInterpolator;
Jorim Jaggi457cc352014-06-02 22:47:42 +0200100 private Interpolator mFastOutLinearInterpolator;
101 private Interpolator mLinearOutSlowInInterpolator;
Jorim Jaggi75c95042014-05-16 19:09:59 +0200102 private ObjectAnimator mClockAnimator;
103 private int mClockAnimationTarget = -1;
Jorim Jaggi7d16bb12014-05-22 04:24:50 +0200104 private int mTopPaddingAdjustment;
105 private KeyguardClockPositionAlgorithm mClockPositionAlgorithm =
106 new KeyguardClockPositionAlgorithm();
107 private KeyguardClockPositionAlgorithm.Result mClockPositionResult =
108 new KeyguardClockPositionAlgorithm.Result();
Selim Cinek4c6969a2014-05-26 19:22:17 +0200109 private boolean mIsSwipedHorizontally;
110 private boolean mIsExpanding;
111 private KeyguardBottomAreaView mKeyguardBottomArea;
112 private boolean mBlockTouches;
113 private ArrayList<View> mSwipeTranslationViews = new ArrayList<>();
Jorim Jaggi069cd032014-05-15 03:09:01 +0200114
Daniel Sandler08d05e32012-08-08 16:39:54 -0400115 public NotificationPanelView(Context context, AttributeSet attrs) {
116 super(context, attrs);
Daniel Sandler13522a22012-09-27 14:46:58 -0400117 }
Chet Haase4d179dc2012-08-22 07:14:42 -0700118
Daniel Sandler040c2e42012-10-17 00:56:33 -0400119 public void setStatusBar(PhoneStatusBar bar) {
Selim Cinekb6d85eb2014-03-28 20:21:01 +0100120 if (mStatusBar != null) {
121 mStatusBar.setOnFlipRunnable(null);
122 }
Daniel Sandler040c2e42012-10-17 00:56:33 -0400123 mStatusBar = bar;
Selim Cinekb6d85eb2014-03-28 20:21:01 +0100124 if (bar != null) {
125 mStatusBar.setOnFlipRunnable(new Runnable() {
126 @Override
127 public void run() {
128 requestPanelHeightUpdate();
129 }
130 });
131 }
Daniel Sandler040c2e42012-10-17 00:56:33 -0400132 }
133
Daniel Sandler13522a22012-09-27 14:46:58 -0400134 @Override
135 protected void onFinishInflate() {
136 super.onFinishInflate();
Jorim Jaggid7daab72014-05-06 22:22:20 +0200137 mHeader = (StatusBarHeaderView) findViewById(R.id.header);
138 mHeader.getBackgroundView().setOnClickListener(this);
Jorim Jaggi3d878be2014-05-10 03:22:32 +0200139 mHeader.setOverlayParent(this);
John Spurlock73203eb2014-04-15 16:14:46 -0400140 mKeyguardStatusView = findViewById(R.id.keyguard_status_view);
Jorim Jaggid7daab72014-05-06 22:22:20 +0200141 mStackScrollerContainer = findViewById(R.id.notification_container_parent);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400142 mQsContainer = findViewById(R.id.quick_settings_container);
John Spurlock3e04cc82014-05-30 12:34:03 -0400143 mQsPanel = findViewById(R.id.quick_settings_panel);
Jorim Jaggid7daab72014-05-06 22:22:20 +0200144 mScrollView = (ObservableScrollView) findViewById(R.id.scroll_view);
145 mScrollView.setListener(this);
Selim Cinekb6d85eb2014-03-28 20:21:01 +0100146 mNotificationStackScroller = (NotificationStackScrollLayout)
147 findViewById(R.id.notification_stack_scroller);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200148 mNotificationStackScroller.setOnHeightChangedListener(this);
Jorim Jaggi290600a2014-05-30 17:02:20 +0200149 mNotificationStackScroller.setOverscrollTopChangedListener(this);
Jorim Jaggi75c95042014-05-16 19:09:59 +0200150 mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(),
151 android.R.interpolator.fast_out_slow_in);
Jorim Jaggi457cc352014-06-02 22:47:42 +0200152 mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(),
153 android.R.interpolator.linear_out_slow_in);
154 mFastOutLinearInterpolator = AnimationUtils.loadInterpolator(getContext(),
155 android.R.interpolator.fast_out_linear_in);
Selim Cinek4c6969a2014-05-26 19:22:17 +0200156 mKeyguardBottomArea = (KeyguardBottomAreaView) findViewById(R.id.keyguard_bottom_area);
157 mSwipeTranslationViews.add(mNotificationStackScroller);
158 mSwipeTranslationViews.add(mKeyguardStatusView);
159 mPageSwiper = new KeyguardPageSwipeHelper(this, getContext());
Jorim Jaggi069cd032014-05-15 03:09:01 +0200160 }
161
162 @Override
163 protected void loadDimens() {
164 super.loadDimens();
Jorim Jaggi8c1a44b2014-04-29 19:04:02 +0200165 mNotificationTopPadding = getResources().getDimensionPixelSize(
166 R.dimen.notifications_top_padding);
Jorim Jaggid7daab72014-05-06 22:22:20 +0200167 mMinStackHeight = getResources().getDimensionPixelSize(R.dimen.collapsed_stack_height);
Jorim Jaggi1d480692014-05-20 19:41:58 +0200168 mFlingAnimationUtils = new FlingAnimationUtils(getContext(), 0.4f);
Selim Cinek9dbbca82014-05-15 15:23:37 +0200169 mStatusBarMinHeight = getResources().getDimensionPixelSize(
170 com.android.internal.R.dimen.status_bar_height);
Jorim Jaggif62f2bb2014-05-25 22:28:41 +0200171 mQsPeekHeight = getResources().getDimensionPixelSize(R.dimen.qs_peek_height);
Jorim Jaggi457cc352014-06-02 22:47:42 +0200172 mNotificationsHeaderCollideDistance =
173 getResources().getDimensionPixelSize(R.dimen.header_notifications_collide_distance);
Jorim Jaggi7d16bb12014-05-22 04:24:50 +0200174 mClockPositionAlgorithm.loadDimens(getResources());
Jorim Jaggi8c1a44b2014-04-29 19:04:02 +0200175 }
176
177 @Override
178 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
179 super.onLayout(changed, left, top, right, bottom);
Jorim Jaggid7daab72014-05-06 22:22:20 +0200180
181 // Calculate quick setting heights.
Jorim Jaggif62f2bb2014-05-25 22:28:41 +0200182 mQsMinExpansionHeight = mHeader.getCollapsedHeight() + mQsPeekHeight;
Jorim Jaggid7daab72014-05-06 22:22:20 +0200183 mQsMaxExpansionHeight = mHeader.getExpandedHeight() + mQsContainer.getHeight();
John Spurlock2684d5e2014-05-28 20:27:44 -0400184 if (mQsExpanded) {
John Spurlockbc3a5e92014-05-30 16:20:05 -0400185 if (mQsFullyExpanded) {
186 setQsStackScrollerPadding(mQsMaxExpansionHeight);
187 }
John Spurlock2684d5e2014-05-28 20:27:44 -0400188 } else {
Jorim Jaggi290600a2014-05-30 17:02:20 +0200189 if (!mStackScrollerOverscrolling) {
190 setQsExpansion(mQsMinExpansionHeight);
191 }
Jorim Jaggif62f2bb2014-05-25 22:28:41 +0200192 positionClockAndNotifications();
193 mNotificationStackScroller.setStackHeight(getExpandedHeight());
Jorim Jaggid7daab72014-05-06 22:22:20 +0200194 }
Jorim Jaggi98fb09c2014-05-01 22:40:56 +0200195 }
196
Jorim Jaggi069cd032014-05-15 03:09:01 +0200197 /**
198 * Positions the clock and notifications dynamically depending on how many notifications are
199 * showing.
200 */
201 private void positionClockAndNotifications() {
Jorim Jaggi75c95042014-05-16 19:09:59 +0200202 boolean animateClock = mNotificationStackScroller.isAddOrRemoveAnimationPending();
Jorim Jaggi069cd032014-05-15 03:09:01 +0200203 if (mStatusBar.getBarState() != StatusBarState.KEYGUARD) {
Jorim Jaggi290600a2014-05-30 17:02:20 +0200204 int bottom = mStackScrollerOverscrolling
205 ? mHeader.getCollapsedHeight()
206 : mHeader.getBottom();
207 mStackScrollerIntrinsicPadding = bottom + mQsPeekHeight
Jorim Jaggif62f2bb2014-05-25 22:28:41 +0200208 + mNotificationTopPadding;
Jorim Jaggi7d16bb12014-05-22 04:24:50 +0200209 mTopPaddingAdjustment = 0;
Jorim Jaggi069cd032014-05-15 03:09:01 +0200210 } else {
Jorim Jaggi7d16bb12014-05-22 04:24:50 +0200211 mClockPositionAlgorithm.setup(
212 mStatusBar.getMaxKeyguardNotifications(),
213 getMaxPanelHeight(),
214 getExpandedHeight(),
215 mNotificationStackScroller.getNotGoneChildCount(),
216 getHeight(),
217 mKeyguardStatusView.getHeight());
218 mClockPositionAlgorithm.run(mClockPositionResult);
Jorim Jaggi75c95042014-05-16 19:09:59 +0200219 if (animateClock || mClockAnimator != null) {
Jorim Jaggi7d16bb12014-05-22 04:24:50 +0200220 startClockAnimation(mClockPositionResult.clockY);
Jorim Jaggi75c95042014-05-16 19:09:59 +0200221 } else {
Jorim Jaggi7d16bb12014-05-22 04:24:50 +0200222 mKeyguardStatusView.setY(mClockPositionResult.clockY);
Jorim Jaggi75c95042014-05-16 19:09:59 +0200223 }
Jorim Jaggi7d16bb12014-05-22 04:24:50 +0200224 applyClockAlpha(mClockPositionResult.clockAlpha);
225 mStackScrollerIntrinsicPadding = mClockPositionResult.stackScrollerPadding;
226 mTopPaddingAdjustment = mClockPositionResult.stackScrollerPaddingAdjustment;
Jorim Jaggi069cd032014-05-15 03:09:01 +0200227 }
228 mNotificationStackScroller.setTopPadding(mStackScrollerIntrinsicPadding,
Jorim Jaggi75c95042014-05-16 19:09:59 +0200229 mAnimateNextTopPaddingChange || animateClock);
Jorim Jaggi069cd032014-05-15 03:09:01 +0200230 mAnimateNextTopPaddingChange = false;
231 }
232
Jorim Jaggi75c95042014-05-16 19:09:59 +0200233 private void startClockAnimation(int y) {
234 if (mClockAnimationTarget == y) {
235 return;
236 }
237 mClockAnimationTarget = y;
238 getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
239 @Override
240 public boolean onPreDraw() {
241 getViewTreeObserver().removeOnPreDrawListener(this);
242 if (mClockAnimator != null) {
243 mClockAnimator.removeAllListeners();
244 mClockAnimator.cancel();
245 }
246 mClockAnimator =
247 ObjectAnimator.ofFloat(mKeyguardStatusView, View.Y, mClockAnimationTarget);
248 mClockAnimator.setInterpolator(mFastOutSlowInInterpolator);
249 mClockAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
250 mClockAnimator.addListener(new AnimatorListenerAdapter() {
251 @Override
252 public void onAnimationEnd(Animator animation) {
253 mClockAnimator = null;
254 mClockAnimationTarget = -1;
255 }
256 });
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200257 mClockAnimator.start();
Jorim Jaggi75c95042014-05-16 19:09:59 +0200258 return true;
259 }
260 });
261 }
262
Jorim Jaggi7d16bb12014-05-22 04:24:50 +0200263 private void applyClockAlpha(float alpha) {
264 if (alpha != 1.0f) {
265 mKeyguardStatusView.setLayerType(LAYER_TYPE_HARDWARE, null);
266 } else {
267 mKeyguardStatusView.setLayerType(LAYER_TYPE_NONE, null);
268 }
269 mKeyguardStatusView.setAlpha(alpha);
Jorim Jaggi069cd032014-05-15 03:09:01 +0200270 }
271
Selim Cinekc27437b2014-05-14 10:23:33 +0200272 public void animateToFullShade() {
Jorim Jaggi98fb09c2014-05-01 22:40:56 +0200273 mAnimateNextTopPaddingChange = true;
Selim Cinekc27437b2014-05-14 10:23:33 +0200274 mNotificationStackScroller.goToFullShade();
Jorim Jaggi98fb09c2014-05-01 22:40:56 +0200275 requestLayout();
Daniel Sandler08d05e32012-08-08 16:39:54 -0400276 }
277
Jorim Jaggid7daab72014-05-06 22:22:20 +0200278 /**
279 * @return Whether Quick Settings are currently expanded.
280 */
281 public boolean isQsExpanded() {
282 return mQsExpanded;
283 }
284
285 public void setQsExpansionEnabled(boolean qsExpansionEnabled) {
286 mQsExpansionEnabled = qsExpansionEnabled;
Jorim Jaggid7daab72014-05-06 22:22:20 +0200287 }
288
Selim Cinek3c4635c2014-05-29 02:12:47 +0200289 @Override
Selim Cinek4c6969a2014-05-26 19:22:17 +0200290 public void resetViews() {
291 mBlockTouches = false;
292 mPageSwiper.reset();
293 closeQs();
294 }
295
Jorim Jaggid7daab72014-05-06 22:22:20 +0200296 public void closeQs() {
297 cancelAnimation();
298 setQsExpansion(mQsMinExpansionHeight);
299 }
300
301 public void openQs() {
302 cancelAnimation();
303 if (mQsExpansionEnabled) {
304 setQsExpansion(mQsMaxExpansionHeight);
305 }
306 }
307
Daniel Sandler08d05e32012-08-08 16:39:54 -0400308 @Override
309 public void fling(float vel, boolean always) {
Daniel Sandler151f00d2012-10-02 22:33:08 -0400310 GestureRecorder gr = ((PhoneStatusBarView) mBar).mBar.getGestureRecorder();
311 if (gr != null) {
Selim Cinek4c6969a2014-05-26 19:22:17 +0200312 gr.tag("fling " + ((vel > 0) ? "open" : "closed"), "notifications,v=" + vel);
Daniel Sandler151f00d2012-10-02 22:33:08 -0400313 }
Daniel Sandler08d05e32012-08-08 16:39:54 -0400314 super.fling(vel, always);
315 }
Chet Haase4d179dc2012-08-22 07:14:42 -0700316
Casey Burkhardt23b0a4e2013-04-29 12:18:32 -0700317 @Override
318 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
319 if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
320 event.getText()
321 .add(getContext().getString(R.string.accessibility_desc_notification_shade));
322 return true;
323 }
324
325 return super.dispatchPopulateAccessibilityEvent(event);
326 }
327
Daniel Sandler040c2e42012-10-17 00:56:33 -0400328 @Override
John Spurlock73203eb2014-04-15 16:14:46 -0400329 public boolean onInterceptTouchEvent(MotionEvent event) {
Selim Cinek4c6969a2014-05-26 19:22:17 +0200330 if (mBlockTouches) {
331 return false;
332 }
Jorim Jaggid7daab72014-05-06 22:22:20 +0200333 int pointerIndex = event.findPointerIndex(mTrackingPointer);
334 if (pointerIndex < 0) {
335 pointerIndex = 0;
336 mTrackingPointer = event.getPointerId(pointerIndex);
John Spurlock73203eb2014-04-15 16:14:46 -0400337 }
Jorim Jaggid7daab72014-05-06 22:22:20 +0200338 final float x = event.getX(pointerIndex);
339 final float y = event.getY(pointerIndex);
340
341 switch (event.getActionMasked()) {
342 case MotionEvent.ACTION_DOWN:
Jorim Jaggifc1a8242014-05-12 19:30:05 +0200343 mIntercepting = true;
Jorim Jaggid7daab72014-05-06 22:22:20 +0200344 mInitialTouchY = y;
345 mInitialTouchX = x;
346 initVelocityTracker();
347 trackMovement(event);
Selim Cinek4c6969a2014-05-26 19:22:17 +0200348 if (shouldQuickSettingsIntercept(mInitialTouchX, mInitialTouchY, 0)) {
Jorim Jaggid7daab72014-05-06 22:22:20 +0200349 getParent().requestDisallowInterceptTouchEvent(true);
350 }
351 break;
352 case MotionEvent.ACTION_POINTER_UP:
353 final int upPointer = event.getPointerId(event.getActionIndex());
354 if (mTrackingPointer == upPointer) {
355 // gesture is ongoing, find a new pointer to track
356 final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
357 mTrackingPointer = event.getPointerId(newIndex);
358 mInitialTouchX = event.getX(newIndex);
359 mInitialTouchY = event.getY(newIndex);
360 }
361 break;
362
363 case MotionEvent.ACTION_MOVE:
364 final float h = y - mInitialTouchY;
365 trackMovement(event);
Selim Cinek4c6969a2014-05-26 19:22:17 +0200366 if (mQsTracking) {
Jorim Jaggifc1a8242014-05-12 19:30:05 +0200367
368 // Already tracking because onOverscrolled was called. We need to update here
369 // so we don't stop for a frame until the next touch event gets handled in
370 // onTouchEvent.
371 setQsExpansion(h + mInitialHeightOnTouch);
372 trackMovement(event);
373 mIntercepting = false;
374 return true;
375 }
Jorim Jaggid7daab72014-05-06 22:22:20 +0200376 if (Math.abs(h) > mTouchSlop && Math.abs(h) > Math.abs(x - mInitialTouchX)
Selim Cinek4c6969a2014-05-26 19:22:17 +0200377 && shouldQuickSettingsIntercept(mInitialTouchX, mInitialTouchY, h)) {
Jorim Jaggid7daab72014-05-06 22:22:20 +0200378 onQsExpansionStarted();
379 mInitialHeightOnTouch = mQsExpansionHeight;
380 mInitialTouchY = y;
381 mInitialTouchX = x;
Selim Cinek4c6969a2014-05-26 19:22:17 +0200382 mQsTracking = true;
Jorim Jaggifc1a8242014-05-12 19:30:05 +0200383 mIntercepting = false;
Jorim Jaggid7daab72014-05-06 22:22:20 +0200384 return true;
385 }
386 break;
Jorim Jaggifc1a8242014-05-12 19:30:05 +0200387
388 case MotionEvent.ACTION_CANCEL:
389 case MotionEvent.ACTION_UP:
Jorim Jaggic9a52ab2014-05-12 23:46:19 +0200390 trackMovement(event);
Selim Cinek4c6969a2014-05-26 19:22:17 +0200391 if (mQsTracking) {
392 flingQsWithCurrentVelocity();
393 mQsTracking = false;
Jorim Jaggic9a52ab2014-05-12 23:46:19 +0200394 }
Jorim Jaggifc1a8242014-05-12 19:30:05 +0200395 mIntercepting = false;
396 break;
Jorim Jaggid7daab72014-05-06 22:22:20 +0200397 }
398 return !mQsExpanded && super.onInterceptTouchEvent(event);
John Spurlock73203eb2014-04-15 16:14:46 -0400399 }
400
401 @Override
Jorim Jaggifc1a8242014-05-12 19:30:05 +0200402 public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
403
Jorim Jaggice50b812014-05-24 16:29:57 +0200404 // Block request when interacting with the scroll view so we can still intercept the
405 // scrolling when QS is expanded.
406 if (mScrollView.isDispatchingTouchEvent()) {
407 return;
Jorim Jaggifc1a8242014-05-12 19:30:05 +0200408 }
Jorim Jaggice50b812014-05-24 16:29:57 +0200409 super.requestDisallowInterceptTouchEvent(disallowIntercept);
Jorim Jaggifc1a8242014-05-12 19:30:05 +0200410 }
411
Selim Cinek4c6969a2014-05-26 19:22:17 +0200412 private void flingQsWithCurrentVelocity() {
Jorim Jaggic9a52ab2014-05-12 23:46:19 +0200413 float vel = getCurrentVelocity();
414
415 // TODO: Better logic whether we should expand or not.
416 flingSettings(vel, vel > 0);
417 }
418
Jorim Jaggifc1a8242014-05-12 19:30:05 +0200419 @Override
Daniel Sandler040c2e42012-10-17 00:56:33 -0400420 public boolean onTouchEvent(MotionEvent event) {
Selim Cinek4c6969a2014-05-26 19:22:17 +0200421 if (mBlockTouches) {
422 return false;
423 }
Selim Cinekb6d85eb2014-03-28 20:21:01 +0100424 // TODO: Handle doublefinger swipe to notifications again. Look at history for a reference
425 // implementation.
Jorim Jaggib3f0a2f2014-06-02 19:29:39 +0200426 if ((!mIsExpanding || mHintAnimationRunning)
427 && !mQsExpanded
428 && mStatusBar.getBarState() != StatusBarState.SHADE) {
Selim Cinek4c6969a2014-05-26 19:22:17 +0200429 mPageSwiper.onTouchEvent(event);
430 if (mPageSwiper.isSwipingInProgress()) {
431 return true;
Jorim Jaggid7daab72014-05-06 22:22:20 +0200432 }
Selim Cinek4c6969a2014-05-26 19:22:17 +0200433 }
434 if (mQsTracking || mQsExpanded) {
435 return onQsTouch(event);
John Spurlock73203eb2014-04-15 16:14:46 -0400436 }
Jorim Jaggid7daab72014-05-06 22:22:20 +0200437
Selim Cinek4c6969a2014-05-26 19:22:17 +0200438 super.onTouchEvent(event);
439 return true;
440 }
441
442 @Override
443 protected boolean hasConflictingGestures() {
444 return mStatusBar.getBarState() != StatusBarState.SHADE;
445 }
446
447 private boolean onQsTouch(MotionEvent event) {
448 int pointerIndex = event.findPointerIndex(mTrackingPointer);
449 if (pointerIndex < 0) {
450 pointerIndex = 0;
451 mTrackingPointer = event.getPointerId(pointerIndex);
452 }
453 final float y = event.getY(pointerIndex);
454 final float x = event.getX(pointerIndex);
455
456 switch (event.getActionMasked()) {
457 case MotionEvent.ACTION_DOWN:
458 mQsTracking = true;
459 mInitialTouchY = y;
460 mInitialTouchX = x;
461 onQsExpansionStarted();
462 mInitialHeightOnTouch = mQsExpansionHeight;
463 initVelocityTracker();
464 trackMovement(event);
465 break;
466
467 case MotionEvent.ACTION_POINTER_UP:
468 final int upPointer = event.getPointerId(event.getActionIndex());
469 if (mTrackingPointer == upPointer) {
470 // gesture is ongoing, find a new pointer to track
471 final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
472 final float newY = event.getY(newIndex);
473 final float newX = event.getX(newIndex);
474 mTrackingPointer = event.getPointerId(newIndex);
475 mInitialHeightOnTouch = mQsExpansionHeight;
476 mInitialTouchY = newY;
477 mInitialTouchX = newX;
478 }
479 break;
480
481 case MotionEvent.ACTION_MOVE:
482 final float h = y - mInitialTouchY;
483 setQsExpansion(h + mInitialHeightOnTouch);
484 trackMovement(event);
485 break;
486
487 case MotionEvent.ACTION_UP:
488 case MotionEvent.ACTION_CANCEL:
489 mQsTracking = false;
490 mTrackingPointer = -1;
491 trackMovement(event);
492 flingQsWithCurrentVelocity();
493 if (mVelocityTracker != null) {
494 mVelocityTracker.recycle();
495 mVelocityTracker = null;
496 }
497 break;
498 }
499 return true;
Jorim Jaggid7daab72014-05-06 22:22:20 +0200500 }
501
Jorim Jaggifc1a8242014-05-12 19:30:05 +0200502 @Override
503 public void onOverscrolled(int amount) {
504 if (mIntercepting) {
505 onQsExpansionStarted(amount);
506 mInitialHeightOnTouch = mQsExpansionHeight;
507 mInitialTouchY = mLastTouchY;
508 mInitialTouchX = mLastTouchX;
Selim Cinek4c6969a2014-05-26 19:22:17 +0200509 mQsTracking = true;
Jorim Jaggifc1a8242014-05-12 19:30:05 +0200510 }
511 }
512
Jorim Jaggi290600a2014-05-30 17:02:20 +0200513
514 @Override
515 public void onOverscrollTopChanged(float amount) {
516 cancelAnimation();
517 float rounded = amount >= 1f ? amount : 0f;
518 mStackScrollerOverscrolling = rounded != 0f;
519 setQsExpansion(mQsMinExpansionHeight + rounded);
520 updateQsState();
521 }
522
Jorim Jaggid7daab72014-05-06 22:22:20 +0200523 private void onQsExpansionStarted() {
Jorim Jaggifc1a8242014-05-12 19:30:05 +0200524 onQsExpansionStarted(0);
525 }
526
527 private void onQsExpansionStarted(int overscrollAmount) {
Jorim Jaggid7daab72014-05-06 22:22:20 +0200528 cancelAnimation();
529
530 // Reset scroll position and apply that position to the expanded height.
Jorim Jaggifc1a8242014-05-12 19:30:05 +0200531 float height = mQsExpansionHeight - mScrollView.getScrollY() - overscrollAmount;
Jorim Jaggid7daab72014-05-06 22:22:20 +0200532 mScrollView.scrollTo(0, 0);
533 setQsExpansion(height);
534 }
535
Jorim Jaggif62f2bb2014-05-25 22:28:41 +0200536 private void setQsExpanded(boolean expanded) {
537 boolean changed = mQsExpanded != expanded;
538 if (changed) {
539 mQsExpanded = expanded;
540 updateQsState();
541 }
Jorim Jaggid7daab72014-05-06 22:22:20 +0200542 }
543
Jorim Jaggif62f2bb2014-05-25 22:28:41 +0200544 public void setKeyguardShowing(boolean keyguardShowing) {
545 mKeyguardShowing = keyguardShowing;
546 updateQsState();
547 }
548
549 private void updateQsState() {
Jorim Jaggi290600a2014-05-30 17:02:20 +0200550 boolean expandVisually = mQsExpanded || mStackScrollerOverscrolling;
551 mHeader.setExpanded(expandVisually, mStackScrollerOverscrolling);
Jorim Jaggif62f2bb2014-05-25 22:28:41 +0200552 mNotificationStackScroller.setEnabled(!mQsExpanded);
Jorim Jaggi290600a2014-05-30 17:02:20 +0200553 mQsPanel.setVisibility(expandVisually ? View.VISIBLE : View.INVISIBLE);
Jorim Jaggif62f2bb2014-05-25 22:28:41 +0200554 mQsContainer.setVisibility(mKeyguardShowing && !mQsExpanded
555 ? View.INVISIBLE
556 : View.VISIBLE);
557 mScrollView.setTouchEnabled(mQsExpanded);
Jorim Jaggid7daab72014-05-06 22:22:20 +0200558 }
559
560 private void setQsExpansion(float height) {
561 height = Math.min(Math.max(height, mQsMinExpansionHeight), mQsMaxExpansionHeight);
John Spurlockbc3a5e92014-05-30 16:20:05 -0400562 mQsFullyExpanded = height == mQsMaxExpansionHeight;
Jorim Jaggi290600a2014-05-30 17:02:20 +0200563 if (height > mQsMinExpansionHeight && !mQsExpanded && !mStackScrollerOverscrolling) {
Jorim Jaggif62f2bb2014-05-25 22:28:41 +0200564 setQsExpanded(true);
Jorim Jaggid7daab72014-05-06 22:22:20 +0200565 } else if (height <= mQsMinExpansionHeight && mQsExpanded) {
Jorim Jaggif62f2bb2014-05-25 22:28:41 +0200566 setQsExpanded(false);
John Spurlock73203eb2014-04-15 16:14:46 -0400567 }
Jorim Jaggid7daab72014-05-06 22:22:20 +0200568 mQsExpansionHeight = height;
Jorim Jaggif62f2bb2014-05-25 22:28:41 +0200569 mHeader.setExpansion(height - mQsPeekHeight);
Jorim Jaggid7daab72014-05-06 22:22:20 +0200570 setQsTranslation(height);
Jorim Jaggi290600a2014-05-30 17:02:20 +0200571 if (!mStackScrollerOverscrolling) {
572 setQsStackScrollerPadding(height);
573 }
John Spurlockd08f91f2014-05-23 11:00:34 -0400574 mStatusBar.userActivity();
Jorim Jaggid7daab72014-05-06 22:22:20 +0200575 }
576
577 private void setQsTranslation(float height) {
578 mQsContainer.setY(height - mQsContainer.getHeight());
579 }
580
581 private void setQsStackScrollerPadding(float height) {
582 float start = height - mScrollView.getScrollY() + mNotificationTopPadding;
583 float stackHeight = mNotificationStackScroller.getHeight() - start;
584 if (stackHeight <= mMinStackHeight) {
585 float overflow = mMinStackHeight - stackHeight;
586 stackHeight = mMinStackHeight;
587 start = mNotificationStackScroller.getHeight() - stackHeight;
588 mNotificationStackScroller.setTranslationY(overflow);
589 mNotificationTranslation = overflow + mScrollView.getScrollY();
590 } else {
591 mNotificationStackScroller.setTranslationY(0);
592 mNotificationTranslation = mScrollView.getScrollY();
593 }
594 mNotificationStackScroller.setTopPadding(clampQsStackScrollerPadding((int) start), false);
595 }
596
597 private int clampQsStackScrollerPadding(int desiredPadding) {
598 return Math.max(desiredPadding, mStackScrollerIntrinsicPadding);
599 }
600
601 private void trackMovement(MotionEvent event) {
602 if (mVelocityTracker != null) mVelocityTracker.addMovement(event);
Jorim Jaggifc1a8242014-05-12 19:30:05 +0200603 mLastTouchX = event.getX();
604 mLastTouchY = event.getY();
Jorim Jaggid7daab72014-05-06 22:22:20 +0200605 }
606
607 private void initVelocityTracker() {
608 if (mVelocityTracker != null) {
609 mVelocityTracker.recycle();
610 }
611 mVelocityTracker = VelocityTracker.obtain();
612 }
613
614 private float getCurrentVelocity() {
615 if (mVelocityTracker == null) {
616 return 0;
617 }
618 mVelocityTracker.computeCurrentVelocity(1000);
619 return mVelocityTracker.getYVelocity();
620 }
621
622 private void cancelAnimation() {
623 if (mQsExpansionAnimator != null) {
624 mQsExpansionAnimator.cancel();
625 }
626 }
627 private void flingSettings(float vel, boolean expand) {
Jorim Jaggid7daab72014-05-06 22:22:20 +0200628 float target = expand ? mQsMaxExpansionHeight : mQsMinExpansionHeight;
Jorim Jaggi9cd731a2014-05-22 14:26:06 +0200629 if (target == mQsExpansionHeight) {
630 return;
631 }
Jorim Jaggid7daab72014-05-06 22:22:20 +0200632 ValueAnimator animator = ValueAnimator.ofFloat(mQsExpansionHeight, target);
Jorim Jaggi87cd5e72014-05-12 23:29:10 +0200633 mFlingAnimationUtils.apply(animator, mQsExpansionHeight, target, vel);
Jorim Jaggid7daab72014-05-06 22:22:20 +0200634 animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
635 @Override
636 public void onAnimationUpdate(ValueAnimator animation) {
637 setQsExpansion((Float) animation.getAnimatedValue());
638 }
639 });
640 animator.addListener(new AnimatorListenerAdapter() {
641 @Override
642 public void onAnimationEnd(Animator animation) {
643 mQsExpansionAnimator = null;
644 }
645 });
646 animator.start();
647 mQsExpansionAnimator = animator;
648 }
649
650 /**
651 * @return Whether we should intercept a gesture to open Quick Settings.
652 */
Selim Cinek4c6969a2014-05-26 19:22:17 +0200653 private boolean shouldQuickSettingsIntercept(float x, float y, float yDiff) {
Jorim Jaggid7daab72014-05-06 22:22:20 +0200654 if (!mQsExpansionEnabled) {
655 return false;
656 }
Jorim Jaggibc5f4962014-05-12 00:00:52 +0200657 boolean onHeader = x >= mHeader.getLeft() && x <= mHeader.getRight()
John Spurlock3e04cc82014-05-30 12:34:03 -0400658 && y >= mHeader.getTop() && y <= mHeader.getBottom();
Jorim Jaggid7daab72014-05-06 22:22:20 +0200659 if (mQsExpanded) {
John Spurlock3e04cc82014-05-30 12:34:03 -0400660 return onHeader || (mScrollView.isScrolledToBottom() && yDiff < 0);
Jorim Jaggid7daab72014-05-06 22:22:20 +0200661 } else {
662 return onHeader;
663 }
Selim Cinekb6d85eb2014-03-28 20:21:01 +0100664 }
665
666 @Override
Jorim Jaggi0d74eeb2014-05-09 22:05:24 +0200667 public void setVisibility(int visibility) {
668 int oldVisibility = getVisibility();
669 super.setVisibility(visibility);
670 if (visibility != oldVisibility) {
671 reparentStatusIcons(visibility == VISIBLE);
672 }
673 }
674
675 /**
676 * When the notification panel gets expanded, we need to move the status icons in the header
677 * card.
678 */
679 private void reparentStatusIcons(boolean toHeader) {
680 if (mStatusBar == null) {
681 return;
682 }
683 LinearLayout systemIcons = mStatusBar.getSystemIcons();
684 if (systemIcons.getParent() != null) {
685 ((ViewGroup) systemIcons.getParent()).removeView(systemIcons);
686 }
687 if (toHeader) {
688 mHeader.attachSystemIcons(systemIcons);
689 } else {
Jorim Jaggi13c1b1f2014-05-11 21:55:00 +0200690 mHeader.onSystemIconsDetached();
Jorim Jaggi0d74eeb2014-05-09 22:05:24 +0200691 mStatusBar.reattachSystemIcons();
692 }
693 }
694
695 @Override
Selim Cinekb6d85eb2014-03-28 20:21:01 +0100696 protected boolean isScrolledToBottom() {
697 if (!isInSettings()) {
698 return mNotificationStackScroller.isScrolledToBottom();
Chris Wren64161cc2012-12-17 16:49:30 -0500699 }
Selim Cinekb6d85eb2014-03-28 20:21:01 +0100700 return super.isScrolledToBottom();
701 }
702
703 @Override
704 protected int getMaxPanelHeight() {
Jorim Jaggi1d480692014-05-20 19:41:58 +0200705 // TODO: Figure out transition for collapsing when QS is open, adjust height here.
706 int maxPanelHeight = super.getMaxPanelHeight();
707 int emptyBottomMargin = mStackScrollerContainer.getHeight()
708 - mNotificationStackScroller.getHeight()
709 + mNotificationStackScroller.getEmptyBottomMargin();
Jorim Jaggi7d16bb12014-05-22 04:24:50 +0200710 int maxHeight = maxPanelHeight - emptyBottomMargin - mTopPaddingAdjustment;
Jorim Jaggi1d480692014-05-20 19:41:58 +0200711 maxHeight = Math.max(maxHeight, mStatusBarMinHeight);
712 return maxHeight;
Selim Cinekb6d85eb2014-03-28 20:21:01 +0100713 }
714
715 private boolean isInSettings() {
Jorim Jaggid7daab72014-05-06 22:22:20 +0200716 return mQsExpanded;
Selim Cinekb6d85eb2014-03-28 20:21:01 +0100717 }
718
719 @Override
720 protected void onHeightUpdated(float expandedHeight) {
Jorim Jaggi7d16bb12014-05-22 04:24:50 +0200721 if (!mQsExpanded) {
722 positionClockAndNotifications();
723 }
Jorim Jaggi8c1a44b2014-04-29 19:04:02 +0200724 mNotificationStackScroller.setStackHeight(expandedHeight);
Jorim Jaggi457cc352014-06-02 22:47:42 +0200725 updateKeyguardHeaderVisibility();
726 }
727
728 /**
729 * Hides the header when notifications are colliding with it.
730 */
731 private void updateKeyguardHeaderVisibility() {
732 if (mStatusBar.getBarState() == StatusBarState.KEYGUARD
733 || mStatusBar.getBarState() == StatusBarState.SHADE_LOCKED) {
734 boolean hidden = mNotificationStackScroller.getNotificationsTopY()
735 <= mHeader.getBottom() + mNotificationsHeaderCollideDistance;
736 if (hidden && !mHeaderHidden) {
737 mHeader.animate()
738 .alpha(0f)
739 .withLayer()
740 .translationY(-mHeader.getHeight()/2)
741 .setInterpolator(mFastOutLinearInterpolator)
742 .setDuration(200);
743 } else if (!hidden && mHeaderHidden) {
744 mHeader.animate()
745 .alpha(1f)
746 .withLayer()
747 .translationY(0)
748 .setInterpolator(mLinearOutSlowInInterpolator)
749 .setDuration(200);
750 }
751 mHeaderHidden = hidden;
752 } else {
753 mHeader.animate().cancel();
754 mHeader.setAlpha(1f);
755 mHeader.setTranslationY(0f);
756 if (mHeader.getLayerType() != LAYER_TYPE_NONE) {
757 mHeader.setLayerType(LAYER_TYPE_NONE, null);
758 }
759 mHeaderHidden = false;
760 }
761
Selim Cinekb6d85eb2014-03-28 20:21:01 +0100762 }
763
764 @Override
Selim Cinek1685e632014-04-08 02:27:49 +0200765 protected void onExpandingStarted() {
766 super.onExpandingStarted();
767 mNotificationStackScroller.onExpansionStarted();
Selim Cinek4c6969a2014-05-26 19:22:17 +0200768 mIsExpanding = true;
Selim Cinek1685e632014-04-08 02:27:49 +0200769 }
770
771 @Override
772 protected void onExpandingFinished() {
773 super.onExpandingFinished();
774 mNotificationStackScroller.onExpansionStopped();
Selim Cinek4c6969a2014-05-26 19:22:17 +0200775 mIsExpanding = false;
Selim Cinek1685e632014-04-08 02:27:49 +0200776 }
Jorim Jaggibe565df2014-04-28 17:51:23 +0200777
778 @Override
Selim Cinek24120a52014-05-26 10:05:42 +0200779 protected void onOverExpansionChanged(float overExpansion) {
780 float currentOverScroll = mNotificationStackScroller.getCurrentOverScrolledPixels(true);
Selim Cineka02fe522014-05-30 17:01:21 +0200781 float expansionChange = overExpansion - mOverExpansion;
782 expansionChange *= EXPANSION_RUBBER_BAND_EXTRA_FACTOR;
783 mNotificationStackScroller.setOverScrolledPixels(currentOverScroll + expansionChange,
784 true /* onTop */,
785 false /* animate */);
Selim Cinek24120a52014-05-26 10:05:42 +0200786 super.onOverExpansionChanged(overExpansion);
787 }
788
789 @Override
Jorim Jaggi282a6152014-06-02 23:37:53 +0200790 protected void onTrackingStarted() {
791 super.onTrackingStarted();
792 if (mStatusBar.getBarState() == StatusBarState.KEYGUARD
793 || mStatusBar.getBarState() == StatusBarState.SHADE_LOCKED) {
794 mPageSwiper.animateHideLeftRightIcon();
795 }
796 }
797
798 @Override
Jorim Jaggi2fbad7b2014-05-26 22:38:00 +0200799 protected void onTrackingStopped(boolean expand) {
800 super.onTrackingStopped(expand);
Selim Cinek24120a52014-05-26 10:05:42 +0200801 mOverExpansion = 0.0f;
Jorim Jaggib3f0a2f2014-06-02 19:29:39 +0200802 mNotificationStackScroller.setOverScrolledPixels(0.0f, true /* onTop */, true /* animate */);
Jorim Jaggi282a6152014-06-02 23:37:53 +0200803 if (expand && (mStatusBar.getBarState() == StatusBarState.KEYGUARD
804 || mStatusBar.getBarState() == StatusBarState.SHADE_LOCKED)) {
805 mPageSwiper.showAllIcons(true);
806 }
Selim Cinek24120a52014-05-26 10:05:42 +0200807 }
808
Selim Cinek24120a52014-05-26 10:05:42 +0200809 @Override
Jorim Jaggibe565df2014-04-28 17:51:23 +0200810 public void onHeightChanged(ExpandableView view) {
811 requestPanelHeightUpdate();
812 }
Jorim Jaggid7daab72014-05-06 22:22:20 +0200813
814 @Override
815 public void onScrollChanged() {
816 if (mQsExpanded) {
817 mNotificationStackScroller.setTranslationY(
818 mNotificationTranslation - mScrollView.getScrollY());
819 }
820 }
821
822 @Override
Selim Cinek4c6969a2014-05-26 19:22:17 +0200823 protected void onConfigurationChanged(Configuration newConfig) {
824 super.onConfigurationChanged(newConfig);
825 mPageSwiper.onConfigurationChanged();
826 }
827
828 @Override
Jorim Jaggid7daab72014-05-06 22:22:20 +0200829 public void onClick(View v) {
830 if (v == mHeader.getBackgroundView()) {
831 onQsExpansionStarted();
832 if (mQsExpanded) {
833 flingSettings(0 /* vel */, false /* expand */);
834 } else if (mQsExpansionEnabled) {
835 flingSettings(0 /* vel */, true /* expand */);
836 }
837 }
838 }
Selim Cinek4c6969a2014-05-26 19:22:17 +0200839
840 @Override
841 public void onAnimationToSideStarted(boolean rightPage) {
Jorim Jaggib3f0a2f2014-06-02 19:29:39 +0200842 boolean start = getLayoutDirection() == LAYOUT_DIRECTION_RTL ? rightPage : !rightPage;
843 if (start) {
Selim Cinek4c6969a2014-05-26 19:22:17 +0200844 mKeyguardBottomArea.launchPhone();
Jorim Jaggib3f0a2f2014-06-02 19:29:39 +0200845 } else {
846 mKeyguardBottomArea.launchCamera();
Selim Cinek4c6969a2014-05-26 19:22:17 +0200847 }
848 mBlockTouches = true;
849 }
850
Jorim Jaggib3f0a2f2014-06-02 19:29:39 +0200851 @Override
852 protected void onEdgeClicked(boolean right) {
853 if ((right && getRightIcon().getVisibility() != View.VISIBLE)
854 || (!right && getLeftIcon().getVisibility() != View.VISIBLE)) {
855 return;
856 }
857 mHintAnimationRunning = true;
858 mPageSwiper.startHintAnimation(right, new Runnable() {
859 @Override
860 public void run() {
861 mHintAnimationRunning = false;
862 mStatusBar.onHintFinished();
863 }
864 });
Jorim Jaggi93a2bb22014-06-02 19:57:28 +0200865 startHighlightIconAnimation(right ? getRightIcon() : getLeftIcon());
Jorim Jaggib3f0a2f2014-06-02 19:29:39 +0200866 boolean start = getLayoutDirection() == LAYOUT_DIRECTION_RTL ? right : !right;
867 if (start) {
868 mStatusBar.onPhoneHintStarted();
869 } else {
870 mStatusBar.onCameraHintStarted();
871 }
872 }
Selim Cinek4c6969a2014-05-26 19:22:17 +0200873
874 @Override
Jorim Jaggi93a2bb22014-06-02 19:57:28 +0200875 protected void startUnlockHintAnimation() {
876 super.startUnlockHintAnimation();
877 startHighlightIconAnimation(getCenterIcon());
878 }
879
880 /**
881 * Starts the highlight (making it fully opaque) animation on an icon.
882 */
883 private void startHighlightIconAnimation(final View icon) {
884 icon.animate()
885 .alpha(1.0f)
886 .setDuration(KeyguardPageSwipeHelper.HINT_PHASE1_DURATION)
887 .setInterpolator(mFastOutSlowInInterpolator)
888 .withEndAction(new Runnable() {
889 @Override
890 public void run() {
891 icon.animate().alpha(KeyguardPageSwipeHelper.SWIPE_RESTING_ALPHA_AMOUNT)
892 .setDuration(KeyguardPageSwipeHelper.HINT_PHASE1_DURATION)
893 .setInterpolator(mFastOutSlowInInterpolator);
894 }
895 });
896 }
897
898 @Override
Selim Cinek4c6969a2014-05-26 19:22:17 +0200899 public float getPageWidth() {
900 return getWidth();
901 }
902
903 @Override
904 public ArrayList<View> getTranslationViews() {
905 return mSwipeTranslationViews;
906 }
907
908 @Override
909 public View getLeftIcon() {
Jorim Jaggib3f0a2f2014-06-02 19:29:39 +0200910 return getLayoutDirection() == LAYOUT_DIRECTION_RTL
911 ? mKeyguardBottomArea.getCameraImageView()
912 : mKeyguardBottomArea.getPhoneImageView();
Selim Cinek4c6969a2014-05-26 19:22:17 +0200913 }
914
915 @Override
916 public View getCenterIcon() {
917 return mKeyguardBottomArea.getLockIcon();
918 }
919
920 @Override
921 public View getRightIcon() {
Jorim Jaggib3f0a2f2014-06-02 19:29:39 +0200922 return getLayoutDirection() == LAYOUT_DIRECTION_RTL
923 ? mKeyguardBottomArea.getPhoneImageView()
924 : mKeyguardBottomArea.getCameraImageView();
Selim Cinek4c6969a2014-05-26 19:22:17 +0200925 }
Daniel Sandler08d05e32012-08-08 16:39:54 -0400926}