blob: 6789930ab76ef5aefe264b0323f1bdba5eb3874e [file] [log] [blame]
Daniel Sandlerc4f2a562012-05-04 11:55:46 -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
Adrian Roos0bd8a4b2016-03-14 16:21:44 -070019import android.annotation.ColorInt;
20import android.annotation.DrawableRes;
21import android.annotation.LayoutRes;
John Spurlock257f2832013-09-21 18:41:53 -040022import android.app.StatusBarManager;
Daniel Sandlerc4f2a562012-05-04 11:55:46 -040023import android.content.Context;
Adrian Roos0bd8a4b2016-03-14 16:21:44 -070024import android.content.res.Configuration;
Adrian Roos2f2bd9a2015-06-04 18:11:14 -070025import android.content.res.TypedArray;
Daniel Sandler198a0302012-08-17 16:04:31 -040026import android.graphics.Canvas;
27import android.graphics.Paint;
Selim Cineka0fad3b2014-09-19 17:20:05 +020028import android.graphics.PorterDuff;
29import android.graphics.PorterDuffXfermode;
John Spurlockfba91202014-04-22 12:58:26 -040030import android.graphics.Rect;
Adrian Roos0bd8a4b2016-03-14 16:21:44 -070031import android.graphics.drawable.Drawable;
Issei Suzukica19e6e2019-02-26 12:39:11 +010032import android.hardware.display.AmbientDisplayConfiguration;
Jaewan Kim50269362016-12-23 11:22:02 +090033import android.media.AudioManager;
John Spurlock0b99ea92014-10-01 15:32:22 -040034import android.media.session.MediaSessionLegacyHelper;
Adrian Roos0bd8a4b2016-03-14 16:21:44 -070035import android.net.Uri;
36import android.os.Bundle;
Adrian Roos8008bd12017-02-22 15:02:09 +010037import android.os.SystemClock;
Lucas Dupin34f6d962019-02-22 14:47:50 -080038import android.os.UserHandle;
39import android.provider.Settings;
Daniel Sandlerc4f2a562012-05-04 11:55:46 -040040import android.util.AttributeSet;
Adrian Roos0bd8a4b2016-03-14 16:21:44 -070041import android.view.ActionMode;
felkachang7749c9a2018-06-11 15:56:15 +080042import android.view.DisplayCutout;
Lucas Dupin34f6d962019-02-22 14:47:50 -080043import android.view.GestureDetector;
Selim Cinek48a92a52017-05-02 20:02:30 -070044import android.view.InputDevice;
Adrian Roos0bd8a4b2016-03-14 16:21:44 -070045import android.view.InputQueue;
Daniel Sandlerc4f2a562012-05-04 11:55:46 -040046import android.view.KeyEvent;
Adrian Roos0bd8a4b2016-03-14 16:21:44 -070047import android.view.LayoutInflater;
48import android.view.Menu;
49import android.view.MenuItem;
Chris Wren5de6e942012-05-16 14:22:21 -040050import android.view.MotionEvent;
Adrian Roos0bd8a4b2016-03-14 16:21:44 -070051import android.view.SurfaceHolder;
Daniel Sandlerb4e56ed2012-09-12 23:07:44 -070052import android.view.View;
Adrian Roos0bd8a4b2016-03-14 16:21:44 -070053import android.view.ViewGroup;
54import android.view.ViewTreeObserver;
55import android.view.Window;
Jorim Jaggib6030952018-10-23 18:31:52 +020056import android.view.WindowInsetsController;
Daniel Sandlerc4f2a562012-05-04 11:55:46 -040057import android.widget.FrameLayout;
Daniel Sandlerc4f2a562012-05-04 11:55:46 -040058
Selim Cinekf8c4add2017-06-08 09:54:58 -070059import com.android.internal.annotations.VisibleForTesting;
Adrian Roos0bd8a4b2016-03-14 16:21:44 -070060import com.android.internal.view.FloatingActionMode;
61import com.android.internal.widget.FloatingToolbar;
Jason Monk1fd3fc32018-08-14 17:20:09 -040062import com.android.systemui.Dependency;
Aaron Heuckrothcd944dc2018-10-01 16:31:08 -040063import com.android.systemui.ExpandHelper;
Chris Wren5de6e942012-05-16 14:22:21 -040064import com.android.systemui.R;
Dave Mankoff468d4f62019-05-08 14:56:29 -040065import com.android.systemui.plugins.FalsingManager;
Beverly8fdb5332019-02-04 14:29:49 -050066import com.android.systemui.plugins.statusbar.StatusBarStateController;
Jorim Jaggiecbab362014-04-23 16:13:15 +020067import com.android.systemui.statusbar.DragDownHelper;
68import com.android.systemui.statusbar.StatusBarState;
Selim Cinek5454a0d2019-07-30 17:14:50 -070069import com.android.systemui.statusbar.notification.DynamicPrivacyController;
Rohan Shah20790b82018-07-02 17:21:04 -070070import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
Lucas Dupincdbb1cb2019-05-16 19:48:30 -070071import com.android.systemui.statusbar.phone.ScrimController.ScrimVisibility;
Lucas Dupin34f6d962019-02-22 14:47:50 -080072import com.android.systemui.tuner.TunerService;
Chris Wren5de6e942012-05-16 14:22:21 -040073
Selim Cinekfc5c1992018-01-29 12:40:32 -080074import java.io.FileDescriptor;
75import java.io.PrintWriter;
76
Lucas Dupin34f6d962019-02-22 14:47:50 -080077/**
78 * Combined status bar and notification panel view. Also holding backdrop and scrims.
79 */
Jorim Jaggiecbab362014-04-23 16:13:15 +020080public class StatusBarWindowView extends FrameLayout {
Daniel Sandler198a0302012-08-17 16:04:31 -040081 public static final String TAG = "StatusBarWindowView";
Jason Monk2a6ea9c2017-01-26 11:14:51 -050082 public static final boolean DEBUG = StatusBar.DEBUG;
Chris Wren5de6e942012-05-16 14:22:21 -040083
Lucas Dupin34f6d962019-02-22 14:47:50 -080084 private final GestureDetector mGestureDetector;
85 private final StatusBarStateController mStatusBarStateController;
86 private boolean mDoubleTapEnabled;
87 private boolean mSingleTapEnabled;
Jorim Jaggiecbab362014-04-23 16:13:15 +020088 private DragDownHelper mDragDownHelper;
Selim Cinekb6d85eb2014-03-28 20:21:01 +010089 private NotificationStackScrollLayout mStackScrollLayout;
Daniel Sandlerb4e56ed2012-09-12 23:07:44 -070090 private NotificationPanelView mNotificationPanel;
Adrian Roos9dc32092014-09-02 23:34:10 +020091 private View mBrightnessMirror;
Lucas Dupin2e838ac2019-04-17 16:50:58 -070092 private LockIcon mLockIcon;
Jorim Jaggif0c38072018-06-19 17:27:08 +020093 private PhoneStatusBarView mStatusBarView;
Chris Wren5de6e942012-05-16 14:22:21 -040094
Adrian Roos2f2bd9a2015-06-04 18:11:14 -070095 private int mRightInset = 0;
Adrian Roos85d202b2016-06-02 16:27:47 -070096 private int mLeftInset = 0;
Adrian Roos2f2bd9a2015-06-04 18:11:14 -070097
Jason Monk2a6ea9c2017-01-26 11:14:51 -050098 private StatusBar mService;
Selim Cineka0fad3b2014-09-19 17:20:05 +020099 private final Paint mTransparentSrcPaint = new Paint();
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700100 private FalsingManager mFalsingManager;
Daniel Sandlerc4f2a562012-05-04 11:55:46 -0400101
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700102 // Implements the floating action mode for TextView's Cut/Copy/Past menu. Normally provided by
103 // DecorView, but since this is a special window we have to roll our own.
104 private View mFloatingActionModeOriginatingView;
105 private ActionMode mFloatingActionMode;
106 private FloatingToolbar mFloatingToolbar;
107 private ViewTreeObserver.OnPreDrawListener mFloatingToolbarPreDrawListener;
Selim Cinek48a92a52017-05-02 20:02:30 -0700108 private boolean mTouchCancelled;
109 private boolean mTouchActive;
Selim Cinek2627d722018-01-19 12:16:49 -0800110 private boolean mExpandAnimationRunning;
Selim Cinek7e222c3c2018-01-25 12:22:41 -0800111 private boolean mExpandAnimationPending;
Jerry Changf89d8572019-04-18 11:09:13 +0800112 private boolean mSuppressingWakeUpGesture;
Lucas Dupin34f6d962019-02-22 14:47:50 -0800113
114 private final GestureDetector.SimpleOnGestureListener mGestureListener =
115 new GestureDetector.SimpleOnGestureListener() {
116 @Override
117 public boolean onSingleTapConfirmed(MotionEvent e) {
Jerry Changf89d8572019-04-18 11:09:13 +0800118 if (mSingleTapEnabled && !mSuppressingWakeUpGesture) {
Lucas Dupin34f6d962019-02-22 14:47:50 -0800119 mService.wakeUpIfDozing(SystemClock.uptimeMillis(), StatusBarWindowView.this,
120 "SINGLE_TAP");
Lucas Dupin3bab3d82019-03-22 14:38:28 -0700121 return true;
Lucas Dupin34f6d962019-02-22 14:47:50 -0800122 }
Lucas Dupin3bab3d82019-03-22 14:38:28 -0700123 return false;
Lucas Dupin34f6d962019-02-22 14:47:50 -0800124 }
125
126 @Override
127 public boolean onDoubleTap(MotionEvent e) {
Lucas Dupin3bab3d82019-03-22 14:38:28 -0700128 if (mDoubleTapEnabled || mSingleTapEnabled) {
Lucas Dupin34f6d962019-02-22 14:47:50 -0800129 mService.wakeUpIfDozing(SystemClock.uptimeMillis(), StatusBarWindowView.this,
130 "DOUBLE_TAP");
Lucas Dupin3bab3d82019-03-22 14:38:28 -0700131 return true;
Lucas Dupin34f6d962019-02-22 14:47:50 -0800132 }
Lucas Dupin3bab3d82019-03-22 14:38:28 -0700133 return false;
Lucas Dupin34f6d962019-02-22 14:47:50 -0800134 }
135 };
136 private final TunerService.Tunable mTunable = (key, newValue) -> {
137 AmbientDisplayConfiguration configuration = new AmbientDisplayConfiguration(mContext);
138 switch (key) {
139 case Settings.Secure.DOZE_DOUBLE_TAP_GESTURE:
140 mDoubleTapEnabled = configuration.doubleTapGestureEnabled(UserHandle.USER_CURRENT);
141 break;
142 case Settings.Secure.DOZE_TAP_SCREEN_GESTURE:
143 mSingleTapEnabled = configuration.tapGestureEnabled(UserHandle.USER_CURRENT);
144 }
145 };
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700146
Jorim Jaggi0d4a9952018-06-06 17:22:56 +0200147 /**
148 * If set to true, the current gesture started below the notch and we need to dispatch touch
149 * events manually as it's outside of the regular view bounds.
150 */
151 private boolean mExpandingBelowNotch;
Selim Cinekb8cc6ef2019-06-14 16:37:53 -0700152 private KeyguardBypassController mBypassController;
Jorim Jaggi0d4a9952018-06-06 17:22:56 +0200153
Daniel Sandlerc4f2a562012-05-04 11:55:46 -0400154 public StatusBarWindowView(Context context, AttributeSet attrs) {
155 super(context, attrs);
Chris Wren5de6e942012-05-16 14:22:21 -0400156 setMotionEventSplittingEnabled(false);
Selim Cineka0fad3b2014-09-19 17:20:05 +0200157 mTransparentSrcPaint.setColor(0);
158 mTransparentSrcPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
Dave Mankoff781ef7e2019-06-28 16:33:25 -0400159 mFalsingManager = Dependency.get(FalsingManager.class); // TODO: inject into a controller.
Lucas Dupin34f6d962019-02-22 14:47:50 -0800160 mGestureDetector = new GestureDetector(context, mGestureListener);
161 mStatusBarStateController = Dependency.get(StatusBarStateController.class);
162 Dependency.get(TunerService.class).addTunable(mTunable,
163 Settings.Secure.DOZE_DOUBLE_TAP_GESTURE,
164 Settings.Secure.DOZE_TAP_SCREEN_GESTURE);
Chris Wren5de6e942012-05-16 14:22:21 -0400165 }
166
167 @Override
John Spurlockfba91202014-04-22 12:58:26 -0400168 protected boolean fitSystemWindows(Rect insets) {
169 if (getFitsSystemWindows()) {
Adrian Roos85d202b2016-06-02 16:27:47 -0700170 boolean paddingChanged = insets.top != getPaddingTop()
Jorim Jaggi416493b2014-09-13 03:57:32 +0200171 || insets.bottom != getPaddingBottom();
Jorim Jaggiaa806142015-05-20 18:04:16 -0700172
felkachang7749c9a2018-06-11 15:56:15 +0800173 int rightCutout = 0;
174 int leftCutout = 0;
175 DisplayCutout displayCutout = getRootWindowInsets().getDisplayCutout();
176 if (displayCutout != null) {
177 leftCutout = displayCutout.getSafeInsetLeft();
178 rightCutout = displayCutout.getSafeInsetRight();
179 }
180
181 int targetLeft = Math.max(insets.left, leftCutout);
182 int targetRight = Math.max(insets.right, rightCutout);
183
Adrian Roos2f2bd9a2015-06-04 18:11:14 -0700184 // Super-special right inset handling, because scrims and backdrop need to ignore it.
felkachang7749c9a2018-06-11 15:56:15 +0800185 if (targetRight != mRightInset || targetLeft != mLeftInset) {
186 mRightInset = targetRight;
187 mLeftInset = targetLeft;
Adrian Roos2f2bd9a2015-06-04 18:11:14 -0700188 applyMargins();
189 }
Adrian Roos85d202b2016-06-02 16:27:47 -0700190 // Drop top inset, and pass through bottom inset.
Adrian Roos2f2bd9a2015-06-04 18:11:14 -0700191 if (paddingChanged) {
Adrian Roos85d202b2016-06-02 16:27:47 -0700192 setPadding(0, 0, 0, 0);
Jorim Jaggi416493b2014-09-13 03:57:32 +0200193 }
Jorim Jaggid7daab72014-05-06 22:22:20 +0200194 insets.left = 0;
195 insets.top = 0;
196 insets.right = 0;
John Spurlockfba91202014-04-22 12:58:26 -0400197 } else {
Adrian Roos85d202b2016-06-02 16:27:47 -0700198 if (mRightInset != 0 || mLeftInset != 0) {
Adrian Roose49e4092015-06-10 18:50:18 -0700199 mRightInset = 0;
Adrian Roos85d202b2016-06-02 16:27:47 -0700200 mLeftInset = 0;
Adrian Roose49e4092015-06-10 18:50:18 -0700201 applyMargins();
202 }
Jorim Jaggi416493b2014-09-13 03:57:32 +0200203 boolean changed = getPaddingLeft() != 0
204 || getPaddingRight() != 0
205 || getPaddingTop() != 0
206 || getPaddingBottom() != 0;
207 if (changed) {
208 setPadding(0, 0, 0, 0);
209 }
Jorim Jaggiaa806142015-05-20 18:04:16 -0700210 insets.top = 0;
John Spurlockfba91202014-04-22 12:58:26 -0400211 }
Jorim Jaggid7daab72014-05-06 22:22:20 +0200212 return false;
John Spurlockfba91202014-04-22 12:58:26 -0400213 }
214
Adrian Roos2f2bd9a2015-06-04 18:11:14 -0700215 private void applyMargins() {
216 final int N = getChildCount();
217 for (int i = 0; i < N; i++) {
218 View child = getChildAt(i);
219 if (child.getLayoutParams() instanceof LayoutParams) {
220 LayoutParams lp = (LayoutParams) child.getLayoutParams();
Adrian Roos85d202b2016-06-02 16:27:47 -0700221 if (!lp.ignoreRightInset
222 && (lp.rightMargin != mRightInset || lp.leftMargin != mLeftInset)) {
Adrian Roos2f2bd9a2015-06-04 18:11:14 -0700223 lp.rightMargin = mRightInset;
Adrian Roos85d202b2016-06-02 16:27:47 -0700224 lp.leftMargin = mLeftInset;
Adrian Roos2f2bd9a2015-06-04 18:11:14 -0700225 child.requestLayout();
226 }
227 }
228 }
229 }
230
Aaron Heuckrothcd944dc2018-10-01 16:31:08 -0400231 @VisibleForTesting
232 protected NotificationStackScrollLayout getStackScrollLayout() {
233 return mStackScrollLayout;
234 }
235
Adrian Roos2f2bd9a2015-06-04 18:11:14 -0700236 @Override
237 public FrameLayout.LayoutParams generateLayoutParams(AttributeSet attrs) {
238 return new LayoutParams(getContext(), attrs);
239 }
240
241 @Override
242 protected FrameLayout.LayoutParams generateDefaultLayoutParams() {
243 return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
244 }
245
John Spurlockfba91202014-04-22 12:58:26 -0400246 @Override
Selim Cinek4e6b2d32015-06-25 20:15:33 -0400247 protected void onFinishInflate() {
248 super.onFinishInflate();
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700249 mStackScrollLayout = findViewById(R.id.notification_stack_scroller);
250 mNotificationPanel = findViewById(R.id.notification_panel);
Adrian Roos9dc32092014-09-02 23:34:10 +0200251 mBrightnessMirror = findViewById(R.id.brightness_mirror);
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700252 mLockIcon = findViewById(R.id.lock_icon);
Selim Cinek4e6b2d32015-06-25 20:15:33 -0400253 }
254
dooyoung.hwange4b841e2016-11-16 08:59:23 +0900255 @Override
256 public void onViewAdded(View child) {
257 super.onViewAdded(child);
258 if (child.getId() == R.id.brightness_mirror) {
259 mBrightnessMirror = child;
260 }
261 }
262
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700263 /**
264 * Propagate {@link StatusBar} pulsing state.
265 */
266 public void setPulsing(boolean pulsing) {
Lucas Dupin2d336632019-05-14 12:13:26 -0700267 if (mLockIcon != null) {
268 mLockIcon.setPulsing(pulsing);
269 }
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700270 }
271
Lucas Dupin71f38042019-05-10 16:23:04 -0700272 /**
273 * Called when the biometric authentication mode changes.
274 * @param wakeAndUnlock If the type is {@link BiometricUnlockController#isWakeAndUnlock()}
Selim Cinek390f1b92019-06-28 18:07:28 -0700275 * @param isUnlock If the type is {@link BiometricUnlockController#isBiometricUnlock()} ()
Lucas Dupin71f38042019-05-10 16:23:04 -0700276 */
Selim Cinek390f1b92019-06-28 18:07:28 -0700277 public void onBiometricAuthModeChanged(boolean wakeAndUnlock, boolean isUnlock) {
Lucas Dupin2d336632019-05-14 12:13:26 -0700278 if (mLockIcon != null) {
Selim Cinek390f1b92019-06-28 18:07:28 -0700279 mLockIcon.onBiometricAuthModeChanged(wakeAndUnlock, isUnlock);
Lucas Dupin2d336632019-05-14 12:13:26 -0700280 }
Lucas Dupin71f38042019-05-10 16:23:04 -0700281 }
282
Jorim Jaggif0c38072018-06-19 17:27:08 +0200283 public void setStatusBarView(PhoneStatusBarView statusBarView) {
284 mStatusBarView = statusBarView;
285 }
286
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500287 public void setService(StatusBar service) {
Selim Cinek4e6b2d32015-06-25 20:15:33 -0400288 mService = service;
Aaron Heuckrothcd944dc2018-10-01 16:31:08 -0400289 NotificationStackScrollLayout stackScrollLayout = getStackScrollLayout();
290 ExpandHelper.Callback expandHelperCallback = stackScrollLayout.getExpandHelperCallback();
291 DragDownHelper.DragDownCallback dragDownCallback = stackScrollLayout.getDragDownCallback();
292 setDragDownHelper(new DragDownHelper(getContext(), this, expandHelperCallback,
Dave Mankoff781ef7e2019-06-28 16:33:25 -0400293 dragDownCallback, mFalsingManager));
Selim Cinekf8c4add2017-06-08 09:54:58 -0700294 }
295
296 @VisibleForTesting
297 void setDragDownHelper(DragDownHelper dragDownHelper) {
298 mDragDownHelper = dragDownHelper;
Selim Cinek4e6b2d32015-06-25 20:15:33 -0400299 }
300
301 @Override
302 protected void onAttachedToWindow () {
303 super.onAttachedToWindow();
Lucas Dupin90a38dd2018-09-05 09:37:37 -0700304 setWillNotDraw(!DEBUG);
Daniel Sandlerc4f2a562012-05-04 11:55:46 -0400305 }
306
307 @Override
308 public boolean dispatchKeyEvent(KeyEvent event) {
Adrian Roos56cf73a2016-07-18 14:23:32 -0700309 if (mService.interceptMediaKey(event)) {
310 return true;
311 }
312 if (super.dispatchKeyEvent(event)) {
313 return true;
314 }
Daniel Sandlerc4f2a562012-05-04 11:55:46 -0400315 boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
316 switch (event.getKeyCode()) {
Jorim Jaggi8c8bcc12014-04-16 21:36:51 +0200317 case KeyEvent.KEYCODE_BACK:
318 if (!down) {
319 mService.onBackPressed();
320 }
321 return true;
322 case KeyEvent.KEYCODE_MENU:
323 if (!down) {
324 return mService.onMenuPressed();
325 }
Jorim Jaggi34250762014-07-03 23:51:19 +0200326 case KeyEvent.KEYCODE_SPACE:
327 if (!down) {
328 return mService.onSpacePressed();
329 }
John Spurlock0b99ea92014-10-01 15:32:22 -0400330 break;
John Spurlockd06aa572014-09-10 10:40:49 -0400331 case KeyEvent.KEYCODE_VOLUME_DOWN:
332 case KeyEvent.KEYCODE_VOLUME_UP:
John Spurlock0b99ea92014-10-01 15:32:22 -0400333 if (mService.isDozing()) {
Jaewan Kim50269362016-12-23 11:22:02 +0900334 MediaSessionLegacyHelper.getHelper(mContext).sendVolumeKeyEvent(
335 event, AudioManager.USE_DEFAULT_STREAM_TYPE, true);
John Spurlock0b99ea92014-10-01 15:32:22 -0400336 return true;
John Spurlockd06aa572014-09-10 10:40:49 -0400337 }
John Spurlock0b99ea92014-10-01 15:32:22 -0400338 break;
Daniel Sandlerc4f2a562012-05-04 11:55:46 -0400339 }
Adrian Roos56cf73a2016-07-18 14:23:32 -0700340 return false;
Daniel Sandlerc4f2a562012-05-04 11:55:46 -0400341 }
Chris Wren5de6e942012-05-16 14:22:21 -0400342
Selim Cinekd95ca7c2017-07-26 12:20:38 -0700343 public void setTouchActive(boolean touchActive) {
344 mTouchActive = touchActive;
Selim Cinekd95ca7c2017-07-26 12:20:38 -0700345 }
346
Jerry Changf89d8572019-04-18 11:09:13 +0800347 void suppressWakeUpGesture(boolean suppress) {
348 mSuppressingWakeUpGesture = suppress;
349 }
350
Chris Wren5de6e942012-05-16 14:22:21 -0400351 @Override
Adrian Roos9dc32092014-09-02 23:34:10 +0200352 public boolean dispatchTouchEvent(MotionEvent ev) {
Selim Cinek48a92a52017-05-02 20:02:30 -0700353 boolean isDown = ev.getActionMasked() == MotionEvent.ACTION_DOWN;
Jorim Jaggi0d4a9952018-06-06 17:22:56 +0200354 boolean isUp = ev.getActionMasked() == MotionEvent.ACTION_UP;
Adrian Roosa6c03f82017-07-26 16:20:30 +0200355 boolean isCancel = ev.getActionMasked() == MotionEvent.ACTION_CANCEL;
Jorim Jaggi0d4a9952018-06-06 17:22:56 +0200356
357 // Reset manual touch dispatch state here but make sure the UP/CANCEL event still gets
358 // delivered.
359 boolean expandingBelowNotch = mExpandingBelowNotch;
360 if (isUp || isCancel) {
361 mExpandingBelowNotch = false;
362 }
363
Adrian Roosa6c03f82017-07-26 16:20:30 +0200364 if (!isCancel && mService.shouldIgnoreTouch()) {
365 return false;
366 }
Selim Cinek48a92a52017-05-02 20:02:30 -0700367 if (isDown && mNotificationPanel.isFullyCollapsed()) {
Jorim Jaggie05256e2016-09-08 14:58:20 -0700368 mNotificationPanel.startExpandLatencyTracking();
369 }
Selim Cinek48a92a52017-05-02 20:02:30 -0700370 if (isDown) {
Selim Cinekd95ca7c2017-07-26 12:20:38 -0700371 setTouchActive(true);
Selim Cinek48a92a52017-05-02 20:02:30 -0700372 mTouchCancelled = false;
373 } else if (ev.getActionMasked() == MotionEvent.ACTION_UP
374 || ev.getActionMasked() == MotionEvent.ACTION_CANCEL) {
Selim Cinekd95ca7c2017-07-26 12:20:38 -0700375 setTouchActive(false);
Selim Cinek48a92a52017-05-02 20:02:30 -0700376 }
Selim Cinek7e222c3c2018-01-25 12:22:41 -0800377 if (mTouchCancelled || mExpandAnimationRunning || mExpandAnimationPending) {
Selim Cinek48a92a52017-05-02 20:02:30 -0700378 return false;
379 }
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700380 mFalsingManager.onTouchEvent(ev, getWidth(), getHeight());
Lucas Dupin34f6d962019-02-22 14:47:50 -0800381 mGestureDetector.onTouchEvent(ev);
Adrian Roos9dc32092014-09-02 23:34:10 +0200382 if (mBrightnessMirror != null && mBrightnessMirror.getVisibility() == VISIBLE) {
383 // Disallow new pointers while the brightness mirror is visible. This is so that you
384 // can't touch anything other than the brightness slider while the mirror is showing
385 // and the rest of the panel is transparent.
386 if (ev.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN) {
387 return false;
388 }
389 }
Selim Cinek48a92a52017-05-02 20:02:30 -0700390 if (isDown) {
Aaron Heuckrothcd944dc2018-10-01 16:31:08 -0400391 getStackScrollLayout().closeControlsIfOutsideTouch(ev);
Mady Mellor7a9b2a62016-03-23 07:41:47 -0700392 }
Adrian Roos67cca742017-04-13 16:52:51 -0700393 if (mService.isDozing()) {
394 mService.mDozeScrimController.extendPulse();
395 }
Mady Mellor7a9b2a62016-03-23 07:41:47 -0700396
Jorim Jaggi0d4a9952018-06-06 17:22:56 +0200397 // In case we start outside of the view bounds (below the status bar), we need to dispatch
398 // the touch manually as the view system can't accomodate for touches outside of the
399 // regular view bounds.
400 if (isDown && ev.getY() >= mBottom) {
401 mExpandingBelowNotch = true;
402 expandingBelowNotch = true;
403 }
404 if (expandingBelowNotch) {
Jorim Jaggif0c38072018-06-19 17:27:08 +0200405 return mStatusBarView.dispatchTouchEvent(ev);
Jorim Jaggi0d4a9952018-06-06 17:22:56 +0200406 }
407
Adrian Roos9dc32092014-09-02 23:34:10 +0200408 return super.dispatchTouchEvent(ev);
409 }
410
411 @Override
Chris Wren5de6e942012-05-16 14:22:21 -0400412 public boolean onInterceptTouchEvent(MotionEvent ev) {
Aaron Heuckrothcd944dc2018-10-01 16:31:08 -0400413 NotificationStackScrollLayout stackScrollLayout = getStackScrollLayout();
Lucas Dupin1c327432019-01-03 13:37:53 -0800414 if (mService.isDozing() && !mService.isPulsing()) {
Adrian Roos8008bd12017-02-22 15:02:09 +0100415 // Capture all touch events in always-on.
Adrian Roosebea7a72016-10-26 12:51:26 -0700416 return true;
417 }
Daniel Sandlerb4e56ed2012-09-12 23:07:44 -0700418 boolean intercept = false;
Selim Cinekfab078b2014-03-27 22:45:58 +0100419 if (mNotificationPanel.isFullyExpanded()
Selim Cinek5454a0d2019-07-30 17:14:50 -0700420 && mDragDownHelper.isDragDownEnabled()
Selim Cinek3d6ae232019-01-04 14:14:33 -0800421 && !mService.isBouncerShowing()
422 && !mService.isDozing()) {
Jorim Jaggiecbab362014-04-23 16:13:15 +0200423 intercept = mDragDownHelper.onInterceptTouchEvent(ev);
Daniel Sandlerb4e56ed2012-09-12 23:07:44 -0700424 }
425 if (!intercept) {
426 super.onInterceptTouchEvent(ev);
427 }
Chris Wren5de6e942012-05-16 14:22:21 -0400428 if (intercept) {
Dianne Hackborna4b7f2f2012-05-21 11:28:41 -0700429 MotionEvent cancellation = MotionEvent.obtain(ev);
430 cancellation.setAction(MotionEvent.ACTION_CANCEL);
Aaron Heuckrothcd944dc2018-10-01 16:31:08 -0400431 stackScrollLayout.onInterceptTouchEvent(cancellation);
Selim Cinek31094df2014-08-14 19:28:15 +0200432 mNotificationPanel.onInterceptTouchEvent(cancellation);
Dianne Hackborna4b7f2f2012-05-21 11:28:41 -0700433 cancellation.recycle();
Chris Wren5de6e942012-05-16 14:22:21 -0400434 }
435 return intercept;
436 }
437
438 @Override
439 public boolean onTouchEvent(MotionEvent ev) {
Adrian Roos8008bd12017-02-22 15:02:09 +0100440 boolean handled = false;
441 if (mService.isDozing()) {
Lucas Dupin1c327432019-01-03 13:37:53 -0800442 handled = !mService.isPulsing();
Adrian Roos8008bd12017-02-22 15:02:09 +0100443 }
Selim Cinek5454a0d2019-07-30 17:14:50 -0700444 if ((mDragDownHelper.isDragDownEnabled() && !handled) || mDragDownHelper.isDraggingDown()) {
Selim Cinek740c1112016-12-22 16:39:54 +0100445 // we still want to finish our drag down gesture when locking the screen
Jorim Jaggiecbab362014-04-23 16:13:15 +0200446 handled = mDragDownHelper.onTouchEvent(ev);
Daniel Sandlerb4e56ed2012-09-12 23:07:44 -0700447 }
448 if (!handled) {
449 handled = super.onTouchEvent(ev);
450 }
John Spurlock257f2832013-09-21 18:41:53 -0400451 final int action = ev.getAction();
John Spurlockd157ca02013-11-04 10:28:05 -0500452 if (!handled && (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL)) {
John Spurlock257f2832013-09-21 18:41:53 -0400453 mService.setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
454 }
Chris Wren5de6e942012-05-16 14:22:21 -0400455 return handled;
456 }
Daniel Sandler198a0302012-08-17 16:04:31 -0400457
458 @Override
459 public void onDraw(Canvas canvas) {
460 super.onDraw(canvas);
461 if (DEBUG) {
462 Paint pt = new Paint();
463 pt.setColor(0x80FFFF00);
464 pt.setStrokeWidth(12.0f);
465 pt.setStyle(Paint.Style.STROKE);
466 canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), pt);
467 }
468 }
Daniel Sandlerac47ff72012-10-23 10:41:44 -0400469
470 public void cancelExpandHelper() {
Aaron Heuckrothcd944dc2018-10-01 16:31:08 -0400471 NotificationStackScrollLayout stackScrollLayout = getStackScrollLayout();
472 if (stackScrollLayout != null) {
473 stackScrollLayout.cancelExpandHelper();
Daniel Sandler1a3bdd52012-10-23 19:21:20 -0400474 }
Daniel Sandlerac47ff72012-10-23 10:41:44 -0400475 }
Adrian Roos2f2bd9a2015-06-04 18:11:14 -0700476
Selim Cinek48a92a52017-05-02 20:02:30 -0700477 public void cancelCurrentTouch() {
478 if (mTouchActive) {
479 final long now = SystemClock.uptimeMillis();
480 MotionEvent event = MotionEvent.obtain(now, now,
481 MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
482 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
483 dispatchTouchEvent(event);
484 event.recycle();
485 mTouchCancelled = true;
486 }
487 }
488
Selim Cinek2627d722018-01-19 12:16:49 -0800489 public void setExpandAnimationRunning(boolean expandAnimationRunning) {
490 mExpandAnimationRunning = expandAnimationRunning;
491 }
492
Selim Cinek7e222c3c2018-01-25 12:22:41 -0800493 public void setExpandAnimationPending(boolean pending) {
494 mExpandAnimationPending = pending;
495 }
496
Selim Cinekfc5c1992018-01-29 12:40:32 -0800497 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
498 pw.print(" mExpandAnimationPending="); pw.println(mExpandAnimationPending);
499 pw.print(" mExpandAnimationRunning="); pw.println(mExpandAnimationRunning);
500 pw.print(" mTouchCancelled="); pw.println(mTouchCancelled);
501 pw.print(" mTouchActive="); pw.println(mTouchActive);
502 }
503
Lucas Dupincdbb1cb2019-05-16 19:48:30 -0700504 /**
505 * Called whenever the scrims become opaque, transparent or semi-transparent.
506 */
507 public void onScrimVisibilityChanged(@ScrimVisibility int scrimsVisible) {
508 if (mLockIcon != null) {
509 mLockIcon.onScrimVisibilityChanged(scrimsVisible);
510 }
511 }
512
Lucas Dupin23964c72019-05-21 16:12:45 -0700513 /**
514 * When we're launching an affordance, like double pressing power to open camera.
515 */
516 public void onShowingLaunchAffordanceChanged(boolean showing) {
517 if (mLockIcon != null) {
518 mLockIcon.onShowingLaunchAffordanceChanged(showing);
519 }
520 }
521
Selim Cinekb8cc6ef2019-06-14 16:37:53 -0700522 public void setBypassController(KeyguardBypassController bypassController) {
523 mBypassController = bypassController;
524 }
525
Selim Cinek60ee7fd2019-06-26 13:06:00 -0700526 public void setBouncerShowingScrimmed(boolean bouncerShowing) {
Selim Cinek820ba2d2019-06-18 18:59:09 -0700527 if (mLockIcon != null) {
Selim Cinek60ee7fd2019-06-26 13:06:00 -0700528 mLockIcon.setBouncerShowingScrimmed(bouncerShowing);
Selim Cinek820ba2d2019-06-18 18:59:09 -0700529 }
530 }
531
Adrian Roos2f2bd9a2015-06-04 18:11:14 -0700532 public class LayoutParams extends FrameLayout.LayoutParams {
533
534 public boolean ignoreRightInset;
535
536 public LayoutParams(int width, int height) {
537 super(width, height);
538 }
539
540 public LayoutParams(Context c, AttributeSet attrs) {
541 super(c, attrs);
542
543 TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.StatusBarWindowView_Layout);
544 ignoreRightInset = a.getBoolean(
545 R.styleable.StatusBarWindowView_Layout_ignoreRightInset, false);
546 a.recycle();
547 }
548 }
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700549
550 @Override
551 public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback,
552 int type) {
553 if (type == ActionMode.TYPE_FLOATING) {
554 return startActionMode(originalView, callback, type);
555 }
556 return super.startActionModeForChild(originalView, callback, type);
557 }
558
559 private ActionMode createFloatingActionMode(
560 View originatingView, ActionMode.Callback2 callback) {
561 if (mFloatingActionMode != null) {
562 mFloatingActionMode.finish();
563 }
564 cleanupFloatingActionModeViews();
Tarandeep Singhc9c83a92017-08-29 14:39:22 -0700565 mFloatingToolbar = new FloatingToolbar(mFakeWindow);
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700566 final FloatingActionMode mode =
Abodunrinwa Toki17293cc2017-05-22 14:16:04 +0100567 new FloatingActionMode(mContext, callback, originatingView, mFloatingToolbar);
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700568 mFloatingActionModeOriginatingView = originatingView;
569 mFloatingToolbarPreDrawListener =
570 new ViewTreeObserver.OnPreDrawListener() {
571 @Override
572 public boolean onPreDraw() {
573 mode.updateViewLocationInWindow();
574 return true;
575 }
576 };
577 return mode;
578 }
579
580 private void setHandledFloatingActionMode(ActionMode mode) {
581 mFloatingActionMode = mode;
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700582 mFloatingActionMode.invalidate(); // Will show the floating toolbar if necessary.
583 mFloatingActionModeOriginatingView.getViewTreeObserver()
584 .addOnPreDrawListener(mFloatingToolbarPreDrawListener);
585 }
586
587 private void cleanupFloatingActionModeViews() {
588 if (mFloatingToolbar != null) {
589 mFloatingToolbar.dismiss();
590 mFloatingToolbar = null;
591 }
592 if (mFloatingActionModeOriginatingView != null) {
593 if (mFloatingToolbarPreDrawListener != null) {
594 mFloatingActionModeOriginatingView.getViewTreeObserver()
595 .removeOnPreDrawListener(mFloatingToolbarPreDrawListener);
596 mFloatingToolbarPreDrawListener = null;
597 }
598 mFloatingActionModeOriginatingView = null;
599 }
600 }
601
602 private ActionMode startActionMode(
603 View originatingView, ActionMode.Callback callback, int type) {
604 ActionMode.Callback2 wrappedCallback = new ActionModeCallback2Wrapper(callback);
605 ActionMode mode = createFloatingActionMode(originatingView, wrappedCallback);
606 if (mode != null && wrappedCallback.onCreateActionMode(mode, mode.getMenu())) {
607 setHandledFloatingActionMode(mode);
608 } else {
609 mode = null;
610 }
611 return mode;
612 }
613
614 private class ActionModeCallback2Wrapper extends ActionMode.Callback2 {
615 private final ActionMode.Callback mWrapped;
616
617 public ActionModeCallback2Wrapper(ActionMode.Callback wrapped) {
618 mWrapped = wrapped;
619 }
620
621 public boolean onCreateActionMode(ActionMode mode, Menu menu) {
622 return mWrapped.onCreateActionMode(mode, menu);
623 }
624
625 public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
626 requestFitSystemWindows();
627 return mWrapped.onPrepareActionMode(mode, menu);
628 }
629
630 public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
631 return mWrapped.onActionItemClicked(mode, item);
632 }
633
634 public void onDestroyActionMode(ActionMode mode) {
635 mWrapped.onDestroyActionMode(mode);
636 if (mode == mFloatingActionMode) {
637 cleanupFloatingActionModeViews();
638 mFloatingActionMode = null;
639 }
640 requestFitSystemWindows();
641 }
642
643 @Override
644 public void onGetContentRect(ActionMode mode, View view, Rect outRect) {
645 if (mWrapped instanceof ActionMode.Callback2) {
646 ((ActionMode.Callback2) mWrapped).onGetContentRect(mode, view, outRect);
647 } else {
648 super.onGetContentRect(mode, view, outRect);
649 }
650 }
651 }
652
653 /**
654 * Minimal window to satisfy FloatingToolbar.
655 */
656 private Window mFakeWindow = new Window(mContext) {
657 @Override
658 public void takeSurface(SurfaceHolder.Callback2 callback) {
659 }
660
661 @Override
662 public void takeInputQueue(InputQueue.Callback callback) {
663 }
664
665 @Override
666 public boolean isFloating() {
667 return false;
668 }
669
670 @Override
671 public void alwaysReadCloseOnTouchAttr() {
672 }
673
674 @Override
675 public void setContentView(@LayoutRes int layoutResID) {
676 }
677
678 @Override
679 public void setContentView(View view) {
680 }
681
682 @Override
683 public void setContentView(View view, ViewGroup.LayoutParams params) {
684 }
685
686 @Override
687 public void addContentView(View view, ViewGroup.LayoutParams params) {
688 }
689
690 @Override
691 public void clearContentView() {
692 }
693
694 @Override
695 public View getCurrentFocus() {
696 return null;
697 }
698
699 @Override
700 public LayoutInflater getLayoutInflater() {
701 return null;
702 }
703
704 @Override
705 public void setTitle(CharSequence title) {
706 }
707
708 @Override
709 public void setTitleColor(@ColorInt int textColor) {
710 }
711
712 @Override
713 public void openPanel(int featureId, KeyEvent event) {
714 }
715
716 @Override
717 public void closePanel(int featureId) {
718 }
719
720 @Override
721 public void togglePanel(int featureId, KeyEvent event) {
722 }
723
724 @Override
725 public void invalidatePanelMenu(int featureId) {
726 }
727
728 @Override
729 public boolean performPanelShortcut(int featureId, int keyCode, KeyEvent event, int flags) {
730 return false;
731 }
732
733 @Override
734 public boolean performPanelIdentifierAction(int featureId, int id, int flags) {
735 return false;
736 }
737
738 @Override
739 public void closeAllPanels() {
740 }
741
742 @Override
743 public boolean performContextMenuIdentifierAction(int id, int flags) {
744 return false;
745 }
746
747 @Override
748 public void onConfigurationChanged(Configuration newConfig) {
749 }
750
751 @Override
752 public void setBackgroundDrawable(Drawable drawable) {
753 }
754
755 @Override
756 public void setFeatureDrawableResource(int featureId, @DrawableRes int resId) {
757 }
758
759 @Override
760 public void setFeatureDrawableUri(int featureId, Uri uri) {
761 }
762
763 @Override
764 public void setFeatureDrawable(int featureId, Drawable drawable) {
765 }
766
767 @Override
768 public void setFeatureDrawableAlpha(int featureId, int alpha) {
769 }
770
771 @Override
772 public void setFeatureInt(int featureId, int value) {
773 }
774
775 @Override
776 public void takeKeyEvents(boolean get) {
777 }
778
779 @Override
780 public boolean superDispatchKeyEvent(KeyEvent event) {
781 return false;
782 }
783
784 @Override
785 public boolean superDispatchKeyShortcutEvent(KeyEvent event) {
786 return false;
787 }
788
789 @Override
790 public boolean superDispatchTouchEvent(MotionEvent event) {
791 return false;
792 }
793
794 @Override
795 public boolean superDispatchTrackballEvent(MotionEvent event) {
796 return false;
797 }
798
799 @Override
800 public boolean superDispatchGenericMotionEvent(MotionEvent event) {
801 return false;
802 }
803
804 @Override
805 public View getDecorView() {
806 return StatusBarWindowView.this;
807 }
808
809 @Override
810 public View peekDecorView() {
811 return null;
812 }
813
814 @Override
815 public Bundle saveHierarchyState() {
816 return null;
817 }
818
819 @Override
820 public void restoreHierarchyState(Bundle savedInstanceState) {
821 }
822
823 @Override
824 protected void onActive() {
825 }
826
827 @Override
828 public void setChildDrawable(int featureId, Drawable drawable) {
829 }
830
831 @Override
832 public void setChildInt(int featureId, int value) {
833 }
834
835 @Override
836 public boolean isShortcutKey(int keyCode, KeyEvent event) {
837 return false;
838 }
839
840 @Override
841 public void setVolumeControlStream(int streamType) {
842 }
843
844 @Override
845 public int getVolumeControlStream() {
846 return 0;
847 }
848
849 @Override
850 public int getStatusBarColor() {
851 return 0;
852 }
853
854 @Override
855 public void setStatusBarColor(@ColorInt int color) {
856 }
857
858 @Override
859 public int getNavigationBarColor() {
860 return 0;
861 }
862
863 @Override
864 public void setNavigationBarColor(@ColorInt int color) {
865 }
866
867 @Override
868 public void setDecorCaptionShade(int decorCaptionShade) {
869 }
870
871 @Override
872 public void setResizingCaptionDrawable(Drawable drawable) {
873 }
874
875 @Override
Andrii Kulian933076d2016-03-29 17:04:42 -0700876 public void onMultiWindowModeChanged() {
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700877 }
878
879 @Override
Winson Chung4d8681f2017-05-23 16:22:08 -0700880 public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
881 }
882
883 @Override
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700884 public void reportActivityRelaunched() {
885 }
Jorim Jaggib6030952018-10-23 18:31:52 +0200886
887 @Override
888 public WindowInsetsController getInsetsController() {
889 return null;
890 }
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700891 };
892
Daniel Sandlerc4f2a562012-05-04 11:55:46 -0400893}
894