1 /* 2 * Copyright (C) 2010 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 17 package com.android.systemui.statusbar.phone; 18 19 import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN; 20 import static android.app.StatusBarManager.WINDOW_STATE_SHOWING; 21 import static android.app.StatusBarManager.windowStateToString; 22 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY; 23 24 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP; 25 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE; 26 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_WAKING; 27 import static com.android.systemui.shared.system.WindowManagerWrapper.NAV_BAR_POS_LEFT; 28 import static com.android.systemui.shared.system.WindowManagerWrapper.NAV_BAR_POS_INVALID; 29 import static com.android.systemui.statusbar.NotificationLockscreenUserManager 30 .NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION; 31 import static com.android.systemui.statusbar.NotificationLockscreenUserManager.PERMISSION_SELF; 32 import static com.android.systemui.statusbar.NotificationMediaManager.DEBUG_MEDIA; 33 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT; 34 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT; 35 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE; 36 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT; 37 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSLUCENT; 38 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT; 39 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_WARNING; 40 41 import android.animation.Animator; 42 import android.animation.AnimatorListenerAdapter; 43 import android.annotation.NonNull; 44 import android.annotation.Nullable; 45 import android.app.ActivityManager; 46 import android.app.ActivityOptions; 47 import android.app.AlarmManager; 48 import android.app.IWallpaperManager; 49 import android.app.KeyguardManager; 50 import android.app.Notification; 51 import android.app.NotificationManager; 52 import android.app.PendingIntent; 53 import android.app.StatusBarManager; 54 import android.app.TaskStackBuilder; 55 import android.app.WallpaperColors; 56 import android.app.WallpaperInfo; 57 import android.app.WallpaperManager; 58 import android.app.admin.DevicePolicyManager; 59 import android.content.BroadcastReceiver; 60 import android.content.ComponentCallbacks2; 61 import android.content.ComponentName; 62 import android.content.Context; 63 import android.content.Intent; 64 import android.content.IntentFilter; 65 import android.content.IntentSender; 66 import android.content.om.IOverlayManager; 67 import android.content.om.OverlayInfo; 68 import android.content.pm.IPackageManager; 69 import android.content.pm.PackageManager; 70 import android.content.pm.PackageManager.NameNotFoundException; 71 import android.content.pm.UserInfo; 72 import android.content.res.Configuration; 73 import android.content.res.Resources; 74 import android.graphics.Bitmap; 75 import android.graphics.Point; 76 import android.graphics.PointF; 77 import android.graphics.PorterDuff; 78 import android.graphics.PorterDuffXfermode; 79 import android.graphics.Rect; 80 import android.graphics.drawable.BitmapDrawable; 81 import android.graphics.drawable.ColorDrawable; 82 import android.graphics.drawable.Drawable; 83 import android.media.AudioAttributes; 84 import android.media.MediaMetadata; 85 import android.metrics.LogMaker; 86 import android.net.Uri; 87 import android.os.AsyncTask; 88 import android.os.Bundle; 89 import android.os.Handler; 90 import android.os.IBinder; 91 import android.os.Looper; 92 import android.os.Message; 93 import android.os.PowerManager; 94 import android.os.RemoteException; 95 import android.os.ServiceManager; 96 import android.os.SystemClock; 97 import android.os.SystemProperties; 98 import android.os.Trace; 99 import android.os.UserHandle; 100 import android.os.UserManager; 101 import android.os.VibrationEffect; 102 import android.os.Vibrator; 103 import android.provider.Settings; 104 import android.service.notification.StatusBarNotification; 105 import android.service.vr.IVrManager; 106 import android.service.vr.IVrStateCallbacks; 107 import android.text.TextUtils; 108 import android.util.DisplayMetrics; 109 import android.util.EventLog; 110 import android.util.Log; 111 import android.util.Slog; 112 import android.util.SparseArray; 113 import android.view.Display; 114 import android.view.IWindowManager; 115 import android.view.KeyEvent; 116 import android.view.LayoutInflater; 117 import android.view.MotionEvent; 118 import android.view.RemoteAnimationAdapter; 119 import android.view.ThreadedRenderer; 120 import android.view.View; 121 import android.view.ViewGroup; 122 import android.view.ViewParent; 123 import android.view.ViewTreeObserver; 124 import android.view.WindowManager; 125 import android.view.WindowManagerGlobal; 126 import android.view.accessibility.AccessibilityManager; 127 import android.view.animation.AccelerateInterpolator; 128 import android.widget.DateTimeView; 129 import android.widget.ImageView; 130 import android.widget.TextView; 131 132 import com.android.internal.annotations.VisibleForTesting; 133 import com.android.internal.colorextraction.ColorExtractor; 134 import com.android.internal.logging.MetricsLogger; 135 import com.android.internal.logging.nano.MetricsProto.MetricsEvent; 136 import com.android.internal.statusbar.IStatusBarService; 137 import com.android.internal.statusbar.NotificationVisibility; 138 import com.android.internal.statusbar.StatusBarIcon; 139 import com.android.internal.widget.LockPatternUtils; 140 import com.android.internal.widget.MessagingGroup; 141 import com.android.internal.widget.MessagingMessage; 142 import com.android.keyguard.KeyguardHostView.OnDismissAction; 143 import com.android.keyguard.KeyguardUpdateMonitor; 144 import com.android.keyguard.KeyguardUpdateMonitorCallback; 145 import com.android.keyguard.ViewMediatorCallback; 146 import com.android.systemui.ActivityStarterDelegate; 147 import com.android.systemui.AutoReinflateContainer; 148 import com.android.systemui.DemoMode; 149 import com.android.systemui.Dependency; 150 import com.android.systemui.EventLogTags; 151 import com.android.systemui.Interpolators; 152 import com.android.systemui.Prefs; 153 import com.android.systemui.R; 154 import com.android.systemui.RecentsComponent; 155 import com.android.systemui.SystemUI; 156 import com.android.systemui.SystemUIFactory; 157 import com.android.systemui.UiOffloadThread; 158 import com.android.systemui.assist.AssistManager; 159 import com.android.systemui.charging.WirelessChargingAnimation; 160 import com.android.systemui.classifier.FalsingLog; 161 import com.android.systemui.classifier.FalsingManager; 162 import com.android.systemui.colorextraction.SysuiColorExtractor; 163 import com.android.systemui.doze.DozeHost; 164 import com.android.systemui.doze.DozeLog; 165 import com.android.systemui.doze.DozeReceiver; 166 import com.android.systemui.fragments.ExtensionFragmentListener; 167 import com.android.systemui.fragments.FragmentHostManager; 168 import com.android.systemui.keyguard.KeyguardViewMediator; 169 import com.android.systemui.keyguard.ScreenLifecycle; 170 import com.android.systemui.keyguard.WakefulnessLifecycle; 171 import com.android.systemui.plugins.ActivityStarter; 172 import com.android.systemui.plugins.qs.QS; 173 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption; 174 import com.android.systemui.qs.QSFragment; 175 import com.android.systemui.qs.QSPanel; 176 import com.android.systemui.qs.QSTileHost; 177 import com.android.systemui.qs.car.CarQSFragment; 178 import com.android.systemui.recents.Recents; 179 import com.android.systemui.recents.ScreenPinningRequest; 180 import com.android.systemui.recents.events.EventBus; 181 import com.android.systemui.recents.events.activity.AppTransitionFinishedEvent; 182 import com.android.systemui.recents.events.activity.UndockingTaskEvent; 183 import com.android.systemui.recents.misc.SystemServicesProxy; 184 import com.android.systemui.shared.system.WindowManagerWrapper; 185 import com.android.systemui.stackdivider.Divider; 186 import com.android.systemui.stackdivider.WindowManagerProxy; 187 import com.android.systemui.statusbar.ActivatableNotificationView; 188 import com.android.systemui.statusbar.AppOpsListener; 189 import com.android.systemui.statusbar.BackDropView; 190 import com.android.systemui.statusbar.CommandQueue; 191 import com.android.systemui.statusbar.CrossFadeHelper; 192 import com.android.systemui.statusbar.DragDownHelper; 193 import com.android.systemui.statusbar.EmptyShadeView; 194 import com.android.systemui.statusbar.ExpandableNotificationRow; 195 import com.android.systemui.statusbar.FooterView; 196 import com.android.systemui.statusbar.GestureRecorder; 197 import com.android.systemui.statusbar.KeyboardShortcuts; 198 import com.android.systemui.statusbar.KeyguardIndicationController; 199 import com.android.systemui.statusbar.NotificationData; 200 import com.android.systemui.statusbar.NotificationData.Entry; 201 import com.android.systemui.statusbar.NotificationEntryManager; 202 import com.android.systemui.statusbar.NotificationGutsManager; 203 import com.android.systemui.statusbar.NotificationInfo; 204 import com.android.systemui.statusbar.NotificationListener; 205 import com.android.systemui.statusbar.NotificationLockscreenUserManager; 206 import com.android.systemui.statusbar.NotificationLogger; 207 import com.android.systemui.statusbar.NotificationMediaManager; 208 import com.android.systemui.statusbar.NotificationPresenter; 209 import com.android.systemui.statusbar.NotificationRemoteInputManager; 210 import com.android.systemui.statusbar.NotificationShelf; 211 import com.android.systemui.statusbar.NotificationViewHierarchyManager; 212 import com.android.systemui.statusbar.RemoteInputController; 213 import com.android.systemui.statusbar.ScrimView; 214 import com.android.systemui.statusbar.StatusBarState; 215 import com.android.systemui.statusbar.VibratorHelper; 216 import com.android.systemui.statusbar.notification.AboveShelfObserver; 217 import com.android.systemui.statusbar.notification.ActivityLaunchAnimator; 218 import com.android.systemui.statusbar.notification.VisualStabilityManager; 219 import com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChangedListener; 220 import com.android.systemui.statusbar.policy.BatteryController; 221 import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback; 222 import com.android.systemui.statusbar.policy.BrightnessMirrorController; 223 import com.android.systemui.statusbar.policy.ConfigurationController; 224 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener; 225 import com.android.systemui.statusbar.policy.DarkIconDispatcher; 226 import com.android.systemui.statusbar.policy.DeviceProvisionedController; 227 import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener; 228 import com.android.systemui.statusbar.policy.ExtensionController; 229 import com.android.systemui.statusbar.policy.HeadsUpManager; 230 import com.android.systemui.statusbar.policy.HeadsUpUtil; 231 import com.android.systemui.statusbar.policy.KeyguardMonitor; 232 import com.android.systemui.statusbar.policy.KeyguardMonitorImpl; 233 import com.android.systemui.statusbar.policy.KeyguardUserSwitcher; 234 import com.android.systemui.statusbar.policy.NetworkController; 235 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; 236 import com.android.systemui.statusbar.policy.PreviewInflater; 237 import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; 238 import com.android.systemui.statusbar.policy.UserInfoController; 239 import com.android.systemui.statusbar.policy.UserInfoControllerImpl; 240 import com.android.systemui.statusbar.policy.UserSwitcherController; 241 import com.android.systemui.statusbar.policy.ZenModeController; 242 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout; 243 import com.android.systemui.volume.VolumeComponent; 244 245 import java.io.FileDescriptor; 246 import java.io.PrintWriter; 247 import java.io.StringWriter; 248 import java.util.ArrayList; 249 import java.util.List; 250 import java.util.Map; 251 252 public class StatusBar extends SystemUI implements DemoMode, 253 DragDownHelper.DragDownCallback, ActivityStarter, OnUnlockMethodChangedListener, 254 OnHeadsUpChangedListener, CommandQueue.Callbacks, ZenModeController.Callback, 255 ColorExtractor.OnColorsChangedListener, ConfigurationListener, NotificationPresenter { 256 public static final boolean MULTIUSER_DEBUG = false; 257 258 public static final boolean ENABLE_CHILD_NOTIFICATIONS 259 = SystemProperties.getBoolean("debug.child_notifs", true); 260 261 protected static final int MSG_HIDE_RECENT_APPS = 1020; 262 protected static final int MSG_PRELOAD_RECENT_APPS = 1022; 263 protected static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 1023; 264 protected static final int MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU = 1026; 265 protected static final int MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU = 1027; 266 267 // Should match the values in PhoneWindowManager 268 public static final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey"; 269 public static final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps"; 270 static public final String SYSTEM_DIALOG_REASON_SCREENSHOT = "screenshot"; 271 272 private static final String BANNER_ACTION_CANCEL = 273 "com.android.systemui.statusbar.banner_action_cancel"; 274 private static final String BANNER_ACTION_SETUP = 275 "com.android.systemui.statusbar.banner_action_setup"; 276 public static final String TAG = "StatusBar"; 277 public static final boolean DEBUG = false; 278 public static final boolean SPEW = false; 279 public static final boolean DUMPTRUCK = true; // extra dumpsys info 280 public static final boolean DEBUG_GESTURES = false; 281 public static final boolean DEBUG_MEDIA_FAKE_ARTWORK = false; 282 public static final boolean DEBUG_CAMERA_LIFT = false; 283 284 public static final boolean DEBUG_WINDOW_STATE = false; 285 286 // additional instrumentation for testing purposes; intended to be left on during development 287 public static final boolean CHATTY = DEBUG; 288 289 public static final boolean SHOW_LOCKSCREEN_MEDIA_ARTWORK = true; 290 291 public static final String ACTION_FAKE_ARTWORK = "fake_artwork"; 292 293 private static final int MSG_OPEN_NOTIFICATION_PANEL = 1000; 294 private static final int MSG_CLOSE_PANELS = 1001; 295 private static final int MSG_OPEN_SETTINGS_PANEL = 1002; 296 private static final int MSG_LAUNCH_TRANSITION_TIMEOUT = 1003; 297 // 1020-1040 reserved for BaseStatusBar 298 299 // Time after we abort the launch transition. 300 private static final long LAUNCH_TRANSITION_TIMEOUT_MS = 5000; 301 302 protected static final boolean CLOSE_PANEL_WHEN_EMPTIED = true; 303 304 private static final int STATUS_OR_NAV_TRANSIENT = 305 View.STATUS_BAR_TRANSIENT | View.NAVIGATION_BAR_TRANSIENT; 306 private static final long AUTOHIDE_TIMEOUT_MS = 2250; 307 308 /** 309 * The delay to reset the hint text when the hint animation is finished running. 310 */ 311 private static final int HINT_RESET_DELAY_MS = 1200; 312 313 private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder() 314 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) 315 .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION) 316 .build(); 317 318 public static final int FADE_KEYGUARD_START_DELAY = 100; 319 public static final int FADE_KEYGUARD_DURATION = 300; 320 public static final int FADE_KEYGUARD_DURATION_PULSING = 96; 321 322 /** If true, the system is in the half-boot-to-decryption-screen state. 323 * Prudently disable QS and notifications. */ 324 private static final boolean ONLY_CORE_APPS; 325 326 /** If true, the lockscreen will show a distinct wallpaper */ 327 private static final boolean ENABLE_LOCKSCREEN_WALLPAPER = true; 328 329 /** 330 * Never let the alpha become zero for surfaces that draw with SRC - otherwise the RenderNode 331 * won't draw anything and uninitialized memory will show through 332 * if mScrimSrcModeEnabled. Note that 0.001 is rounded down to 0 in 333 * libhwui. 334 */ 335 private static final float SRC_MIN_ALPHA = 0.002f; 336 337 static { 338 boolean onlyCoreApps; 339 try { 340 IPackageManager packageManager = 341 IPackageManager.Stub.asInterface(ServiceManager.getService("package")); 342 onlyCoreApps = packageManager.isOnlyCoreApps(); 343 } catch (RemoteException e) { 344 onlyCoreApps = false; 345 } 346 ONLY_CORE_APPS = onlyCoreApps; 347 } 348 349 /** 350 * The {@link StatusBarState} of the status bar. 351 */ 352 protected int mState; 353 protected boolean mBouncerShowing; 354 355 private PhoneStatusBarPolicy mIconPolicy; 356 private StatusBarSignalPolicy mSignalPolicy; 357 358 private VolumeComponent mVolumeComponent; 359 private BrightnessMirrorController mBrightnessMirrorController; 360 private boolean mBrightnessMirrorVisible; 361 protected FingerprintUnlockController mFingerprintUnlockController; 362 private LightBarController mLightBarController; 363 protected LockscreenWallpaper mLockscreenWallpaper; 364 365 private int mNaturalBarHeight = -1; 366 367 private final Point mCurrentDisplaySize = new Point(); 368 369 protected StatusBarWindowView mStatusBarWindow; 370 protected PhoneStatusBarView mStatusBarView; 371 private int mStatusBarWindowState = WINDOW_STATE_SHOWING; 372 protected StatusBarWindowManager mStatusBarWindowManager; 373 protected UnlockMethodCache mUnlockMethodCache; 374 private DozeServiceHost mDozeServiceHost = new DozeServiceHost(); 375 private boolean mWakeUpComingFromTouch; 376 private PointF mWakeUpTouchLocation; 377 378 private final Object mQueueLock = new Object(); 379 380 protected StatusBarIconController mIconController; 381 382 // expanded notifications 383 protected NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window 384 private TextView mNotificationPanelDebugText; 385 386 // settings 387 private QSPanel mQSPanel; 388 389 // top bar 390 private KeyguardStatusBarView mKeyguardStatusBar; 391 private boolean mLeaveOpenOnKeyguardHide; 392 KeyguardIndicationController mKeyguardIndicationController; 393 394 // Keyguard is actually fading away now. 395 protected boolean mKeyguardFadingAway; 396 protected long mKeyguardFadingAwayDelay; 397 protected long mKeyguardFadingAwayDuration; 398 399 // RemoteInputView to be activated after unlock 400 private View mPendingRemoteInputView; 401 private View mPendingWorkRemoteInputView; 402 403 private RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler = 404 Dependency.get(RemoteInputQuickSettingsDisabler.class); 405 406 private View mReportRejectedTouch; 407 408 private int mMaxAllowedKeyguardNotifications; 409 410 private boolean mExpandedVisible; 411 412 private final int[] mAbsPos = new int[2]; 413 private final ArrayList<Runnable> mPostCollapseRunnables = new ArrayList<>(); 414 415 private NotificationGutsManager mGutsManager; 416 protected NotificationLogger mNotificationLogger; 417 protected NotificationEntryManager mEntryManager; 418 protected NotificationViewHierarchyManager mViewHierarchyManager; 419 protected AppOpsListener mAppOpsListener; 420 protected KeyguardViewMediator mKeyguardViewMediator; 421 private ZenModeController mZenController; 422 423 /** 424 * Helper that is responsible for showing the right toast when a disallowed activity operation 425 * occurred. In pinned mode, we show instructions on how to break out of this mode, whilst in 426 * fully locked mode we only show that unlocking is blocked. 427 */ 428 private ScreenPinningNotify mScreenPinningNotify; 429 430 // for disabling the status bar 431 private int mDisabled1 = 0; 432 private int mDisabled2 = 0; 433 434 // tracking calls to View.setSystemUiVisibility() 435 private int mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE; 436 private final Rect mLastFullscreenStackBounds = new Rect(); 437 private final Rect mLastDockedStackBounds = new Rect(); 438 private final Rect mTmpRect = new Rect(); 439 440 // last value sent to window manager 441 private int mLastDispatchedSystemUiVisibility = ~View.SYSTEM_UI_FLAG_VISIBLE; 442 443 private final DisplayMetrics mDisplayMetrics = new DisplayMetrics(); 444 445 // XXX: gesture research 446 private final GestureRecorder mGestureRec = DEBUG_GESTURES 447 ? new GestureRecorder("/sdcard/statusbar_gestures.dat") 448 : null; 449 450 private ScreenPinningRequest mScreenPinningRequest; 451 452 private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class); 453 454 // ensure quick settings is disabled until the current user makes it through the setup wizard 455 @VisibleForTesting 456 protected boolean mUserSetup = false; 457 private final DeviceProvisionedListener mUserSetupObserver = new DeviceProvisionedListener() { 458 @Override 459 public void onUserSetupChanged() { 460 final boolean userSetup = mDeviceProvisionedController.isUserSetup( 461 mDeviceProvisionedController.getCurrentUser()); 462 if (MULTIUSER_DEBUG) { 463 Log.d(TAG, String.format("User setup changed: userSetup=%s mUserSetup=%s", 464 userSetup, mUserSetup)); 465 } 466 467 if (userSetup != mUserSetup) { 468 mUserSetup = userSetup; 469 if (!mUserSetup && mStatusBarView != null) 470 animateCollapseQuickSettings(); 471 if (mNotificationPanel != null) { 472 mNotificationPanel.setUserSetupComplete(mUserSetup); 473 } 474 updateQsExpansionEnabled(); 475 } 476 } 477 }; 478 479 protected final H mHandler = createHandler(); 480 481 private int mInteractingWindows; 482 private boolean mAutohideSuspended; 483 private int mStatusBarMode; 484 private int mMaxKeyguardNotifications; 485 486 private ViewMediatorCallback mKeyguardViewMediatorCallback; 487 protected ScrimController mScrimController; 488 protected DozeScrimController mDozeScrimController; 489 private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class); 490 491 private final Runnable mAutohide = () -> { 492 int requested = mSystemUiVisibility & ~STATUS_OR_NAV_TRANSIENT; 493 if (mSystemUiVisibility != requested) { 494 notifyUiVisibilityChanged(requested); 495 } 496 }; 497 498 protected boolean mDozing; 499 private boolean mDozingRequested; 500 protected boolean mScrimSrcModeEnabled; 501 502 protected BackDropView mBackdrop; 503 protected ImageView mBackdropFront, mBackdropBack; 504 protected final PorterDuffXfermode mSrcXferMode = new PorterDuffXfermode(PorterDuff.Mode.SRC); 505 protected final PorterDuffXfermode mSrcOverXferMode = 506 new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER); 507 508 private NotificationMediaManager mMediaManager; 509 protected NotificationLockscreenUserManager mLockscreenUserManager; 510 protected NotificationRemoteInputManager mRemoteInputManager; 511 512 private BroadcastReceiver mWallpaperChangedReceiver = new BroadcastReceiver() { 513 @Override 514 public void onReceive(Context context, Intent intent) { 515 WallpaperManager wallpaperManager = context.getSystemService(WallpaperManager.class); 516 if (wallpaperManager == null) { 517 Log.w(TAG, "WallpaperManager not available"); 518 return; 519 } 520 WallpaperInfo info = wallpaperManager.getWallpaperInfo(); 521 final boolean supportsAmbientMode = info != null && 522 info.getSupportsAmbientMode(); 523 524 mStatusBarWindowManager.setWallpaperSupportsAmbientMode(supportsAmbientMode); 525 mScrimController.setWallpaperSupportsAmbientMode(supportsAmbientMode); 526 } 527 }; 528 529 private Runnable mLaunchTransitionEndRunnable; 530 protected boolean mLaunchTransitionFadingAway; 531 private ExpandableNotificationRow mDraggedDownRow; 532 private boolean mLaunchCameraOnScreenTurningOn; 533 private boolean mLaunchCameraOnFinishedGoingToSleep; 534 private int mLastCameraLaunchSource; 535 private PowerManager.WakeLock mGestureWakeLock; 536 private Vibrator mVibrator; 537 private long[] mCameraLaunchGestureVibePattern; 538 539 private final int[] mTmpInt2 = new int[2]; 540 541 // Fingerprint (as computed by getLoggingFingerprint() of the last logged state. 542 private int mLastLoggedStateFingerprint; 543 private boolean mTopHidesStatusBar; 544 private boolean mStatusBarWindowHidden; 545 private boolean mHideIconsForBouncer; 546 private boolean mIsOccluded; 547 private boolean mWereIconsJustHidden; 548 private boolean mBouncerWasShowingWhenHidden; 549 550 // Notifies StatusBarKeyguardViewManager every time the keyguard transition is over, 551 // this animation is tied to the scrim for historic reasons. 552 // TODO: notify when keyguard has faded away instead of the scrim. 553 private final ScrimController.Callback mUnlockScrimCallback = new ScrimController 554 .Callback() { 555 @Override 556 public void onFinished() { 557 if (mStatusBarKeyguardViewManager == null) { 558 Log.w(TAG, "Tried to notify keyguard visibility when " 559 + "mStatusBarKeyguardViewManager was null"); 560 return; 561 } 562 if (mKeyguardFadingAway) { 563 mStatusBarKeyguardViewManager.onKeyguardFadedAway(); 564 } 565 } 566 567 @Override 568 public void onCancelled() { 569 onFinished(); 570 } 571 }; 572 573 private KeyguardUserSwitcher mKeyguardUserSwitcher; 574 protected UserSwitcherController mUserSwitcherController; 575 private NetworkController mNetworkController; 576 private KeyguardMonitorImpl mKeyguardMonitor 577 = (KeyguardMonitorImpl) Dependency.get(KeyguardMonitor.class); 578 private BatteryController mBatteryController; 579 protected boolean mPanelExpanded; 580 private IOverlayManager mOverlayManager; 581 private boolean mKeyguardRequested; 582 private boolean mIsKeyguard; 583 private LogMaker mStatusBarStateLog; 584 private final LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger(); 585 protected NotificationIconAreaController mNotificationIconAreaController; 586 private boolean mReinflateNotificationsOnUserSwitched; 587 protected boolean mClearAllEnabled; 588 @Nullable private View mAmbientIndicationContainer; 589 private SysuiColorExtractor mColorExtractor; 590 private ScreenLifecycle mScreenLifecycle; 591 @VisibleForTesting WakefulnessLifecycle mWakefulnessLifecycle; 592 593 private final View.OnClickListener mGoToLockedShadeListener = v -> { 594 if (mState == StatusBarState.KEYGUARD) { 595 wakeUpIfDozing(SystemClock.uptimeMillis(), v); 596 goToLockedShade(null); 597 } 598 }; 599 private boolean mNoAnimationOnNextBarModeChange; 600 protected FalsingManager mFalsingManager; 601 602 private final KeyguardUpdateMonitorCallback mUpdateCallback = 603 new KeyguardUpdateMonitorCallback() { 604 @Override 605 public void onDreamingStateChanged(boolean dreaming) { 606 if (dreaming) { 607 maybeEscalateHeadsUp(); 608 } 609 } 610 611 @Override 612 public void onStrongAuthStateChanged(int userId) { 613 super.onStrongAuthStateChanged(userId); 614 mEntryManager.updateNotifications(); 615 } 616 }; 617 618 private NavigationBarFragment mNavigationBar; 619 private View mNavigationBarView; 620 protected ActivityLaunchAnimator mActivityLaunchAnimator; 621 private HeadsUpAppearanceController mHeadsUpAppearanceController; 622 private boolean mVibrateOnOpening; 623 private VibratorHelper mVibratorHelper; 624 625 @Override 626 public void start() { 627 mGroupManager = Dependency.get(NotificationGroupManager.class); 628 mVisualStabilityManager = Dependency.get(VisualStabilityManager.class); 629 mNotificationLogger = Dependency.get(NotificationLogger.class); 630 mRemoteInputManager = Dependency.get(NotificationRemoteInputManager.class); 631 mNotificationListener = Dependency.get(NotificationListener.class); 632 mGroupManager = Dependency.get(NotificationGroupManager.class); 633 mNetworkController = Dependency.get(NetworkController.class); 634 mUserSwitcherController = Dependency.get(UserSwitcherController.class); 635 mScreenLifecycle = Dependency.get(ScreenLifecycle.class); 636 mScreenLifecycle.addObserver(mScreenObserver); 637 mWakefulnessLifecycle = Dependency.get(WakefulnessLifecycle.class); 638 mWakefulnessLifecycle.addObserver(mWakefulnessObserver); 639 mBatteryController = Dependency.get(BatteryController.class); 640 mAssistManager = Dependency.get(AssistManager.class); 641 mOverlayManager = IOverlayManager.Stub.asInterface( 642 ServiceManager.getService(Context.OVERLAY_SERVICE)); 643 mLockscreenUserManager = Dependency.get(NotificationLockscreenUserManager.class); 644 mGutsManager = Dependency.get(NotificationGutsManager.class); 645 mMediaManager = Dependency.get(NotificationMediaManager.class); 646 mEntryManager = Dependency.get(NotificationEntryManager.class); 647 mViewHierarchyManager = Dependency.get(NotificationViewHierarchyManager.class); 648 mAppOpsListener = Dependency.get(AppOpsListener.class); 649 mAppOpsListener.setUpWithPresenter(this, mEntryManager); 650 mZenController = Dependency.get(ZenModeController.class); 651 mKeyguardViewMediator = getComponent(KeyguardViewMediator.class); 652 653 mColorExtractor = Dependency.get(SysuiColorExtractor.class); 654 mColorExtractor.addOnColorsChangedListener(this); 655 656 mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); 657 658 mDisplay = mWindowManager.getDefaultDisplay(); 659 updateDisplaySize(); 660 661 Resources res = mContext.getResources(); 662 mVibrateOnOpening = mContext.getResources().getBoolean( 663 R.bool.config_vibrateOnIconAnimation); 664 mVibratorHelper = Dependency.get(VibratorHelper.class); 665 mScrimSrcModeEnabled = res.getBoolean(R.bool.config_status_bar_scrim_behind_use_src); 666 mClearAllEnabled = res.getBoolean(R.bool.config_enableNotificationsClearAll); 667 668 DateTimeView.setReceiverHandler(Dependency.get(Dependency.TIME_TICK_HANDLER)); 669 putComponent(StatusBar.class, this); 670 671 // start old BaseStatusBar.start(). 672 mWindowManagerService = WindowManagerGlobal.getWindowManagerService(); 673 mDevicePolicyManager = (DevicePolicyManager) mContext.getSystemService( 674 Context.DEVICE_POLICY_SERVICE); 675 676 mAccessibilityManager = (AccessibilityManager) 677 mContext.getSystemService(Context.ACCESSIBILITY_SERVICE); 678 679 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 680 681 mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class); 682 683 mBarService = IStatusBarService.Stub.asInterface( 684 ServiceManager.getService(Context.STATUS_BAR_SERVICE)); 685 686 mRecents = getComponent(Recents.class); 687 688 mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE); 689 mLockPatternUtils = new LockPatternUtils(mContext); 690 691 mMediaManager.setUpWithPresenter(this, mEntryManager); 692 693 // Connect in to the status bar manager service 694 mCommandQueue = getComponent(CommandQueue.class); 695 mCommandQueue.addCallbacks(this); 696 697 int[] switches = new int[9]; 698 ArrayList<IBinder> binders = new ArrayList<>(); 699 ArrayList<String> iconSlots = new ArrayList<>(); 700 ArrayList<StatusBarIcon> icons = new ArrayList<>(); 701 Rect fullscreenStackBounds = new Rect(); 702 Rect dockedStackBounds = new Rect(); 703 try { 704 mBarService.registerStatusBar(mCommandQueue, iconSlots, icons, switches, binders, 705 fullscreenStackBounds, dockedStackBounds); 706 } catch (RemoteException ex) { 707 // If the system process isn't there we're doomed anyway. 708 } 709 710 createAndAddWindows(); 711 712 // Make sure we always have the most current wallpaper info. 713 IntentFilter wallpaperChangedFilter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED); 714 mContext.registerReceiver(mWallpaperChangedReceiver, wallpaperChangedFilter); 715 mWallpaperChangedReceiver.onReceive(mContext, null); 716 717 mLockscreenUserManager.setUpWithPresenter(this, mEntryManager); 718 mCommandQueue.disable(switches[0], switches[6], false /* animate */); 719 setSystemUiVisibility(switches[1], switches[7], switches[8], 0xffffffff, 720 fullscreenStackBounds, dockedStackBounds); 721 topAppWindowChanged(switches[2] != 0); 722 // StatusBarManagerService has a back up of IME token and it's restored here. 723 setImeWindowStatus(binders.get(0), switches[3], switches[4], switches[5] != 0); 724 725 // Set up the initial icon state 726 int N = iconSlots.size(); 727 for (int i=0; i < N; i++) { 728 mCommandQueue.setIcon(iconSlots.get(i), icons.get(i)); 729 } 730 731 // Set up the initial notification state. 732 mNotificationListener.setUpWithPresenter(this, mEntryManager); 733 734 if (DEBUG) { 735 Log.d(TAG, String.format( 736 "init: icons=%d disabled=0x%08x lights=0x%08x menu=0x%08x imeButton=0x%08x", 737 icons.size(), 738 switches[0], 739 switches[1], 740 switches[2], 741 switches[3] 742 )); 743 } 744 745 setHeadsUpUser(mLockscreenUserManager.getCurrentUserId()); 746 747 IntentFilter internalFilter = new IntentFilter(); 748 internalFilter.addAction(BANNER_ACTION_CANCEL); 749 internalFilter.addAction(BANNER_ACTION_SETUP); 750 mContext.registerReceiver(mBannerActionBroadcastReceiver, internalFilter, PERMISSION_SELF, 751 null); 752 753 IVrManager vrManager = IVrManager.Stub.asInterface(ServiceManager.getService( 754 Context.VR_SERVICE)); 755 try { 756 vrManager.registerListener(mVrStateCallbacks); 757 } catch (RemoteException e) { 758 Slog.e(TAG, "Failed to register VR mode state listener: " + e); 759 } 760 761 IWallpaperManager wallpaperManager = IWallpaperManager.Stub.asInterface( 762 ServiceManager.getService(Context.WALLPAPER_SERVICE)); 763 try { 764 wallpaperManager.setInAmbientMode(false /* ambientMode */, false /* animated */); 765 } catch (RemoteException e) { 766 // Just pass, nothing critical. 767 } 768 769 // end old BaseStatusBar.start(). 770 771 // Lastly, call to the icon policy to install/update all the icons. 772 mIconPolicy = new PhoneStatusBarPolicy(mContext, mIconController); 773 mSignalPolicy = new StatusBarSignalPolicy(mContext, mIconController); 774 775 mUnlockMethodCache = UnlockMethodCache.getInstance(mContext); 776 mUnlockMethodCache.addListener(this); 777 startKeyguard(); 778 779 KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateCallback); 780 putComponent(DozeHost.class, mDozeServiceHost); 781 782 mScreenPinningRequest = new ScreenPinningRequest(mContext); 783 mFalsingManager = FalsingManager.getInstance(mContext); 784 785 Dependency.get(ActivityStarterDelegate.class).setActivityStarterImpl(this); 786 787 Dependency.get(ConfigurationController.class).addCallback(this); 788 } 789 790 // ================================================================================ 791 // Constructing the view 792 // ================================================================================ 793 protected void makeStatusBarView() { 794 final Context context = mContext; 795 updateDisplaySize(); // populates mDisplayMetrics 796 updateResources(); 797 updateTheme(); 798 799 inflateStatusBarWindow(context); 800 mStatusBarWindow.setService(this); 801 mStatusBarWindow.setOnTouchListener(getStatusBarWindowTouchListener()); 802 803 // TODO: Deal with the ugliness that comes from having some of the statusbar broken out 804 // into fragments, but the rest here, it leaves some awkward lifecycle and whatnot. 805 mNotificationPanel = mStatusBarWindow.findViewById(R.id.notification_panel); 806 mStackScroller = mStatusBarWindow.findViewById(R.id.notification_stack_scroller); 807 mZenController.addCallback(this); 808 mActivityLaunchAnimator = new ActivityLaunchAnimator(mStatusBarWindow, 809 this, 810 mNotificationPanel, 811 mStackScroller); 812 mGutsManager.setUpWithPresenter(this, mEntryManager, mStackScroller, mCheckSaveListener, 813 key -> { 814 try { 815 mBarService.onNotificationSettingsViewed(key); 816 } catch (RemoteException e) { 817 // if we're here we're dead 818 } 819 }); 820 mNotificationLogger.setUpWithEntryManager(mEntryManager, mStackScroller); 821 mNotificationPanel.setStatusBar(this); 822 mNotificationPanel.setGroupManager(mGroupManager); 823 mAboveShelfObserver = new AboveShelfObserver(mStackScroller); 824 mAboveShelfObserver.setListener(mStatusBarWindow.findViewById( 825 R.id.notification_container_parent)); 826 mKeyguardStatusBar = mStatusBarWindow.findViewById(R.id.keyguard_header); 827 828 mNotificationIconAreaController = SystemUIFactory.getInstance() 829 .createNotificationIconAreaController(context, this); 830 inflateShelf(); 831 mNotificationIconAreaController.setupShelf(mNotificationShelf); 832 Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mNotificationIconAreaController); 833 FragmentHostManager.get(mStatusBarWindow) 834 .addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> { 835 CollapsedStatusBarFragment statusBarFragment = 836 (CollapsedStatusBarFragment) fragment; 837 statusBarFragment.initNotificationIconArea(mNotificationIconAreaController); 838 mStatusBarView = (PhoneStatusBarView) fragment.getView(); 839 mStatusBarView.setBar(this); 840 mStatusBarView.setPanel(mNotificationPanel); 841 mStatusBarView.setScrimController(mScrimController); 842 mStatusBarView.setBouncerShowing(mBouncerShowing); 843 if (mHeadsUpAppearanceController != null) { 844 // This view is being recreated, let's destroy the old one 845 mHeadsUpAppearanceController.destroy(); 846 } 847 mHeadsUpAppearanceController = new HeadsUpAppearanceController( 848 mNotificationIconAreaController, mHeadsUpManager, mStatusBarWindow); 849 setAreThereNotifications(); 850 checkBarModes(); 851 }).getFragmentManager() 852 .beginTransaction() 853 .replace(R.id.status_bar_container, new CollapsedStatusBarFragment(), 854 CollapsedStatusBarFragment.TAG) 855 .commit(); 856 mIconController = Dependency.get(StatusBarIconController.class); 857 858 mHeadsUpManager = new HeadsUpManagerPhone(context, mStatusBarWindow, mGroupManager, this, 859 mVisualStabilityManager); 860 Dependency.get(ConfigurationController.class).addCallback(mHeadsUpManager); 861 mHeadsUpManager.addListener(this); 862 mHeadsUpManager.addListener(mNotificationPanel); 863 mHeadsUpManager.addListener(mGroupManager); 864 mHeadsUpManager.addListener(mVisualStabilityManager); 865 mNotificationPanel.setHeadsUpManager(mHeadsUpManager); 866 mGroupManager.setHeadsUpManager(mHeadsUpManager); 867 putComponent(HeadsUpManager.class, mHeadsUpManager); 868 869 mEntryManager.setUpWithPresenter(this, mStackScroller, this, mHeadsUpManager); 870 mViewHierarchyManager.setUpWithPresenter(this, mEntryManager, mStackScroller); 871 872 if (MULTIUSER_DEBUG) { 873 mNotificationPanelDebugText = mNotificationPanel.findViewById(R.id.header_debug_info); 874 mNotificationPanelDebugText.setVisibility(View.VISIBLE); 875 } 876 877 try { 878 boolean showNav = mWindowManagerService.hasNavigationBar(); 879 if (DEBUG) Log.v(TAG, "hasNavigationBar=" + showNav); 880 if (showNav) { 881 createNavigationBar(); 882 } 883 } catch (RemoteException ex) { 884 // no window manager? good luck with that 885 } 886 mScreenPinningNotify = new ScreenPinningNotify(mContext); 887 mStackScroller.setLongPressListener(mEntryManager.getNotificationLongClicker()); 888 mStackScroller.setStatusBar(this); 889 mStackScroller.setGroupManager(mGroupManager); 890 mStackScroller.setHeadsUpManager(mHeadsUpManager); 891 mGroupManager.setOnGroupChangeListener(mStackScroller); 892 mVisualStabilityManager.setVisibilityLocationProvider(mStackScroller); 893 894 inflateEmptyShadeView(); 895 inflateFooterView(); 896 897 mBackdrop = mStatusBarWindow.findViewById(R.id.backdrop); 898 mBackdropFront = mBackdrop.findViewById(R.id.backdrop_front); 899 mBackdropBack = mBackdrop.findViewById(R.id.backdrop_back); 900 901 if (ENABLE_LOCKSCREEN_WALLPAPER) { 902 mLockscreenWallpaper = new LockscreenWallpaper(mContext, this, mHandler); 903 } 904 905 mKeyguardIndicationController = 906 SystemUIFactory.getInstance().createKeyguardIndicationController(mContext, 907 mStatusBarWindow.findViewById(R.id.keyguard_indication_area), 908 mNotificationPanel.getLockIcon()); 909 mNotificationPanel.setKeyguardIndicationController(mKeyguardIndicationController); 910 911 912 mAmbientIndicationContainer = mStatusBarWindow.findViewById( 913 R.id.ambient_indication_container); 914 915 // set the initial view visibility 916 setAreThereNotifications(); 917 918 // TODO: Find better place for this callback. 919 mBatteryController.addCallback(new BatteryStateChangeCallback() { 920 @Override 921 public void onPowerSaveChanged(boolean isPowerSave) { 922 mHandler.post(mCheckBarModes); 923 if (mDozeServiceHost != null) { 924 mDozeServiceHost.firePowerSaveChanged(isPowerSave); 925 } 926 } 927 928 @Override 929 public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) { 930 // noop 931 } 932 }); 933 934 mLightBarController = Dependency.get(LightBarController.class); 935 if (mNavigationBar != null) { 936 mNavigationBar.setLightBarController(mLightBarController); 937 } 938 939 ScrimView scrimBehind = mStatusBarWindow.findViewById(R.id.scrim_behind); 940 ScrimView scrimInFront = mStatusBarWindow.findViewById(R.id.scrim_in_front); 941 mScrimController = SystemUIFactory.getInstance().createScrimController( 942 scrimBehind, scrimInFront, mLockscreenWallpaper, 943 (state, alpha, color) -> mLightBarController.setScrimState(state, alpha, color), 944 scrimsVisible -> { 945 if (mStatusBarWindowManager != null) { 946 mStatusBarWindowManager.setScrimsVisibility(scrimsVisible); 947 } 948 }, DozeParameters.getInstance(mContext), 949 mContext.getSystemService(AlarmManager.class)); 950 if (mScrimSrcModeEnabled) { 951 Runnable runnable = () -> { 952 boolean asSrc = mBackdrop.getVisibility() != View.VISIBLE; 953 mScrimController.setDrawBehindAsSrc(asSrc); 954 mStackScroller.setDrawBackgroundAsSrc(asSrc); 955 }; 956 mBackdrop.setOnVisibilityChangedRunnable(runnable); 957 runnable.run(); 958 } 959 mStackScroller.setScrimController(mScrimController); 960 mDozeScrimController = new DozeScrimController(mScrimController, context, 961 DozeParameters.getInstance(context)); 962 963 // Other icons 964 mVolumeComponent = getComponent(VolumeComponent.class); 965 966 mNotificationPanel.setUserSetupComplete(mUserSetup); 967 if (UserManager.get(mContext).isUserSwitcherEnabled()) { 968 createUserSwitcher(); 969 } 970 971 // Set up the quick settings tile panel 972 View container = mStatusBarWindow.findViewById(R.id.qs_frame); 973 if (container != null) { 974 FragmentHostManager fragmentHostManager = FragmentHostManager.get(container); 975 ExtensionFragmentListener.attachExtensonToFragment(container, QS.TAG, R.id.qs_frame, 976 Dependency.get(ExtensionController.class) 977 .newExtension(QS.class) 978 .withPlugin(QS.class) 979 .withFeature(PackageManager.FEATURE_AUTOMOTIVE, CarQSFragment::new) 980 .withDefault(QSFragment::new) 981 .build()); 982 final QSTileHost qsh = SystemUIFactory.getInstance().createQSTileHost(mContext, this, 983 mIconController); 984 mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow, 985 (visible) -> { 986 mBrightnessMirrorVisible = visible; 987 updateScrimController(); 988 }); 989 fragmentHostManager.addTagListener(QS.TAG, (tag, f) -> { 990 QS qs = (QS) f; 991 if (qs instanceof QSFragment) { 992 ((QSFragment) qs).setHost(qsh); 993 mQSPanel = ((QSFragment) qs).getQsPanel(); 994 mQSPanel.setBrightnessMirror(mBrightnessMirrorController); 995 mKeyguardStatusBar.setQSPanel(mQSPanel); 996 } 997 }); 998 } 999 1000 mReportRejectedTouch = mStatusBarWindow.findViewById(R.id.report_rejected_touch); 1001 if (mReportRejectedTouch != null) { 1002 updateReportRejectedTouchVisibility(); 1003 mReportRejectedTouch.setOnClickListener(v -> { 1004 Uri session = mFalsingManager.reportRejectedTouch(); 1005 if (session == null) { return; } 1006 1007 StringWriter message = new StringWriter(); 1008 message.write("Build info: "); 1009 message.write(SystemProperties.get("ro.build.description")); 1010 message.write("\nSerial number: "); 1011 message.write(SystemProperties.get("ro.serialno")); 1012 message.write("\n"); 1013 1014 PrintWriter falsingPw = new PrintWriter(message); 1015 FalsingLog.dump(falsingPw); 1016 falsingPw.flush(); 1017 1018 startActivityDismissingKeyguard(Intent.createChooser(new Intent(Intent.ACTION_SEND) 1019 .setType("*/*") 1020 .putExtra(Intent.EXTRA_SUBJECT, "Rejected touch report") 1021 .putExtra(Intent.EXTRA_STREAM, session) 1022 .putExtra(Intent.EXTRA_TEXT, message.toString()), 1023 "Share rejected touch report") 1024 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), 1025 true /* onlyProvisioned */, true /* dismissShade */); 1026 }); 1027 } 1028 1029 PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 1030 if (!pm.isScreenOn()) { 1031 mBroadcastReceiver.onReceive(mContext, new Intent(Intent.ACTION_SCREEN_OFF)); 1032 } 1033 mGestureWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, 1034 "GestureWakeLock"); 1035 mVibrator = mContext.getSystemService(Vibrator.class); 1036 int[] pattern = mContext.getResources().getIntArray( 1037 R.array.config_cameraLaunchGestureVibePattern); 1038 mCameraLaunchGestureVibePattern = new long[pattern.length]; 1039 for (int i = 0; i < pattern.length; i++) { 1040 mCameraLaunchGestureVibePattern[i] = pattern[i]; 1041 } 1042 1043 // receive broadcasts 1044 IntentFilter filter = new IntentFilter(); 1045 filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); 1046 filter.addAction(Intent.ACTION_SCREEN_OFF); 1047 filter.addAction(DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG); 1048 context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null); 1049 1050 IntentFilter demoFilter = new IntentFilter(); 1051 if (DEBUG_MEDIA_FAKE_ARTWORK) { 1052 demoFilter.addAction(ACTION_FAKE_ARTWORK); 1053 } 1054 demoFilter.addAction(ACTION_DEMO); 1055 context.registerReceiverAsUser(mDemoReceiver, UserHandle.ALL, demoFilter, 1056 android.Manifest.permission.DUMP, null); 1057 1058 // listen for USER_SETUP_COMPLETE setting (per-user) 1059 mDeviceProvisionedController.addCallback(mUserSetupObserver); 1060 mUserSetupObserver.onUserSetupChanged(); 1061 1062 // disable profiling bars, since they overlap and clutter the output on app windows 1063 ThreadedRenderer.overrideProperty("disableProfileBars", "true"); 1064 1065 // Private API call to make the shadows look better for Recents 1066 ThreadedRenderer.overrideProperty("ambientRatio", String.valueOf(1.5f)); 1067 } 1068 1069 protected void createNavigationBar() { 1070 mNavigationBarView = NavigationBarFragment.create(mContext, (tag, fragment) -> { 1071 mNavigationBar = (NavigationBarFragment) fragment; 1072 if (mLightBarController != null) { 1073 mNavigationBar.setLightBarController(mLightBarController); 1074 } 1075 mNavigationBar.setCurrentSysuiVisibility(mSystemUiVisibility); 1076 }); 1077 } 1078 1079 /** 1080 * Returns the {@link android.view.View.OnTouchListener} that will be invoked when the 1081 * background window of the status bar is clicked. 1082 */ 1083 protected View.OnTouchListener getStatusBarWindowTouchListener() { 1084 return (v, event) -> { 1085 checkUserAutohide(event); 1086 mRemoteInputManager.checkRemoteInputOutside(event); 1087 if (event.getAction() == MotionEvent.ACTION_DOWN) { 1088 if (mExpandedVisible) { 1089 animateCollapsePanels(); 1090 } 1091 } 1092 return mStatusBarWindow.onTouchEvent(event); 1093 }; 1094 } 1095 1096 private void inflateShelf() { 1097 mNotificationShelf = 1098 (NotificationShelf) LayoutInflater.from(mContext).inflate( 1099 R.layout.status_bar_notification_shelf, mStackScroller, false); 1100 mNotificationShelf.setOnActivatedListener(this); 1101 mStackScroller.setShelf(mNotificationShelf); 1102 mNotificationShelf.setOnClickListener(mGoToLockedShadeListener); 1103 mNotificationShelf.setStatusBarState(mState); 1104 } 1105 1106 public void onDensityOrFontScaleChanged() { 1107 MessagingMessage.dropCache(); 1108 MessagingGroup.dropCache(); 1109 // start old BaseStatusBar.onDensityOrFontScaleChanged(). 1110 if (!KeyguardUpdateMonitor.getInstance(mContext).isSwitchingUser()) { 1111 mEntryManager.updateNotificationsOnDensityOrFontScaleChanged(); 1112 } else { 1113 mReinflateNotificationsOnUserSwitched = true; 1114 } 1115 // end old BaseStatusBar.onDensityOrFontScaleChanged(). 1116 // TODO: Remove this. 1117 if (mBrightnessMirrorController != null) { 1118 mBrightnessMirrorController.onDensityOrFontScaleChanged(); 1119 } 1120 mStatusBarKeyguardViewManager.onDensityOrFontScaleChanged(); 1121 // TODO: Bring these out of StatusBar. 1122 ((UserInfoControllerImpl) Dependency.get(UserInfoController.class)) 1123 .onDensityOrFontScaleChanged(); 1124 Dependency.get(UserSwitcherController.class).onDensityOrFontScaleChanged(); 1125 if (mKeyguardUserSwitcher != null) { 1126 mKeyguardUserSwitcher.onDensityOrFontScaleChanged(); 1127 } 1128 mNotificationIconAreaController.onDensityOrFontScaleChanged(mContext); 1129 mHeadsUpManager.onDensityOrFontScaleChanged(); 1130 1131 reevaluateStyles(); 1132 } 1133 1134 private void onThemeChanged() { 1135 reevaluateStyles(); 1136 1137 // Clock and bottom icons 1138 mNotificationPanel.onThemeChanged(); 1139 // The status bar on the keyguard is a special layout. 1140 if (mKeyguardStatusBar != null) mKeyguardStatusBar.onThemeChanged(); 1141 // Recreate Indication controller because internal references changed 1142 mKeyguardIndicationController = 1143 SystemUIFactory.getInstance().createKeyguardIndicationController(mContext, 1144 mStatusBarWindow.findViewById(R.id.keyguard_indication_area), 1145 mNotificationPanel.getLockIcon()); 1146 mNotificationPanel.setKeyguardIndicationController(mKeyguardIndicationController); 1147 mKeyguardIndicationController 1148 .setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager); 1149 mKeyguardIndicationController.setVisible(mState == StatusBarState.KEYGUARD); 1150 mKeyguardIndicationController.setDozing(mDozing); 1151 if (mStatusBarKeyguardViewManager != null) { 1152 mStatusBarKeyguardViewManager.onThemeChanged(); 1153 } 1154 if (mAmbientIndicationContainer instanceof AutoReinflateContainer) { 1155 ((AutoReinflateContainer) mAmbientIndicationContainer).inflateLayout(); 1156 } 1157 } 1158 1159 protected void reevaluateStyles() { 1160 inflateFooterView(); 1161 updateFooter(); 1162 inflateEmptyShadeView(); 1163 updateEmptyShadeView(); 1164 } 1165 1166 @Override 1167 public void onOverlayChanged() { 1168 if (mBrightnessMirrorController != null) { 1169 mBrightnessMirrorController.onOverlayChanged(); 1170 } 1171 } 1172 1173 private void inflateEmptyShadeView() { 1174 if (mStackScroller == null) { 1175 return; 1176 } 1177 mEmptyShadeView = (EmptyShadeView) LayoutInflater.from(mContext).inflate( 1178 R.layout.status_bar_no_notifications, mStackScroller, false); 1179 mEmptyShadeView.setText(R.string.empty_shade_text); 1180 mStackScroller.setEmptyShadeView(mEmptyShadeView); 1181 } 1182 1183 private void inflateFooterView() { 1184 if (mStackScroller == null) { 1185 return; 1186 } 1187 1188 mFooterView = (FooterView) LayoutInflater.from(mContext).inflate( 1189 R.layout.status_bar_notification_footer, mStackScroller, false); 1190 mFooterView.setDismissButtonClickListener(v -> { 1191 mMetricsLogger.action(MetricsEvent.ACTION_DISMISS_ALL_NOTES); 1192 clearAllNotifications(); 1193 }); 1194 mFooterView.setManageButtonClickListener(v -> { 1195 manageNotifications(); 1196 }); 1197 mStackScroller.setFooterView(mFooterView); 1198 } 1199 1200 protected void createUserSwitcher() { 1201 mKeyguardUserSwitcher = new KeyguardUserSwitcher(mContext, 1202 mStatusBarWindow.findViewById(R.id.keyguard_user_switcher), mKeyguardStatusBar, 1203 mNotificationPanel); 1204 } 1205 1206 protected void inflateStatusBarWindow(Context context) { 1207 mStatusBarWindow = (StatusBarWindowView) View.inflate(context, 1208 R.layout.super_status_bar, null); 1209 } 1210 1211 public void manageNotifications() { 1212 Intent intent = new Intent(Settings.ACTION_ALL_APPS_NOTIFICATION_SETTINGS); 1213 startActivity(intent, true, true, Intent.FLAG_ACTIVITY_SINGLE_TOP); 1214 } 1215 1216 public void clearAllNotifications() { 1217 // animate-swipe all dismissable notifications, then animate the shade closed 1218 int numChildren = mStackScroller.getChildCount(); 1219 1220 final ArrayList<View> viewsToHide = new ArrayList<>(numChildren); 1221 final ArrayList<ExpandableNotificationRow> viewsToRemove = new ArrayList<>(numChildren); 1222 for (int i = 0; i < numChildren; i++) { 1223 final View child = mStackScroller.getChildAt(i); 1224 if (child instanceof ExpandableNotificationRow) { 1225 ExpandableNotificationRow row = (ExpandableNotificationRow) child; 1226 boolean parentVisible = false; 1227 boolean hasClipBounds = child.getClipBounds(mTmpRect); 1228 if (mStackScroller.canChildBeDismissed(child)) { 1229 viewsToRemove.add(row); 1230 if (child.getVisibility() == View.VISIBLE 1231 && (!hasClipBounds || mTmpRect.height() > 0)) { 1232 viewsToHide.add(child); 1233 parentVisible = true; 1234 } 1235 } else if (child.getVisibility() == View.VISIBLE 1236 && (!hasClipBounds || mTmpRect.height() > 0)) { 1237 parentVisible = true; 1238 } 1239 List<ExpandableNotificationRow> children = row.getNotificationChildren(); 1240 if (children != null) { 1241 for (ExpandableNotificationRow childRow : children) { 1242 viewsToRemove.add(childRow); 1243 if (parentVisible && row.areChildrenExpanded() 1244 && mStackScroller.canChildBeDismissed(childRow)) { 1245 hasClipBounds = childRow.getClipBounds(mTmpRect); 1246 if (childRow.getVisibility() == View.VISIBLE 1247 && (!hasClipBounds || mTmpRect.height() > 0)) { 1248 viewsToHide.add(childRow); 1249 } 1250 } 1251 } 1252 } 1253 } 1254 } 1255 if (viewsToRemove.isEmpty()) { 1256 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE); 1257 return; 1258 } 1259 1260 addPostCollapseAction(() -> { 1261 mStackScroller.setDismissAllInProgress(false); 1262 for (ExpandableNotificationRow rowToRemove : viewsToRemove) { 1263 if (mStackScroller.canChildBeDismissed(rowToRemove)) { 1264 mEntryManager.removeNotification(rowToRemove.getEntry().key, null); 1265 } else { 1266 rowToRemove.resetTranslation(); 1267 } 1268 } 1269 try { 1270 mBarService.onClearAllNotifications(mLockscreenUserManager.getCurrentUserId()); 1271 } catch (Exception ex) { 1272 } 1273 }); 1274 1275 performDismissAllAnimations(viewsToHide); 1276 1277 } 1278 1279 private void performDismissAllAnimations(ArrayList<View> hideAnimatedList) { 1280 Runnable animationFinishAction = () -> { 1281 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE); 1282 }; 1283 1284 if (hideAnimatedList.isEmpty()) { 1285 animationFinishAction.run(); 1286 return; 1287 } 1288 1289 // let's disable our normal animations 1290 mStackScroller.setDismissAllInProgress(true); 1291 1292 // Decrease the delay for every row we animate to give the sense of 1293 // accelerating the swipes 1294 int rowDelayDecrement = 10; 1295 int currentDelay = 140; 1296 int totalDelay = 180; 1297 int numItems = hideAnimatedList.size(); 1298 for (int i = numItems - 1; i >= 0; i--) { 1299 View view = hideAnimatedList.get(i); 1300 Runnable endRunnable = null; 1301 if (i == 0) { 1302 endRunnable = animationFinishAction; 1303 } 1304 mStackScroller.dismissViewAnimated(view, endRunnable, totalDelay, 260); 1305 currentDelay = Math.max(50, currentDelay - rowDelayDecrement); 1306 totalDelay += currentDelay; 1307 } 1308 } 1309 1310 protected void startKeyguard() { 1311 Trace.beginSection("StatusBar#startKeyguard"); 1312 KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class); 1313 mFingerprintUnlockController = new FingerprintUnlockController(mContext, 1314 mDozeScrimController, keyguardViewMediator, 1315 mScrimController, this, UnlockMethodCache.getInstance(mContext)); 1316 mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this, 1317 getBouncerContainer(), mNotificationPanel, mFingerprintUnlockController); 1318 mKeyguardIndicationController 1319 .setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager); 1320 mFingerprintUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager); 1321 mRemoteInputManager.getController().addCallback(mStatusBarKeyguardViewManager); 1322 1323 mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback(); 1324 mLightBarController.setFingerprintUnlockController(mFingerprintUnlockController); 1325 Dependency.get(KeyguardDismissUtil.class).setDismissHandler(this::executeWhenUnlocked); 1326 Trace.endSection(); 1327 } 1328 1329 protected View getStatusBarView() { 1330 return mStatusBarView; 1331 } 1332 1333 public StatusBarWindowView getStatusBarWindow() { 1334 return mStatusBarWindow; 1335 } 1336 1337 protected ViewGroup getBouncerContainer() { 1338 return mStatusBarWindow; 1339 } 1340 1341 public int getStatusBarHeight() { 1342 if (mNaturalBarHeight < 0) { 1343 final Resources res = mContext.getResources(); 1344 mNaturalBarHeight = 1345 res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height); 1346 } 1347 return mNaturalBarHeight; 1348 } 1349 1350 protected boolean toggleSplitScreenMode(int metricsDockAction, int metricsUndockAction) { 1351 if (mRecents == null) { 1352 return false; 1353 } 1354 int dockSide = WindowManagerProxy.getInstance().getDockSide(); 1355 if (dockSide == WindowManager.DOCKED_INVALID) { 1356 final int navbarPos = WindowManagerWrapper.getInstance().getNavBarPosition(); 1357 if (navbarPos == NAV_BAR_POS_INVALID) { 1358 return false; 1359 } 1360 int createMode = navbarPos == NAV_BAR_POS_LEFT 1361 ? ActivityManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT 1362 : ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT; 1363 return mRecents.splitPrimaryTask(NavigationBarGestureHelper.DRAG_MODE_NONE, createMode, 1364 null, metricsDockAction); 1365 } else { 1366 Divider divider = getComponent(Divider.class); 1367 if (divider != null && divider.isMinimized() && !divider.isHomeStackResizable()) { 1368 // Undocking from the minimized state is not supported 1369 return false; 1370 } else { 1371 EventBus.getDefault().send(new UndockingTaskEvent()); 1372 if (metricsUndockAction != -1) { 1373 mMetricsLogger.action(metricsUndockAction); 1374 } 1375 } 1376 } 1377 return true; 1378 } 1379 1380 @Override 1381 public void onPerformRemoveNotification(StatusBarNotification n) { 1382 if (mStackScroller.hasPulsingNotifications() && 1383 !mHeadsUpManager.hasHeadsUpNotifications()) { 1384 // We were showing a pulse for a notification, but no notifications are pulsing anymore. 1385 // Finish the pulse. 1386 mDozeScrimController.pulseOutNow(); 1387 } 1388 } 1389 1390 @Override 1391 public void updateNotificationViews() { 1392 // The function updateRowStates depends on both of these being non-null, so check them here. 1393 // We may be called before they are set from DeviceProvisionedController's callback. 1394 if (mStackScroller == null || mScrimController == null) return; 1395 1396 // Do not modify the notifications during collapse. 1397 if (isCollapsing()) { 1398 addPostCollapseAction(this::updateNotificationViews); 1399 return; 1400 } 1401 1402 mViewHierarchyManager.updateNotificationViews(); 1403 1404 updateSpeedBumpIndex(); 1405 updateFooter(); 1406 updateEmptyShadeView(); 1407 1408 updateQsExpansionEnabled(); 1409 1410 // Let's also update the icons 1411 mNotificationIconAreaController.updateNotificationIcons(); 1412 } 1413 1414 @Override 1415 public void onNotificationAdded(Entry shadeEntry) { 1416 // Recalculate the position of the sliding windows and the titles. 1417 setAreThereNotifications(); 1418 } 1419 1420 @Override 1421 public void onNotificationUpdated(StatusBarNotification notification) { 1422 setAreThereNotifications(); 1423 } 1424 1425 @Override 1426 public void onNotificationRemoved(String key, StatusBarNotification old) { 1427 if (SPEW) Log.d(TAG, "removeNotification key=" + key + " old=" + old); 1428 1429 if (old != null) { 1430 if (CLOSE_PANEL_WHEN_EMPTIED && !hasActiveNotifications() 1431 && !mNotificationPanel.isTracking() && !mNotificationPanel.isQsExpanded()) { 1432 if (mState == StatusBarState.SHADE) { 1433 animateCollapsePanels(); 1434 } else if (mState == StatusBarState.SHADE_LOCKED && !isCollapsing()) { 1435 goToKeyguard(); 1436 } 1437 } 1438 } 1439 setAreThereNotifications(); 1440 } 1441 1442 /** 1443 * Disable QS if device not provisioned. 1444 * If the user switcher is simple then disable QS during setup because 1445 * the user intends to use the lock screen user switcher, QS in not needed. 1446 */ 1447 private void updateQsExpansionEnabled() { 1448 mNotificationPanel.setQsExpansionEnabled(isDeviceProvisioned() 1449 && (mUserSetup || mUserSwitcherController == null 1450 || !mUserSwitcherController.isSimpleUserSwitcher()) 1451 && ((mDisabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) == 0) 1452 && ((mDisabled2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) == 0) 1453 && !mDozing 1454 && !ONLY_CORE_APPS); 1455 } 1456 1457 public void addQsTile(ComponentName tile) { 1458 if (mQSPanel != null && mQSPanel.getHost() != null) { 1459 mQSPanel.getHost().addTile(tile); 1460 } 1461 } 1462 1463 public void remQsTile(ComponentName tile) { 1464 if (mQSPanel != null && mQSPanel.getHost() != null) { 1465 mQSPanel.getHost().removeTile(tile); 1466 } 1467 } 1468 1469 public void clickTile(ComponentName tile) { 1470 mQSPanel.clickTile(tile); 1471 } 1472 1473 @VisibleForTesting 1474 protected void updateFooter() { 1475 boolean showDismissView = mClearAllEnabled && hasActiveClearableNotifications(); 1476 boolean showFooterView = (showDismissView || 1477 mEntryManager.getNotificationData().getActiveNotifications().size() != 0) 1478 && mState != StatusBarState.KEYGUARD 1479 && !mRemoteInputManager.getController().isRemoteInputActive(); 1480 1481 mStackScroller.updateFooterView(showFooterView, showDismissView); 1482 } 1483 1484 /** 1485 * Return whether there are any clearable notifications 1486 */ 1487 private boolean hasActiveClearableNotifications() { 1488 int childCount = mStackScroller.getChildCount(); 1489 for (int i = 0; i < childCount; i++) { 1490 View child = mStackScroller.getChildAt(i); 1491 if (!(child instanceof ExpandableNotificationRow)) { 1492 continue; 1493 } 1494 if (((ExpandableNotificationRow) child).canViewBeDismissed()) { 1495 return true; 1496 } 1497 } 1498 return false; 1499 } 1500 1501 private void updateEmptyShadeView() { 1502 boolean showEmptyShadeView = 1503 mState != StatusBarState.KEYGUARD && 1504 mEntryManager.getNotificationData().getActiveNotifications().size() == 0; 1505 mNotificationPanel.showEmptyShadeView(showEmptyShadeView); 1506 } 1507 1508 private void updateSpeedBumpIndex() { 1509 int speedBumpIndex = 0; 1510 int currentIndex = 0; 1511 final int N = mStackScroller.getChildCount(); 1512 for (int i = 0; i < N; i++) { 1513 View view = mStackScroller.getChildAt(i); 1514 if (view.getVisibility() == View.GONE || !(view instanceof ExpandableNotificationRow)) { 1515 continue; 1516 } 1517 ExpandableNotificationRow row = (ExpandableNotificationRow) view; 1518 currentIndex++; 1519 if (!mEntryManager.getNotificationData().isAmbient( 1520 row.getStatusBarNotification().getKey())) { 1521 speedBumpIndex = currentIndex; 1522 } 1523 } 1524 boolean noAmbient = speedBumpIndex == N; 1525 mStackScroller.updateSpeedBumpIndex(speedBumpIndex, noAmbient); 1526 } 1527 1528 public static boolean isTopLevelChild(Entry entry) { 1529 return entry.row.getParent() instanceof NotificationStackScrollLayout; 1530 } 1531 1532 public boolean areNotificationsHidden() { 1533 return mZenController.areNotificationsHiddenInShade(); 1534 } 1535 1536 public void requestNotificationUpdate() { 1537 mEntryManager.updateNotifications(); 1538 } 1539 1540 protected void setAreThereNotifications() { 1541 1542 if (SPEW) { 1543 final boolean clearable = hasActiveNotifications() && 1544 hasActiveClearableNotifications(); 1545 Log.d(TAG, "setAreThereNotifications: N=" + 1546 mEntryManager.getNotificationData().getActiveNotifications().size() + " any=" + 1547 hasActiveNotifications() + " clearable=" + clearable); 1548 } 1549 1550 if (mStatusBarView != null) { 1551 final View nlo = mStatusBarView.findViewById(R.id.notification_lights_out); 1552 final boolean showDot = hasActiveNotifications() && !areLightsOn(); 1553 if (showDot != (nlo.getAlpha() == 1.0f)) { 1554 if (showDot) { 1555 nlo.setAlpha(0f); 1556 nlo.setVisibility(View.VISIBLE); 1557 } 1558 nlo.animate() 1559 .alpha(showDot ? 1 : 0) 1560 .setDuration(showDot ? 750 : 250) 1561 .setInterpolator(new AccelerateInterpolator(2.0f)) 1562 .setListener(showDot ? null : new AnimatorListenerAdapter() { 1563 @Override 1564 public void onAnimationEnd(Animator _a) { 1565 nlo.setVisibility(View.GONE); 1566 } 1567 }) 1568 .start(); 1569 } 1570 } 1571 1572 mMediaManager.findAndUpdateMediaNotifications(); 1573 } 1574 1575 1576 /** 1577 * Hide the album artwork that is fading out and release its bitmap. 1578 */ 1579 protected final Runnable mHideBackdropFront = new Runnable() { 1580 @Override 1581 public void run() { 1582 if (DEBUG_MEDIA) { 1583 Log.v(TAG, "DEBUG_MEDIA: removing fade layer"); 1584 } 1585 mBackdropFront.setVisibility(View.INVISIBLE); 1586 mBackdropFront.animate().cancel(); 1587 mBackdropFront.setImageDrawable(null); 1588 } 1589 }; 1590 1591 // TODO: Move this to NotificationMediaManager. 1592 /** 1593 * Refresh or remove lockscreen artwork from media metadata or the lockscreen wallpaper. 1594 */ 1595 @Override 1596 public void updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation) { 1597 Trace.beginSection("StatusBar#updateMediaMetaData"); 1598 if (!SHOW_LOCKSCREEN_MEDIA_ARTWORK) { 1599 Trace.endSection(); 1600 return; 1601 } 1602 1603 if (mBackdrop == null) { 1604 Trace.endSection(); 1605 return; // called too early 1606 } 1607 1608 boolean wakeAndUnlock = mFingerprintUnlockController != null 1609 && mFingerprintUnlockController.isWakeAndUnlock(); 1610 if (mLaunchTransitionFadingAway || wakeAndUnlock) { 1611 mBackdrop.setVisibility(View.INVISIBLE); 1612 Trace.endSection(); 1613 return; 1614 } 1615 1616 MediaMetadata mediaMetadata = mMediaManager.getMediaMetadata(); 1617 1618 if (DEBUG_MEDIA) { 1619 Log.v(TAG, "DEBUG_MEDIA: updating album art for notification " 1620 + mMediaManager.getMediaNotificationKey() 1621 + " metadata=" + mediaMetadata 1622 + " metaDataChanged=" + metaDataChanged 1623 + " state=" + mState); 1624 } 1625 1626 Drawable artworkDrawable = null; 1627 if (mediaMetadata != null) { 1628 Bitmap artworkBitmap = mediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ART); 1629 if (artworkBitmap == null) { 1630 artworkBitmap = mediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART); 1631 // might still be null 1632 } 1633 if (artworkBitmap != null) { 1634 artworkDrawable = new BitmapDrawable(mBackdropBack.getResources(), artworkBitmap); 1635 } 1636 } 1637 boolean allowWhenShade = false; 1638 if (ENABLE_LOCKSCREEN_WALLPAPER && artworkDrawable == null) { 1639 Bitmap lockWallpaper = mLockscreenWallpaper.getBitmap(); 1640 if (lockWallpaper != null) { 1641 artworkDrawable = new LockscreenWallpaper.WallpaperDrawable( 1642 mBackdropBack.getResources(), lockWallpaper); 1643 // We're in the SHADE mode on the SIM screen - yet we still need to show 1644 // the lockscreen wallpaper in that mode. 1645 allowWhenShade = mStatusBarKeyguardViewManager != null 1646 && mStatusBarKeyguardViewManager.isShowing(); 1647 } 1648 } 1649 1650 boolean hideBecauseOccluded = mStatusBarKeyguardViewManager != null 1651 && mStatusBarKeyguardViewManager.isOccluded(); 1652 1653 final boolean hasArtwork = artworkDrawable != null; 1654 1655 if ((hasArtwork || DEBUG_MEDIA_FAKE_ARTWORK) && !mDozing 1656 && (mState != StatusBarState.SHADE || allowWhenShade) 1657 && mFingerprintUnlockController.getMode() 1658 != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING 1659 && !hideBecauseOccluded) { 1660 // time to show some art! 1661 if (mBackdrop.getVisibility() != View.VISIBLE) { 1662 mBackdrop.setVisibility(View.VISIBLE); 1663 if (allowEnterAnimation) { 1664 mBackdrop.setAlpha(SRC_MIN_ALPHA); 1665 mBackdrop.animate().alpha(1f); 1666 } else { 1667 mBackdrop.animate().cancel(); 1668 mBackdrop.setAlpha(1f); 1669 } 1670 mStatusBarWindowManager.setBackdropShowing(true); 1671 mColorExtractor.setMediaBackdropVisible(true); 1672 metaDataChanged = true; 1673 if (DEBUG_MEDIA) { 1674 Log.v(TAG, "DEBUG_MEDIA: Fading in album artwork"); 1675 } 1676 } 1677 if (metaDataChanged) { 1678 if (mBackdropBack.getDrawable() != null) { 1679 Drawable drawable = 1680 mBackdropBack.getDrawable().getConstantState() 1681 .newDrawable(mBackdropFront.getResources()).mutate(); 1682 mBackdropFront.setImageDrawable(drawable); 1683 if (mScrimSrcModeEnabled) { 1684 mBackdropFront.getDrawable().mutate().setXfermode(mSrcOverXferMode); 1685 } 1686 mBackdropFront.setAlpha(1f); 1687 mBackdropFront.setVisibility(View.VISIBLE); 1688 } else { 1689 mBackdropFront.setVisibility(View.INVISIBLE); 1690 } 1691 1692 if (DEBUG_MEDIA_FAKE_ARTWORK) { 1693 final int c = 0xFF000000 | (int)(Math.random() * 0xFFFFFF); 1694 Log.v(TAG, String.format("DEBUG_MEDIA: setting new color: 0x%08x", c)); 1695 mBackdropBack.setBackgroundColor(0xFFFFFFFF); 1696 mBackdropBack.setImageDrawable(new ColorDrawable(c)); 1697 } else { 1698 mBackdropBack.setImageDrawable(artworkDrawable); 1699 } 1700 if (mScrimSrcModeEnabled) { 1701 mBackdropBack.getDrawable().mutate().setXfermode(mSrcXferMode); 1702 } 1703 1704 if (mBackdropFront.getVisibility() == View.VISIBLE) { 1705 if (DEBUG_MEDIA) { 1706 Log.v(TAG, "DEBUG_MEDIA: Crossfading album artwork from " 1707 + mBackdropFront.getDrawable() 1708 + " to " 1709 + mBackdropBack.getDrawable()); 1710 } 1711 mBackdropFront.animate() 1712 .setDuration(250) 1713 .alpha(0f).withEndAction(mHideBackdropFront); 1714 } 1715 } 1716 } else { 1717 // need to hide the album art, either because we are unlocked, on AOD 1718 // or because the metadata isn't there to support it 1719 if (mBackdrop.getVisibility() != View.GONE) { 1720 if (DEBUG_MEDIA) { 1721 Log.v(TAG, "DEBUG_MEDIA: Fading out album artwork"); 1722 } 1723 mColorExtractor.setMediaBackdropVisible(false); 1724 boolean cannotAnimateDoze = mDozing && !ScrimState.AOD.getAnimateChange(); 1725 if (mFingerprintUnlockController.getMode() 1726 == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING 1727 || hideBecauseOccluded || cannotAnimateDoze) { 1728 1729 // We are unlocking directly - no animation! 1730 mBackdrop.setVisibility(View.GONE); 1731 mBackdropBack.setImageDrawable(null); 1732 mStatusBarWindowManager.setBackdropShowing(false); 1733 } else { 1734 mStatusBarWindowManager.setBackdropShowing(false); 1735 mBackdrop.animate() 1736 .alpha(SRC_MIN_ALPHA) 1737 .setInterpolator(Interpolators.ACCELERATE_DECELERATE) 1738 .setDuration(300) 1739 .setStartDelay(0) 1740 .withEndAction(() -> { 1741 mBackdrop.setVisibility(View.GONE); 1742 mBackdropFront.animate().cancel(); 1743 mBackdropBack.setImageDrawable(null); 1744 mHandler.post(mHideBackdropFront); 1745 }); 1746 if (mKeyguardFadingAway) { 1747 mBackdrop.animate() 1748 // Make it disappear faster, as the focus should be on the activity 1749 // behind. 1750 .setDuration(mKeyguardFadingAwayDuration / 2) 1751 .setStartDelay(mKeyguardFadingAwayDelay) 1752 .setInterpolator(Interpolators.LINEAR) 1753 .start(); 1754 } 1755 } 1756 } 1757 } 1758 Trace.endSection(); 1759 } 1760 1761 private void updateReportRejectedTouchVisibility() { 1762 if (mReportRejectedTouch == null) { 1763 return; 1764 } 1765 mReportRejectedTouch.setVisibility(mState == StatusBarState.KEYGUARD && !mDozing 1766 && mFalsingManager.isReportingEnabled() ? View.VISIBLE : View.INVISIBLE); 1767 } 1768 1769 /** 1770 * State is one or more of the DISABLE constants from StatusBarManager. 1771 */ 1772 @Override 1773 public void disable(int state1, int state2, boolean animate) { 1774 state2 = mRemoteInputQuickSettingsDisabler.adjustDisableFlags(state2); 1775 1776 animate &= mStatusBarWindowState != WINDOW_STATE_HIDDEN; 1777 final int old1 = mDisabled1; 1778 final int diff1 = state1 ^ old1; 1779 mDisabled1 = state1; 1780 1781 final int old2 = mDisabled2; 1782 final int diff2 = state2 ^ old2; 1783 mDisabled2 = state2; 1784 1785 if (DEBUG) { 1786 Log.d(TAG, String.format("disable1: 0x%08x -> 0x%08x (diff1: 0x%08x)", 1787 old1, state1, diff1)); 1788 Log.d(TAG, String.format("disable2: 0x%08x -> 0x%08x (diff2: 0x%08x)", 1789 old2, state2, diff2)); 1790 } 1791 1792 StringBuilder flagdbg = new StringBuilder(); 1793 flagdbg.append("disable<"); 1794 flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_EXPAND)) ? 'E' : 'e'); 1795 flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_EXPAND)) ? '!' : ' '); 1796 flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS)) ? 'I' : 'i'); 1797 flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS)) ? '!' : ' '); 1798 flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS)) ? 'A' : 'a'); 1799 flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS)) ? '!' : ' '); 1800 flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_SYSTEM_INFO)) ? 'S' : 's'); 1801 flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_SYSTEM_INFO)) ? '!' : ' '); 1802 flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_BACK)) ? 'B' : 'b'); 1803 flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_BACK)) ? '!' : ' '); 1804 flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_HOME)) ? 'H' : 'h'); 1805 flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_HOME)) ? '!' : ' '); 1806 flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_RECENT)) ? 'R' : 'r'); 1807 flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_RECENT)) ? '!' : ' '); 1808 flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_CLOCK)) ? 'C' : 'c'); 1809 flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_CLOCK)) ? '!' : ' '); 1810 flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_SEARCH)) ? 'S' : 's'); 1811 flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_SEARCH)) ? '!' : ' '); 1812 flagdbg.append("> disable2<"); 1813 flagdbg.append(0 != ((state2 & StatusBarManager.DISABLE2_QUICK_SETTINGS)) ? 'Q' : 'q'); 1814 flagdbg.append(0 != ((diff2 & StatusBarManager.DISABLE2_QUICK_SETTINGS)) ? '!' : ' '); 1815 flagdbg.append(0 != ((state2 & StatusBarManager.DISABLE2_SYSTEM_ICONS)) ? 'I' : 'i'); 1816 flagdbg.append(0 != ((diff2 & StatusBarManager.DISABLE2_SYSTEM_ICONS)) ? '!' : ' '); 1817 flagdbg.append(0 != ((state2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE)) ? 'N' : 'n'); 1818 flagdbg.append(0 != ((diff2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE)) ? '!' : ' '); 1819 flagdbg.append('>'); 1820 Log.d(TAG, flagdbg.toString()); 1821 1822 if ((diff1 & StatusBarManager.DISABLE_EXPAND) != 0) { 1823 if ((state1 & StatusBarManager.DISABLE_EXPAND) != 0) { 1824 animateCollapsePanels(); 1825 } 1826 } 1827 1828 if ((diff1 & StatusBarManager.DISABLE_RECENT) != 0) { 1829 if ((state1 & StatusBarManager.DISABLE_RECENT) != 0) { 1830 // close recents if it's visible 1831 mHandler.removeMessages(MSG_HIDE_RECENT_APPS); 1832 mHandler.sendEmptyMessage(MSG_HIDE_RECENT_APPS); 1833 } 1834 } 1835 1836 if ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) { 1837 mEntryManager.setDisableNotificationAlerts( 1838 (state1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0); 1839 } 1840 1841 if ((diff2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) { 1842 updateQsExpansionEnabled(); 1843 } 1844 1845 if ((diff2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0) { 1846 updateQsExpansionEnabled(); 1847 if ((state1 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0) { 1848 animateCollapsePanels(); 1849 } 1850 } 1851 } 1852 1853 /** 1854 * Reapplies the disable flags as last requested by StatusBarManager. 1855 * 1856 * This needs to be called if state used by {@link #adjustDisableFlags} changes. 1857 */ 1858 public void recomputeDisableFlags(boolean animate) { 1859 mCommandQueue.recomputeDisableFlags(animate); 1860 } 1861 1862 protected H createHandler() { 1863 return new StatusBar.H(); 1864 } 1865 1866 private void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade, 1867 int flags) { 1868 startActivityDismissingKeyguard(intent, onlyProvisioned, dismissShade, flags); 1869 } 1870 1871 @Override 1872 public void startActivity(Intent intent, boolean dismissShade) { 1873 startActivityDismissingKeyguard(intent, false, dismissShade); 1874 } 1875 1876 @Override 1877 public void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade) { 1878 startActivityDismissingKeyguard(intent, onlyProvisioned, dismissShade); 1879 } 1880 1881 @Override 1882 public void startActivity(Intent intent, boolean dismissShade, Callback callback) { 1883 startActivityDismissingKeyguard(intent, false, dismissShade, 1884 false /* disallowEnterPictureInPictureWhileLaunching */, callback, 0); 1885 } 1886 1887 public void setQsExpanded(boolean expanded) { 1888 mStatusBarWindowManager.setQsExpanded(expanded); 1889 mNotificationPanel.setStatusAccessibilityImportance(expanded 1890 ? View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 1891 : View.IMPORTANT_FOR_ACCESSIBILITY_AUTO); 1892 } 1893 1894 public boolean isGoingToNotificationShade() { 1895 return mLeaveOpenOnKeyguardHide; 1896 } 1897 1898 public boolean isWakeUpComingFromTouch() { 1899 return mWakeUpComingFromTouch; 1900 } 1901 1902 public boolean isFalsingThresholdNeeded() { 1903 return getBarState() == StatusBarState.KEYGUARD; 1904 } 1905 1906 @Override 1907 public boolean isDozing() { 1908 return mDozing && mStackScroller.isFullyDark(); 1909 } 1910 1911 @Override 1912 public boolean shouldPeek(Entry entry, StatusBarNotification sbn) { 1913 if (mIsOccluded && !isDozing()) { 1914 boolean devicePublic = mLockscreenUserManager. 1915 isLockscreenPublicMode(mLockscreenUserManager.getCurrentUserId()); 1916 boolean userPublic = devicePublic 1917 || mLockscreenUserManager.isLockscreenPublicMode(sbn.getUserId()); 1918 boolean needsRedaction = mLockscreenUserManager.needsRedaction(entry); 1919 if (userPublic && needsRedaction) { 1920 return false; 1921 } 1922 } 1923 1924 if (!panelsEnabled()) { 1925 if (DEBUG) { 1926 Log.d(TAG, "No peeking: disabled panel : " + sbn.getKey()); 1927 } 1928 return false; 1929 } 1930 1931 if (sbn.getNotification().fullScreenIntent != null) { 1932 if (mAccessibilityManager.isTouchExplorationEnabled()) { 1933 if (DEBUG) Log.d(TAG, "No peeking: accessible fullscreen: " + sbn.getKey()); 1934 return false; 1935 } else if (isDozing()) { 1936 // We never want heads up when we are dozing. 1937 return false; 1938 } else { 1939 // we only allow head-up on the lockscreen if it doesn't have a fullscreen intent 1940 return !mStatusBarKeyguardViewManager.isShowing() 1941 || mStatusBarKeyguardViewManager.isOccluded(); 1942 } 1943 } 1944 return true; 1945 } 1946 1947 @Override // NotificationData.Environment 1948 public String getCurrentMediaNotificationKey() { 1949 return mMediaManager.getMediaNotificationKey(); 1950 } 1951 1952 public boolean isScrimSrcModeEnabled() { 1953 return mScrimSrcModeEnabled; 1954 } 1955 1956 /** 1957 * To be called when there's a state change in StatusBarKeyguardViewManager. 1958 */ 1959 public void onKeyguardViewManagerStatesUpdated() { 1960 logStateToEventlog(); 1961 } 1962 1963 @Override // UnlockMethodCache.OnUnlockMethodChangedListener 1964 public void onUnlockMethodStateChanged() { 1965 logStateToEventlog(); 1966 } 1967 1968 @Override 1969 public void onHeadsUpPinnedModeChanged(boolean inPinnedMode) { 1970 if (inPinnedMode) { 1971 mStatusBarWindowManager.setHeadsUpShowing(true); 1972 mStatusBarWindowManager.setForceStatusBarVisible(true); 1973 if (mNotificationPanel.isFullyCollapsed()) { 1974 // We need to ensure that the touchable region is updated before the window will be 1975 // resized, in order to not catch any touches. A layout will ensure that 1976 // onComputeInternalInsets will be called and after that we can resize the layout. Let's 1977 // make sure that the window stays small for one frame until the touchableRegion is set. 1978 mNotificationPanel.requestLayout(); 1979 mStatusBarWindowManager.setForceWindowCollapsed(true); 1980 mNotificationPanel.post(() -> { 1981 mStatusBarWindowManager.setForceWindowCollapsed(false); 1982 }); 1983 } 1984 } else { 1985 if (!mNotificationPanel.isFullyCollapsed() || mNotificationPanel.isTracking()) { 1986 // We are currently tracking or is open and the shade doesn't need to be kept 1987 // open artificially. 1988 mStatusBarWindowManager.setHeadsUpShowing(false); 1989 } else { 1990 // we need to keep the panel open artificially, let's wait until the animation 1991 // is finished. 1992 mHeadsUpManager.setHeadsUpGoingAway(true); 1993 mStackScroller.runAfterAnimationFinished(() -> { 1994 if (!mHeadsUpManager.hasPinnedHeadsUp()) { 1995 mStatusBarWindowManager.setHeadsUpShowing(false); 1996 mHeadsUpManager.setHeadsUpGoingAway(false); 1997 } 1998 mRemoteInputManager.removeRemoteInputEntriesKeptUntilCollapsed(); 1999 }); 2000 } 2001 } 2002 } 2003 2004 @Override 2005 public void onHeadsUpPinned(ExpandableNotificationRow headsUp) { 2006 dismissVolumeDialog(); 2007 } 2008 2009 @Override 2010 public void onHeadsUpUnPinned(ExpandableNotificationRow headsUp) { 2011 } 2012 2013 @Override 2014 public void onHeadsUpStateChanged(Entry entry, boolean isHeadsUp) { 2015 mEntryManager.onHeadsUpStateChanged(entry, isHeadsUp); 2016 2017 if (isHeadsUp) { 2018 mDozeServiceHost.fireNotificationHeadsUp(); 2019 } 2020 } 2021 2022 protected void setHeadsUpUser(int newUserId) { 2023 if (mHeadsUpManager != null) { 2024 mHeadsUpManager.setUser(newUserId); 2025 } 2026 } 2027 2028 public boolean isKeyguardCurrentlySecure() { 2029 return !mUnlockMethodCache.canSkipBouncer(); 2030 } 2031 2032 public void setPanelExpanded(boolean isExpanded) { 2033 mPanelExpanded = isExpanded; 2034 updateHideIconsForBouncer(false /* animate */); 2035 mStatusBarWindowManager.setPanelExpanded(isExpanded); 2036 mVisualStabilityManager.setPanelExpanded(isExpanded); 2037 if (isExpanded && getBarState() != StatusBarState.KEYGUARD) { 2038 if (DEBUG) { 2039 Log.v(TAG, "clearing notification effects from setExpandedHeight"); 2040 } 2041 clearNotificationEffects(); 2042 } 2043 2044 if (!isExpanded) { 2045 mRemoteInputManager.removeRemoteInputEntriesKeptUntilCollapsed(); 2046 } 2047 } 2048 2049 public NotificationStackScrollLayout getNotificationScrollLayout() { 2050 return mStackScroller; 2051 } 2052 2053 public boolean isPulsing() { 2054 return mDozeScrimController != null && mDozeScrimController.isPulsing(); 2055 } 2056 2057 public boolean isLaunchTransitionFadingAway() { 2058 return mLaunchTransitionFadingAway; 2059 } 2060 2061 public boolean hideStatusBarIconsWhenExpanded() { 2062 return mNotificationPanel.hideStatusBarIconsWhenExpanded(); 2063 } 2064 2065 @Override 2066 public void onColorsChanged(ColorExtractor extractor, int which) { 2067 updateTheme(); 2068 } 2069 2070 public boolean isUsingDarkTheme() { 2071 OverlayInfo themeInfo = null; 2072 try { 2073 themeInfo = mOverlayManager.getOverlayInfo("com.android.systemui.theme.dark", 2074 mLockscreenUserManager.getCurrentUserId()); 2075 } catch (RemoteException e) { 2076 e.printStackTrace(); 2077 } 2078 return themeInfo != null && themeInfo.isEnabled(); 2079 } 2080 2081 @Nullable 2082 public View getAmbientIndicationContainer() { 2083 return mAmbientIndicationContainer; 2084 } 2085 2086 public void setOccluded(boolean occluded) { 2087 mIsOccluded = occluded; 2088 mScrimController.setKeyguardOccluded(occluded); 2089 updateHideIconsForBouncer(false /* animate */); 2090 } 2091 2092 public boolean hideStatusBarIconsForBouncer() { 2093 return mHideIconsForBouncer || mWereIconsJustHidden; 2094 } 2095 2096 /** 2097 * Decides if the status bar (clock + notifications + signal cluster) should be visible 2098 * or not when showing the bouncer. 2099 * 2100 * We want to hide it when: 2101 * User swipes up on the keyguard 2102 * Locked activity that doesn't show a status bar requests the bouncer 2103 * 2104 * @param animate should the change of the icons be animated. 2105 */ 2106 private void updateHideIconsForBouncer(boolean animate) { 2107 boolean hideBecauseApp = mTopHidesStatusBar && mIsOccluded 2108 && (mStatusBarWindowHidden || mBouncerShowing); 2109 boolean hideBecauseKeyguard = !mPanelExpanded && !mIsOccluded && mBouncerShowing; 2110 boolean shouldHideIconsForBouncer = hideBecauseApp || hideBecauseKeyguard; 2111 if (mHideIconsForBouncer != shouldHideIconsForBouncer) { 2112 mHideIconsForBouncer = shouldHideIconsForBouncer; 2113 if (!shouldHideIconsForBouncer && mBouncerWasShowingWhenHidden) { 2114 // We're delaying the showing, since most of the time the fullscreen app will 2115 // hide the icons again and we don't want them to fade in and out immediately again. 2116 mWereIconsJustHidden = true; 2117 mHandler.postDelayed(() -> { 2118 mWereIconsJustHidden = false; 2119 recomputeDisableFlags(true); 2120 }, 500); 2121 } else { 2122 recomputeDisableFlags(animate); 2123 } 2124 } 2125 if (shouldHideIconsForBouncer) { 2126 mBouncerWasShowingWhenHidden = mBouncerShowing; 2127 } 2128 } 2129 2130 public void onLaunchAnimationCancelled() { 2131 if (!isCollapsing()) { 2132 onClosingFinished(); 2133 } 2134 } 2135 2136 /** 2137 * All changes to the status bar and notifications funnel through here and are batched. 2138 */ 2139 protected class H extends Handler { 2140 @Override 2141 public void handleMessage(Message m) { 2142 switch (m.what) { 2143 case MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU: 2144 toggleKeyboardShortcuts(m.arg1); 2145 break; 2146 case MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU: 2147 dismissKeyboardShortcuts(); 2148 break; 2149 // End old BaseStatusBar.H handling. 2150 case MSG_OPEN_NOTIFICATION_PANEL: 2151 animateExpandNotificationsPanel(); 2152 break; 2153 case MSG_OPEN_SETTINGS_PANEL: 2154 animateExpandSettingsPanel((String) m.obj); 2155 break; 2156 case MSG_CLOSE_PANELS: 2157 animateCollapsePanels(); 2158 break; 2159 case MSG_LAUNCH_TRANSITION_TIMEOUT: 2160 onLaunchTransitionTimeout(); 2161 break; 2162 } 2163 } 2164 } 2165 2166 public void maybeEscalateHeadsUp() { 2167 mHeadsUpManager.getAllEntries().forEach(entry -> { 2168 final StatusBarNotification sbn = entry.notification; 2169 final Notification notification = sbn.getNotification(); 2170 if (notification.fullScreenIntent != null) { 2171 if (DEBUG) { 2172 Log.d(TAG, "converting a heads up to fullScreen"); 2173 } 2174 try { 2175 EventLog.writeEvent(EventLogTags.SYSUI_HEADS_UP_ESCALATION, 2176 sbn.getKey()); 2177 notification.fullScreenIntent.send(); 2178 entry.notifyFullScreenIntentLaunched(); 2179 } catch (PendingIntent.CanceledException e) { 2180 } 2181 } 2182 }); 2183 mHeadsUpManager.releaseAllImmediately(); 2184 } 2185 2186 /** 2187 * Called for system navigation gestures. First action opens the panel, second opens 2188 * settings. Down action closes the entire panel. 2189 */ 2190 @Override 2191 public void handleSystemKey(int key) { 2192 if (SPEW) Log.d(TAG, "handleNavigationKey: " + key); 2193 if (!panelsEnabled() || !mKeyguardMonitor.isDeviceInteractive() 2194 || mKeyguardMonitor.isShowing() && !mKeyguardMonitor.isOccluded()) { 2195 return; 2196 } 2197 2198 // Panels are not available in setup 2199 if (!mUserSetup) return; 2200 2201 if (KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP == key) { 2202 mMetricsLogger.action(MetricsEvent.ACTION_SYSTEM_NAVIGATION_KEY_UP); 2203 mNotificationPanel.collapse(false /* delayed */, 1.0f /* speedUpFactor */); 2204 } else if (KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN == key) { 2205 mMetricsLogger.action(MetricsEvent.ACTION_SYSTEM_NAVIGATION_KEY_DOWN); 2206 if (mNotificationPanel.isFullyCollapsed()) { 2207 if (mVibrateOnOpening) { 2208 mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK); 2209 } 2210 mNotificationPanel.expand(true /* animate */); 2211 mMetricsLogger.count(NotificationPanelView.COUNTER_PANEL_OPEN, 1); 2212 } else if (!mNotificationPanel.isInSettings() && !mNotificationPanel.isExpanding()){ 2213 mNotificationPanel.flingSettings(0 /* velocity */, true /* expand */); 2214 mMetricsLogger.count(NotificationPanelView.COUNTER_PANEL_OPEN_QS, 1); 2215 } 2216 } 2217 2218 } 2219 2220 @Override 2221 public void showPinningEnterExitToast(boolean entering) { 2222 if (entering) { 2223 mScreenPinningNotify.showPinningStartToast(); 2224 } else { 2225 mScreenPinningNotify.showPinningExitToast(); 2226 } 2227 } 2228 2229 @Override 2230 public void showPinningEscapeToast() { 2231 mScreenPinningNotify.showEscapeToast(getNavigationBarView() == null 2232 || getNavigationBarView().isRecentsButtonVisible()); 2233 } 2234 2235 boolean panelsEnabled() { 2236 return (mDisabled1 & StatusBarManager.DISABLE_EXPAND) == 0 2237 && (mDisabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) == 0 2238 && !ONLY_CORE_APPS; 2239 } 2240 2241 void makeExpandedVisible(boolean force) { 2242 if (SPEW) Log.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible); 2243 if (!force && (mExpandedVisible || !panelsEnabled())) { 2244 return; 2245 } 2246 2247 mExpandedVisible = true; 2248 2249 // Expand the window to encompass the full screen in anticipation of the drag. 2250 // This is only possible to do atomically because the status bar is at the top of the screen! 2251 mStatusBarWindowManager.setPanelVisible(true); 2252 2253 visibilityChanged(true); 2254 recomputeDisableFlags(!force /* animate */); 2255 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true); 2256 } 2257 2258 public void animateCollapsePanels() { 2259 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE); 2260 } 2261 2262 private final Runnable mAnimateCollapsePanels = this::animateCollapsePanels; 2263 2264 public void postAnimateCollapsePanels() { 2265 mHandler.post(mAnimateCollapsePanels); 2266 } 2267 2268 public void postAnimateForceCollapsePanels() { 2269 mHandler.post(() -> { 2270 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */); 2271 }); 2272 } 2273 2274 public void postAnimateOpenPanels() { 2275 mHandler.sendEmptyMessage(MSG_OPEN_SETTINGS_PANEL); 2276 } 2277 2278 @Override 2279 public void togglePanel() { 2280 if (mPanelExpanded) { 2281 animateCollapsePanels(); 2282 } else { 2283 animateExpandNotificationsPanel(); 2284 } 2285 } 2286 2287 @Override 2288 public void animateCollapsePanels(int flags) { 2289 animateCollapsePanels(flags, false /* force */, false /* delayed */, 2290 1.0f /* speedUpFactor */); 2291 } 2292 2293 public void animateCollapsePanels(int flags, boolean force) { 2294 animateCollapsePanels(flags, force, false /* delayed */, 1.0f /* speedUpFactor */); 2295 } 2296 2297 public void animateCollapsePanels(int flags, boolean force, boolean delayed) { 2298 animateCollapsePanels(flags, force, delayed, 1.0f /* speedUpFactor */); 2299 } 2300 2301 public void animateCollapsePanels(int flags, boolean force, boolean delayed, 2302 float speedUpFactor) { 2303 if (!force && mState != StatusBarState.SHADE) { 2304 runPostCollapseRunnables(); 2305 return; 2306 } 2307 if (SPEW) { 2308 Log.d(TAG, "animateCollapse():" 2309 + " mExpandedVisible=" + mExpandedVisible 2310 + " flags=" + flags); 2311 } 2312 2313 if ((flags & CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL) == 0) { 2314 if (!mHandler.hasMessages(MSG_HIDE_RECENT_APPS)) { 2315 mHandler.removeMessages(MSG_HIDE_RECENT_APPS); 2316 mHandler.sendEmptyMessage(MSG_HIDE_RECENT_APPS); 2317 } 2318 } 2319 2320 // TODO(b/62444020): remove when this bug is fixed 2321 Log.v(TAG, "mStatusBarWindow: " + mStatusBarWindow + " canPanelBeCollapsed(): " 2322 + mNotificationPanel.canPanelBeCollapsed()); 2323 if (mStatusBarWindow != null && mNotificationPanel.canPanelBeCollapsed()) { 2324 // release focus immediately to kick off focus change transition 2325 mStatusBarWindowManager.setStatusBarFocusable(false); 2326 2327 mStatusBarWindow.cancelExpandHelper(); 2328 mStatusBarView.collapsePanel(true /* animate */, delayed, speedUpFactor); 2329 } 2330 } 2331 2332 private void runPostCollapseRunnables() { 2333 ArrayList<Runnable> clonedList = new ArrayList<>(mPostCollapseRunnables); 2334 mPostCollapseRunnables.clear(); 2335 int size = clonedList.size(); 2336 for (int i = 0; i < size; i++) { 2337 clonedList.get(i).run(); 2338 } 2339 mStatusBarKeyguardViewManager.readyForKeyguardDone(); 2340 } 2341 2342 @Override 2343 public void animateExpandNotificationsPanel() { 2344 if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible); 2345 if (!panelsEnabled()) { 2346 return ; 2347 } 2348 2349 mNotificationPanel.expandWithoutQs(); 2350 2351 if (false) postStartTracing(); 2352 } 2353 2354 @Override 2355 public void animateExpandSettingsPanel(String subPanel) { 2356 if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible); 2357 if (!panelsEnabled()) { 2358 return; 2359 } 2360 2361 // Settings are not available in setup 2362 if (!mUserSetup) return; 2363 2364 2365 if (subPanel != null) { 2366 mQSPanel.openDetails(subPanel); 2367 } 2368 mNotificationPanel.expandWithQs(); 2369 2370 if (false) postStartTracing(); 2371 } 2372 2373 public void animateCollapseQuickSettings() { 2374 if (mState == StatusBarState.SHADE) { 2375 mStatusBarView.collapsePanel(true, false /* delayed */, 1.0f /* speedUpFactor */); 2376 } 2377 } 2378 2379 void makeExpandedInvisible() { 2380 if (SPEW) Log.d(TAG, "makeExpandedInvisible: mExpandedVisible=" + mExpandedVisible 2381 + " mExpandedVisible=" + mExpandedVisible); 2382 2383 if (!mExpandedVisible || mStatusBarWindow == null) { 2384 return; 2385 } 2386 2387 // Ensure the panel is fully collapsed (just in case; bug 6765842, 7260868) 2388 mStatusBarView.collapsePanel(/*animate=*/ false, false /* delayed*/, 2389 1.0f /* speedUpFactor */); 2390 2391 mNotificationPanel.closeQs(); 2392 2393 mExpandedVisible = false; 2394 visibilityChanged(false); 2395 2396 // Shrink the window to the size of the status bar only 2397 mStatusBarWindowManager.setPanelVisible(false); 2398 mStatusBarWindowManager.setForceStatusBarVisible(false); 2399 2400 // Close any guts that might be visible 2401 mGutsManager.closeAndSaveGuts(true /* removeLeavebehind */, true /* force */, 2402 true /* removeControls */, -1 /* x */, -1 /* y */, true /* resetMenu */); 2403 2404 runPostCollapseRunnables(); 2405 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false); 2406 showBouncerIfKeyguard(); 2407 recomputeDisableFlags(mNotificationPanel.hideStatusBarIconsWhenExpanded() /* animate */); 2408 2409 // Trimming will happen later if Keyguard is showing - doing it here might cause a jank in 2410 // the bouncer appear animation. 2411 if (!mStatusBarKeyguardViewManager.isShowing()) { 2412 WindowManagerGlobal.getInstance().trimMemory(ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN); 2413 } 2414 } 2415 2416 public boolean interceptTouchEvent(MotionEvent event) { 2417 if (DEBUG_GESTURES) { 2418 if (event.getActionMasked() != MotionEvent.ACTION_MOVE) { 2419 EventLog.writeEvent(EventLogTags.SYSUI_STATUSBAR_TOUCH, 2420 event.getActionMasked(), (int) event.getX(), (int) event.getY(), 2421 mDisabled1, mDisabled2); 2422 } 2423 2424 } 2425 2426 if (SPEW) { 2427 Log.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled1=" 2428 + mDisabled1 + " mDisabled2=" + mDisabled2); 2429 } else if (CHATTY) { 2430 if (event.getAction() != MotionEvent.ACTION_MOVE) { 2431 Log.d(TAG, String.format( 2432 "panel: %s at (%f, %f) mDisabled1=0x%08x mDisabled2=0x%08x", 2433 MotionEvent.actionToString(event.getAction()), 2434 event.getRawX(), event.getRawY(), mDisabled1, mDisabled2)); 2435 } 2436 } 2437 2438 if (DEBUG_GESTURES) { 2439 mGestureRec.add(event); 2440 } 2441 2442 if (mStatusBarWindowState == WINDOW_STATE_SHOWING) { 2443 final boolean upOrCancel = 2444 event.getAction() == MotionEvent.ACTION_UP || 2445 event.getAction() == MotionEvent.ACTION_CANCEL; 2446 if (upOrCancel && !mExpandedVisible) { 2447 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false); 2448 } else { 2449 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true); 2450 } 2451 } 2452 return false; 2453 } 2454 2455 public GestureRecorder getGestureRecorder() { 2456 return mGestureRec; 2457 } 2458 2459 public FingerprintUnlockController getFingerprintUnlockController() { 2460 return mFingerprintUnlockController; 2461 } 2462 2463 @Override // CommandQueue 2464 public void setWindowState(int window, int state) { 2465 boolean showing = state == WINDOW_STATE_SHOWING; 2466 if (mStatusBarWindow != null 2467 && window == StatusBarManager.WINDOW_STATUS_BAR 2468 && mStatusBarWindowState != state) { 2469 mStatusBarWindowState = state; 2470 if (DEBUG_WINDOW_STATE) Log.d(TAG, "Status bar " + windowStateToString(state)); 2471 if (!showing && mState == StatusBarState.SHADE) { 2472 mStatusBarView.collapsePanel(false /* animate */, false /* delayed */, 2473 1.0f /* speedUpFactor */); 2474 } 2475 if (mStatusBarView != null) { 2476 mStatusBarWindowHidden = state == WINDOW_STATE_HIDDEN; 2477 updateHideIconsForBouncer(false /* animate */); 2478 } 2479 } 2480 } 2481 2482 @Override // CommandQueue 2483 public void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis, 2484 int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) { 2485 final int oldVal = mSystemUiVisibility; 2486 final int newVal = (oldVal&~mask) | (vis&mask); 2487 final int diff = newVal ^ oldVal; 2488 if (DEBUG) Log.d(TAG, String.format( 2489 "setSystemUiVisibility vis=%s mask=%s oldVal=%s newVal=%s diff=%s", 2490 Integer.toHexString(vis), Integer.toHexString(mask), 2491 Integer.toHexString(oldVal), Integer.toHexString(newVal), 2492 Integer.toHexString(diff))); 2493 boolean sbModeChanged = false; 2494 if (diff != 0) { 2495 mSystemUiVisibility = newVal; 2496 2497 // update low profile 2498 if ((diff & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0) { 2499 setAreThereNotifications(); 2500 } 2501 2502 // ready to unhide 2503 if ((vis & View.STATUS_BAR_UNHIDE) != 0) { 2504 mSystemUiVisibility &= ~View.STATUS_BAR_UNHIDE; 2505 mNoAnimationOnNextBarModeChange = true; 2506 } 2507 2508 // update status bar mode 2509 final int sbMode = computeStatusBarMode(oldVal, newVal); 2510 2511 sbModeChanged = sbMode != -1; 2512 if (sbModeChanged && sbMode != mStatusBarMode) { 2513 mStatusBarMode = sbMode; 2514 checkBarModes(); 2515 touchAutoHide(); 2516 } 2517 2518 if ((vis & View.NAVIGATION_BAR_UNHIDE) != 0) { 2519 mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE; 2520 } 2521 2522 // send updated sysui visibility to window manager 2523 notifyUiVisibilityChanged(mSystemUiVisibility); 2524 } 2525 2526 mLightBarController.onSystemUiVisibilityChanged(fullscreenStackVis, dockedStackVis, 2527 mask, fullscreenStackBounds, dockedStackBounds, sbModeChanged, mStatusBarMode); 2528 } 2529 2530 @Override 2531 public void showWirelessChargingAnimation(int batteryLevel) { 2532 if (mDozing || mKeyguardManager.isKeyguardLocked()) { 2533 // on ambient or lockscreen, hide notification panel 2534 WirelessChargingAnimation.makeWirelessChargingAnimation(mContext, null, 2535 batteryLevel, new WirelessChargingAnimation.Callback() { 2536 @Override 2537 public void onAnimationStarting() { 2538 CrossFadeHelper.fadeOut(mNotificationPanel, 1); 2539 } 2540 2541 @Override 2542 public void onAnimationEnded() { 2543 CrossFadeHelper.fadeIn(mNotificationPanel); 2544 } 2545 }, mDozing).show(); 2546 } else { 2547 // workspace 2548 WirelessChargingAnimation.makeWirelessChargingAnimation(mContext, null, 2549 batteryLevel, null, false).show(); 2550 } 2551 } 2552 2553 void touchAutoHide() { 2554 // update transient bar autohide 2555 if (mStatusBarMode == MODE_SEMI_TRANSPARENT || (mNavigationBar != null 2556 && mNavigationBar.isSemiTransparent())) { 2557 scheduleAutohide(); 2558 } else { 2559 cancelAutohide(); 2560 } 2561 } 2562 2563 protected int computeStatusBarMode(int oldVal, int newVal) { 2564 return computeBarMode(oldVal, newVal, View.STATUS_BAR_TRANSIENT, 2565 View.STATUS_BAR_TRANSLUCENT, View.STATUS_BAR_TRANSPARENT); 2566 } 2567 2568 protected BarTransitions getStatusBarTransitions() { 2569 return mStatusBarView.getBarTransitions(); 2570 } 2571 2572 protected int computeBarMode(int oldVis, int newVis, 2573 int transientFlag, int translucentFlag, int transparentFlag) { 2574 final int oldMode = barMode(oldVis, transientFlag, translucentFlag, transparentFlag); 2575 final int newMode = barMode(newVis, transientFlag, translucentFlag, transparentFlag); 2576 if (oldMode == newMode) { 2577 return -1; // no mode change 2578 } 2579 return newMode; 2580 } 2581 2582 private int barMode(int vis, int transientFlag, int translucentFlag, int transparentFlag) { 2583 int lightsOutTransparent = View.SYSTEM_UI_FLAG_LOW_PROFILE | transparentFlag; 2584 return (vis & transientFlag) != 0 ? MODE_SEMI_TRANSPARENT 2585 : (vis & translucentFlag) != 0 ? MODE_TRANSLUCENT 2586 : (vis & lightsOutTransparent) == lightsOutTransparent ? MODE_LIGHTS_OUT_TRANSPARENT 2587 : (vis & transparentFlag) != 0 ? MODE_TRANSPARENT 2588 : (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0 ? MODE_LIGHTS_OUT 2589 : MODE_OPAQUE; 2590 } 2591 2592 void checkBarModes() { 2593 if (mDemoMode) return; 2594 if (mStatusBarView != null) checkBarMode(mStatusBarMode, mStatusBarWindowState, 2595 getStatusBarTransitions()); 2596 if (mNavigationBar != null) mNavigationBar.checkNavBarModes(); 2597 mNoAnimationOnNextBarModeChange = false; 2598 } 2599 2600 // Called by NavigationBarFragment 2601 void setQsScrimEnabled(boolean scrimEnabled) { 2602 mNotificationPanel.setQsScrimEnabled(scrimEnabled); 2603 } 2604 2605 void checkBarMode(int mode, int windowState, BarTransitions transitions) { 2606 final boolean anim = !mNoAnimationOnNextBarModeChange && mDeviceInteractive 2607 && windowState != WINDOW_STATE_HIDDEN; 2608 transitions.transitionTo(mode, anim); 2609 } 2610 2611 private void finishBarAnimations() { 2612 if (mStatusBarView != null) { 2613 mStatusBarView.getBarTransitions().finishAnimations(); 2614 } 2615 if (mNavigationBar != null) { 2616 mNavigationBar.finishBarAnimations(); 2617 } 2618 } 2619 2620 private final Runnable mCheckBarModes = this::checkBarModes; 2621 2622 public void setInteracting(int barWindow, boolean interacting) { 2623 final boolean changing = ((mInteractingWindows & barWindow) != 0) != interacting; 2624 mInteractingWindows = interacting 2625 ? (mInteractingWindows | barWindow) 2626 : (mInteractingWindows & ~barWindow); 2627 if (mInteractingWindows != 0) { 2628 suspendAutohide(); 2629 } else { 2630 resumeSuspendedAutohide(); 2631 } 2632 // manually dismiss the volume panel when interacting with the nav bar 2633 if (changing && interacting && barWindow == StatusBarManager.WINDOW_NAVIGATION_BAR) { 2634 touchAutoDim(); 2635 dismissVolumeDialog(); 2636 } 2637 checkBarModes(); 2638 } 2639 2640 private void dismissVolumeDialog() { 2641 if (mVolumeComponent != null) { 2642 mVolumeComponent.dismissNow(); 2643 } 2644 } 2645 2646 private void resumeSuspendedAutohide() { 2647 if (mAutohideSuspended) { 2648 scheduleAutohide(); 2649 mHandler.postDelayed(mCheckBarModes, 500); // longer than home -> launcher 2650 } 2651 } 2652 2653 private void suspendAutohide() { 2654 mHandler.removeCallbacks(mAutohide); 2655 mHandler.removeCallbacks(mCheckBarModes); 2656 mAutohideSuspended = (mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0; 2657 } 2658 2659 private void cancelAutohide() { 2660 mAutohideSuspended = false; 2661 mHandler.removeCallbacks(mAutohide); 2662 } 2663 2664 private void scheduleAutohide() { 2665 cancelAutohide(); 2666 mHandler.postDelayed(mAutohide, AUTOHIDE_TIMEOUT_MS); 2667 } 2668 2669 public void touchAutoDim() { 2670 if (mNavigationBar != null) { 2671 mNavigationBar.getBarTransitions().setAutoDim(false); 2672 } 2673 mHandler.removeCallbacks(mAutoDim); 2674 if (mState != StatusBarState.KEYGUARD && mState != StatusBarState.SHADE_LOCKED) { 2675 mHandler.postDelayed(mAutoDim, AUTOHIDE_TIMEOUT_MS); 2676 } 2677 } 2678 2679 void checkUserAutohide(MotionEvent event) { 2680 if ((mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0 // a transient bar is revealed 2681 && event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar 2682 && event.getX() == 0 && event.getY() == 0 // a touch outside both bars 2683 && !mRemoteInputManager.getController() 2684 .isRemoteInputActive()) { // not due to typing in IME 2685 userAutohide(); 2686 } 2687 } 2688 2689 private void userAutohide() { 2690 cancelAutohide(); 2691 mHandler.postDelayed(mAutohide, 350); // longer than app gesture -> flag clear 2692 } 2693 2694 private boolean areLightsOn() { 2695 return 0 == (mSystemUiVisibility & View.SYSTEM_UI_FLAG_LOW_PROFILE); 2696 } 2697 2698 public void setLightsOn(boolean on) { 2699 Log.v(TAG, "setLightsOn(" + on + ")"); 2700 if (on) { 2701 setSystemUiVisibility(0, 0, 0, View.SYSTEM_UI_FLAG_LOW_PROFILE, 2702 mLastFullscreenStackBounds, mLastDockedStackBounds); 2703 } else { 2704 setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE, 0, 0, 2705 View.SYSTEM_UI_FLAG_LOW_PROFILE, mLastFullscreenStackBounds, 2706 mLastDockedStackBounds); 2707 } 2708 } 2709 2710 private void notifyUiVisibilityChanged(int vis) { 2711 try { 2712 if (mLastDispatchedSystemUiVisibility != vis) { 2713 mWindowManagerService.statusBarVisibilityChanged(vis); 2714 mLastDispatchedSystemUiVisibility = vis; 2715 } 2716 } catch (RemoteException ex) { 2717 } 2718 } 2719 2720 @Override 2721 public void topAppWindowChanged(boolean showMenu) { 2722 if (SPEW) { 2723 Log.d(TAG, (showMenu?"showing":"hiding") + " the MENU button"); 2724 } 2725 2726 // See above re: lights-out policy for legacy apps. 2727 if (showMenu) setLightsOn(true); 2728 } 2729 2730 public static String viewInfo(View v) { 2731 return "[(" + v.getLeft() + "," + v.getTop() + ")(" + v.getRight() + "," + v.getBottom() 2732 + ") " + v.getWidth() + "x" + v.getHeight() + "]"; 2733 } 2734 2735 @Override 2736 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2737 synchronized (mQueueLock) { 2738 pw.println("Current Status Bar state:"); 2739 pw.println(" mExpandedVisible=" + mExpandedVisible); 2740 pw.println(" mDisplayMetrics=" + mDisplayMetrics); 2741 pw.println(" mStackScroller: " + viewInfo(mStackScroller)); 2742 pw.println(" mStackScroller: " + viewInfo(mStackScroller) 2743 + " scroll " + mStackScroller.getScrollX() 2744 + "," + mStackScroller.getScrollY()); 2745 } 2746 2747 pw.print(" mInteractingWindows="); pw.println(mInteractingWindows); 2748 pw.print(" mStatusBarWindowState="); 2749 pw.println(windowStateToString(mStatusBarWindowState)); 2750 pw.print(" mStatusBarMode="); 2751 pw.println(BarTransitions.modeToString(mStatusBarMode)); 2752 pw.print(" mDozing="); pw.println(mDozing); 2753 pw.print(" mZenMode="); 2754 pw.println(Settings.Global.zenModeToString(Settings.Global.getInt( 2755 mContext.getContentResolver(), Settings.Global.ZEN_MODE, 2756 Settings.Global.ZEN_MODE_OFF))); 2757 2758 if (mStatusBarView != null) { 2759 dumpBarTransitions(pw, "mStatusBarView", mStatusBarView.getBarTransitions()); 2760 } 2761 pw.println(" StatusBarWindowView: "); 2762 if (mStatusBarWindow != null) { 2763 mStatusBarWindow.dump(fd, pw, args); 2764 } 2765 2766 pw.println(" mMediaManager: "); 2767 if (mMediaManager != null) { 2768 mMediaManager.dump(fd, pw, args); 2769 } 2770 2771 pw.println(" Panels: "); 2772 if (mNotificationPanel != null) { 2773 pw.println(" mNotificationPanel=" + 2774 mNotificationPanel + " params=" + mNotificationPanel.getLayoutParams().debug("")); 2775 pw.print (" "); 2776 mNotificationPanel.dump(fd, pw, args); 2777 } 2778 pw.println(" mStackScroller: "); 2779 if (mStackScroller != null) { 2780 pw.print (" "); 2781 mStackScroller.dump(fd, pw, args); 2782 } 2783 pw.println(" Theme:"); 2784 if (mOverlayManager == null) { 2785 pw.println(" overlay manager not initialized!"); 2786 } else { 2787 pw.println(" dark overlay on: " + isUsingDarkTheme()); 2788 } 2789 final boolean lightWpTheme = mContext.getThemeResId() == R.style.Theme_SystemUI_Light; 2790 pw.println(" light wallpaper theme: " + lightWpTheme); 2791 2792 DozeLog.dump(pw); 2793 2794 if (mFingerprintUnlockController != null) { 2795 mFingerprintUnlockController.dump(pw); 2796 } 2797 2798 if (mKeyguardIndicationController != null) { 2799 mKeyguardIndicationController.dump(fd, pw, args); 2800 } 2801 2802 if (mScrimController != null) { 2803 mScrimController.dump(fd, pw, args); 2804 } 2805 2806 if (mStatusBarKeyguardViewManager != null) { 2807 mStatusBarKeyguardViewManager.dump(pw); 2808 } 2809 2810 if (DUMPTRUCK) { 2811 synchronized (mEntryManager.getNotificationData()) { 2812 mEntryManager.getNotificationData().dump(pw, " "); 2813 } 2814 2815 if (false) { 2816 pw.println("see the logcat for a dump of the views we have created."); 2817 // must happen on ui thread 2818 mHandler.post(() -> { 2819 mStatusBarView.getLocationOnScreen(mAbsPos); 2820 Log.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1] + 2821 ") " + mStatusBarView.getWidth() + "x" + getStatusBarHeight()); 2822 mStatusBarView.debug(); 2823 }); 2824 } 2825 } 2826 2827 if (DEBUG_GESTURES) { 2828 pw.print(" status bar gestures: "); 2829 mGestureRec.dump(fd, pw, args); 2830 } 2831 2832 if (mHeadsUpManager != null) { 2833 mHeadsUpManager.dump(fd, pw, args); 2834 } else { 2835 pw.println(" mHeadsUpManager: null"); 2836 } 2837 if (mGroupManager != null) { 2838 mGroupManager.dump(fd, pw, args); 2839 } else { 2840 pw.println(" mGroupManager: null"); 2841 } 2842 2843 if (mLightBarController != null) { 2844 mLightBarController.dump(fd, pw, args); 2845 } 2846 2847 if (KeyguardUpdateMonitor.getInstance(mContext) != null) { 2848 KeyguardUpdateMonitor.getInstance(mContext).dump(fd, pw, args); 2849 } 2850 2851 FalsingManager.getInstance(mContext).dump(pw); 2852 FalsingLog.dump(pw); 2853 2854 pw.println("SharedPreferences:"); 2855 for (Map.Entry<String, ?> entry : Prefs.getAll(mContext).entrySet()) { 2856 pw.print(" "); pw.print(entry.getKey()); pw.print("="); pw.println(entry.getValue()); 2857 } 2858 } 2859 2860 static void dumpBarTransitions(PrintWriter pw, String var, BarTransitions transitions) { 2861 pw.print(" "); pw.print(var); pw.print(".BarTransitions.mMode="); 2862 pw.println(BarTransitions.modeToString(transitions.getMode())); 2863 } 2864 2865 public void createAndAddWindows() { 2866 addStatusBarWindow(); 2867 } 2868 2869 private void addStatusBarWindow() { 2870 makeStatusBarView(); 2871 mStatusBarWindowManager = Dependency.get(StatusBarWindowManager.class); 2872 mRemoteInputManager.setUpWithPresenter(this, mEntryManager, this, 2873 new RemoteInputController.Delegate() { 2874 public void setRemoteInputActive(NotificationData.Entry entry, 2875 boolean remoteInputActive) { 2876 mHeadsUpManager.setRemoteInputActive(entry, remoteInputActive); 2877 entry.row.notifyHeightChanged(true /* needsAnimation */); 2878 updateFooter(); 2879 } 2880 public void lockScrollTo(NotificationData.Entry entry) { 2881 mStackScroller.lockScrollTo(entry.row); 2882 } 2883 public void requestDisallowLongPressAndDismiss() { 2884 mStackScroller.requestDisallowLongPress(); 2885 mStackScroller.requestDisallowDismiss(); 2886 } 2887 }); 2888 mRemoteInputManager.getController().addCallback(mStatusBarWindowManager); 2889 mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight()); 2890 } 2891 2892 // called by makeStatusbar and also by PhoneStatusBarView 2893 void updateDisplaySize() { 2894 mDisplay.getMetrics(mDisplayMetrics); 2895 mDisplay.getSize(mCurrentDisplaySize); 2896 if (DEBUG_GESTURES) { 2897 mGestureRec.tag("display", 2898 String.format("%dx%d", mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels)); 2899 } 2900 } 2901 2902 float getDisplayDensity() { 2903 return mDisplayMetrics.density; 2904 } 2905 2906 float getDisplayWidth() { 2907 return mDisplayMetrics.widthPixels; 2908 } 2909 2910 float getDisplayHeight() { 2911 return mDisplayMetrics.heightPixels; 2912 } 2913 2914 int getRotation() { 2915 return mDisplay.getRotation(); 2916 } 2917 2918 public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned, 2919 boolean dismissShade, int flags) { 2920 startActivityDismissingKeyguard(intent, onlyProvisioned, dismissShade, 2921 false /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */, 2922 flags); 2923 } 2924 2925 public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned, 2926 boolean dismissShade) { 2927 startActivityDismissingKeyguard(intent, onlyProvisioned, dismissShade, 0); 2928 } 2929 2930 public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned, 2931 final boolean dismissShade, final boolean disallowEnterPictureInPictureWhileLaunching, 2932 final Callback callback, int flags) { 2933 if (onlyProvisioned && !isDeviceProvisioned()) return; 2934 2935 final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity( 2936 mContext, intent, mLockscreenUserManager.getCurrentUserId()); 2937 Runnable runnable = () -> { 2938 mAssistManager.hideAssist(); 2939 intent.setFlags( 2940 Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); 2941 intent.addFlags(flags); 2942 int result = ActivityManager.START_CANCELED; 2943 ActivityOptions options = new ActivityOptions(getActivityOptions( 2944 null /* remoteAnimation */)); 2945 options.setDisallowEnterPictureInPictureWhileLaunching( 2946 disallowEnterPictureInPictureWhileLaunching); 2947 if (intent == KeyguardBottomAreaView.INSECURE_CAMERA_INTENT) { 2948 // Normally an activity will set it's requested rotation 2949 // animation on its window. However when launching an activity 2950 // causes the orientation to change this is too late. In these cases 2951 // the default animation is used. This doesn't look good for 2952 // the camera (as it rotates the camera contents out of sync 2953 // with physical reality). So, we ask the WindowManager to 2954 // force the crossfade animation if an orientation change 2955 // happens to occur during the launch. 2956 options.setRotationAnimationHint( 2957 WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS); 2958 } 2959 try { 2960 result = ActivityManager.getService().startActivityAsUser( 2961 null, mContext.getBasePackageName(), 2962 intent, 2963 intent.resolveTypeIfNeeded(mContext.getContentResolver()), 2964 null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, 2965 options.toBundle(), UserHandle.CURRENT.getIdentifier()); 2966 } catch (RemoteException e) { 2967 Log.w(TAG, "Unable to start activity", e); 2968 } 2969 if (callback != null) { 2970 callback.onActivityStarted(result); 2971 } 2972 }; 2973 Runnable cancelRunnable = () -> { 2974 if (callback != null) { 2975 callback.onActivityStarted(ActivityManager.START_CANCELED); 2976 } 2977 }; 2978 executeRunnableDismissingKeyguard(runnable, cancelRunnable, dismissShade, 2979 afterKeyguardGone, true /* deferred */); 2980 } 2981 2982 public void readyForKeyguardDone() { 2983 mStatusBarKeyguardViewManager.readyForKeyguardDone(); 2984 } 2985 2986 public void executeRunnableDismissingKeyguard(final Runnable runnable, 2987 final Runnable cancelAction, 2988 final boolean dismissShade, 2989 final boolean afterKeyguardGone, 2990 final boolean deferred) { 2991 dismissKeyguardThenExecute(() -> { 2992 if (runnable != null) { 2993 if (mStatusBarKeyguardViewManager.isShowing() 2994 && mStatusBarKeyguardViewManager.isOccluded()) { 2995 mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(runnable); 2996 } else { 2997 AsyncTask.execute(runnable); 2998 } 2999 } 3000 if (dismissShade) { 3001 if (mExpandedVisible) { 3002 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */, 3003 true /* delayed*/); 3004 } else { 3005 3006 // Do it after DismissAction has been processed to conserve the needed ordering. 3007 mHandler.post(this::runPostCollapseRunnables); 3008 } 3009 } else if (isInLaunchTransition() && mNotificationPanel.isLaunchTransitionFinished()) { 3010 3011 // We are not dismissing the shade, but the launch transition is already finished, 3012 // so nobody will call readyForKeyguardDone anymore. Post it such that 3013 // keyguardDonePending gets called first. 3014 mHandler.post(mStatusBarKeyguardViewManager::readyForKeyguardDone); 3015 } 3016 return deferred; 3017 }, cancelAction, afterKeyguardGone); 3018 } 3019 3020 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 3021 @Override 3022 public void onReceive(Context context, Intent intent) { 3023 if (DEBUG) Log.v(TAG, "onReceive: " + intent); 3024 String action = intent.getAction(); 3025 if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) { 3026 KeyboardShortcuts.dismiss(); 3027 if (mRemoteInputManager.getController() != null) { 3028 mRemoteInputManager.getController().closeRemoteInputs(); 3029 } 3030 if (mLockscreenUserManager.isCurrentProfile(getSendingUserId())) { 3031 int flags = CommandQueue.FLAG_EXCLUDE_NONE; 3032 String reason = intent.getStringExtra("reason"); 3033 if (reason != null && reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) { 3034 flags |= CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL; 3035 } 3036 animateCollapsePanels(flags); 3037 } 3038 } 3039 else if (Intent.ACTION_SCREEN_OFF.equals(action)) { 3040 finishBarAnimations(); 3041 resetUserExpandedStates(); 3042 } 3043 else if (DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG.equals(action)) { 3044 mQSPanel.showDeviceMonitoringDialog(); 3045 } 3046 } 3047 }; 3048 3049 private final BroadcastReceiver mDemoReceiver = new BroadcastReceiver() { 3050 @Override 3051 public void onReceive(Context context, Intent intent) { 3052 if (DEBUG) Log.v(TAG, "onReceive: " + intent); 3053 String action = intent.getAction(); 3054 if (ACTION_DEMO.equals(action)) { 3055 Bundle bundle = intent.getExtras(); 3056 if (bundle != null) { 3057 String command = bundle.getString("command", "").trim().toLowerCase(); 3058 if (command.length() > 0) { 3059 try { 3060 dispatchDemoCommand(command, bundle); 3061 } catch (Throwable t) { 3062 Log.w(TAG, "Error running demo command, intent=" + intent, t); 3063 } 3064 } 3065 } 3066 } else if (ACTION_FAKE_ARTWORK.equals(action)) { 3067 if (DEBUG_MEDIA_FAKE_ARTWORK) { 3068 updateMediaMetaData(true, true); 3069 } 3070 } 3071 } 3072 }; 3073 3074 public void resetUserExpandedStates() { 3075 ArrayList<Entry> activeNotifications = mEntryManager.getNotificationData() 3076 .getActiveNotifications(); 3077 final int notificationCount = activeNotifications.size(); 3078 for (int i = 0; i < notificationCount; i++) { 3079 NotificationData.Entry entry = activeNotifications.get(i); 3080 if (entry.row != null) { 3081 entry.row.resetUserExpansion(); 3082 } 3083 } 3084 } 3085 3086 private void executeWhenUnlocked(OnDismissAction action) { 3087 if (mStatusBarKeyguardViewManager.isShowing()) { 3088 mLeaveOpenOnKeyguardHide = true; 3089 } 3090 dismissKeyguardThenExecute(action, null /* cancelAction */, false /* afterKeyguardGone */); 3091 } 3092 3093 protected void dismissKeyguardThenExecute(OnDismissAction action, boolean afterKeyguardGone) { 3094 dismissKeyguardThenExecute(action, null /* cancelRunnable */, afterKeyguardGone); 3095 } 3096 3097 private void dismissKeyguardThenExecute(OnDismissAction action, Runnable cancelAction, 3098 boolean afterKeyguardGone) { 3099 if (mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_ASLEEP 3100 && mUnlockMethodCache.canSkipBouncer() 3101 && !mLeaveOpenOnKeyguardHide 3102 && isPulsing()) { 3103 // Reuse the fingerprint wake-and-unlock transition if we dismiss keyguard from a pulse. 3104 // TODO: Factor this transition out of FingerprintUnlockController. 3105 mFingerprintUnlockController.startWakeAndUnlock( 3106 FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING); 3107 } 3108 if (mStatusBarKeyguardViewManager.isShowing()) { 3109 mStatusBarKeyguardViewManager.dismissWithAction(action, cancelAction, 3110 afterKeyguardGone); 3111 } else { 3112 action.onDismiss(); 3113 } 3114 } 3115 3116 // SystemUIService notifies SystemBars of configuration changes, which then calls down here 3117 @Override 3118 public void onConfigChanged(Configuration newConfig) { 3119 updateResources(); 3120 updateDisplaySize(); // populates mDisplayMetrics 3121 3122 if (DEBUG) { 3123 Log.v(TAG, "configuration changed: " + mContext.getResources().getConfiguration()); 3124 } 3125 3126 mViewHierarchyManager.updateRowStates(); 3127 mScreenPinningRequest.onConfigurationChanged(); 3128 } 3129 3130 @Override 3131 public void onUserSwitched(int newUserId) { 3132 // Begin old BaseStatusBar.userSwitched 3133 setHeadsUpUser(newUserId); 3134 // End old BaseStatusBar.userSwitched 3135 if (MULTIUSER_DEBUG) mNotificationPanelDebugText.setText("USER " + newUserId); 3136 animateCollapsePanels(); 3137 updatePublicMode(); 3138 mEntryManager.getNotificationData().filterAndSort(); 3139 if (mReinflateNotificationsOnUserSwitched) { 3140 mEntryManager.updateNotificationsOnDensityOrFontScaleChanged(); 3141 mReinflateNotificationsOnUserSwitched = false; 3142 } 3143 updateNotificationViews(); 3144 mMediaManager.clearCurrentMediaNotification(); 3145 setLockscreenUser(newUserId); 3146 } 3147 3148 @Override 3149 public NotificationLockscreenUserManager getNotificationLockscreenUserManager() { 3150 return mLockscreenUserManager; 3151 } 3152 3153 @Override 3154 public void onBindRow(Entry entry, PackageManager pmUser, 3155 StatusBarNotification sbn, ExpandableNotificationRow row) { 3156 row.setAboveShelfChangedListener(mAboveShelfObserver); 3157 row.setSecureStateProvider(this::isKeyguardCurrentlySecure); 3158 } 3159 3160 protected void setLockscreenUser(int newUserId) { 3161 mLockscreenWallpaper.setCurrentUser(newUserId); 3162 mScrimController.setCurrentUser(newUserId); 3163 updateMediaMetaData(true, false); 3164 } 3165 3166 /** 3167 * Reload some of our resources when the configuration changes. 3168 * 3169 * We don't reload everything when the configuration changes -- we probably 3170 * should, but getting that smooth is tough. Someday we'll fix that. In the 3171 * meantime, just update the things that we know change. 3172 */ 3173 void updateResources() { 3174 // Update the quick setting tiles 3175 if (mQSPanel != null) { 3176 mQSPanel.updateResources(); 3177 } 3178 3179 loadDimens(); 3180 3181 if (mStatusBarView != null) { 3182 mStatusBarView.updateResources(); 3183 } 3184 if (mNotificationPanel != null) { 3185 mNotificationPanel.updateResources(); 3186 } 3187 if (mBrightnessMirrorController != null) { 3188 mBrightnessMirrorController.updateResources(); 3189 } 3190 } 3191 3192 protected void loadDimens() { 3193 final Resources res = mContext.getResources(); 3194 3195 int oldBarHeight = mNaturalBarHeight; 3196 mNaturalBarHeight = res.getDimensionPixelSize( 3197 com.android.internal.R.dimen.status_bar_height); 3198 if (mStatusBarWindowManager != null && mNaturalBarHeight != oldBarHeight) { 3199 mStatusBarWindowManager.setBarHeight(mNaturalBarHeight); 3200 } 3201 mMaxAllowedKeyguardNotifications = res.getInteger( 3202 R.integer.keyguard_max_notification_count); 3203 3204 if (DEBUG) Log.v(TAG, "defineSlots"); 3205 } 3206 3207 // Visibility reporting 3208 3209 protected void handleVisibleToUserChanged(boolean visibleToUser) { 3210 if (visibleToUser) { 3211 handleVisibleToUserChangedImpl(visibleToUser); 3212 mNotificationLogger.startNotificationLogging(); 3213 } else { 3214 mNotificationLogger.stopNotificationLogging(); 3215 handleVisibleToUserChangedImpl(visibleToUser); 3216 } 3217 } 3218 3219 void handlePeekToExpandTransistion() { 3220 try { 3221 // consider the transition from peek to expanded to be a panel open, 3222 // but not one that clears notification effects. 3223 int notificationLoad = mEntryManager.getNotificationData() 3224 .getActiveNotifications().size(); 3225 mBarService.onPanelRevealed(false, notificationLoad); 3226 } catch (RemoteException ex) { 3227 // Won't fail unless the world has ended. 3228 } 3229 } 3230 3231 /** 3232 * The LEDs are turned off when the notification panel is shown, even just a little bit. 3233 * See also StatusBar.setPanelExpanded for another place where we attempt to do this. 3234 */ 3235 private void handleVisibleToUserChangedImpl(boolean visibleToUser) { 3236 if (visibleToUser) { 3237 boolean pinnedHeadsUp = mHeadsUpManager.hasPinnedHeadsUp(); 3238 boolean clearNotificationEffects = 3239 !isPresenterFullyCollapsed() && 3240 (mState == StatusBarState.SHADE 3241 || mState == StatusBarState.SHADE_LOCKED); 3242 int notificationLoad = mEntryManager.getNotificationData().getActiveNotifications() 3243 .size(); 3244 if (pinnedHeadsUp && isPresenterFullyCollapsed()) { 3245 notificationLoad = 1; 3246 } 3247 final int finalNotificationLoad = notificationLoad; 3248 mUiOffloadThread.submit(() -> { 3249 try { 3250 mBarService.onPanelRevealed(clearNotificationEffects, 3251 finalNotificationLoad); 3252 } catch (RemoteException ex) { 3253 // Won't fail unless the world has ended. 3254 } 3255 }); 3256 } else { 3257 mUiOffloadThread.submit(() -> { 3258 try { 3259 mBarService.onPanelHidden(); 3260 } catch (RemoteException ex) { 3261 // Won't fail unless the world has ended. 3262 } 3263 }); 3264 } 3265 3266 } 3267 3268 private void logStateToEventlog() { 3269 boolean isShowing = mStatusBarKeyguardViewManager.isShowing(); 3270 boolean isOccluded = mStatusBarKeyguardViewManager.isOccluded(); 3271 boolean isBouncerShowing = mStatusBarKeyguardViewManager.isBouncerShowing(); 3272 boolean isSecure = mUnlockMethodCache.isMethodSecure(); 3273 boolean canSkipBouncer = mUnlockMethodCache.canSkipBouncer(); 3274 int stateFingerprint = getLoggingFingerprint(mState, 3275 isShowing, 3276 isOccluded, 3277 isBouncerShowing, 3278 isSecure, 3279 canSkipBouncer); 3280 if (stateFingerprint != mLastLoggedStateFingerprint) { 3281 if (mStatusBarStateLog == null) { 3282 mStatusBarStateLog = new LogMaker(MetricsEvent.VIEW_UNKNOWN); 3283 } 3284 mMetricsLogger.write(mStatusBarStateLog 3285 .setCategory(isBouncerShowing ? MetricsEvent.BOUNCER : MetricsEvent.LOCKSCREEN) 3286 .setType(isShowing ? MetricsEvent.TYPE_OPEN : MetricsEvent.TYPE_CLOSE) 3287 .setSubtype(isSecure ? 1 : 0)); 3288 EventLogTags.writeSysuiStatusBarState(mState, 3289 isShowing ? 1 : 0, 3290 isOccluded ? 1 : 0, 3291 isBouncerShowing ? 1 : 0, 3292 isSecure ? 1 : 0, 3293 canSkipBouncer ? 1 : 0); 3294 mLastLoggedStateFingerprint = stateFingerprint; 3295 } 3296 } 3297 3298 /** 3299 * Returns a fingerprint of fields logged to eventlog 3300 */ 3301 private static int getLoggingFingerprint(int statusBarState, boolean keyguardShowing, 3302 boolean keyguardOccluded, boolean bouncerShowing, boolean secure, 3303 boolean currentlyInsecure) { 3304 // Reserve 8 bits for statusBarState. We'll never go higher than 3305 // that, right? Riiiight. 3306 return (statusBarState & 0xFF) 3307 | ((keyguardShowing ? 1 : 0) << 8) 3308 | ((keyguardOccluded ? 1 : 0) << 9) 3309 | ((bouncerShowing ? 1 : 0) << 10) 3310 | ((secure ? 1 : 0) << 11) 3311 | ((currentlyInsecure ? 1 : 0) << 12); 3312 } 3313 3314 // 3315 // tracing 3316 // 3317 3318 void postStartTracing() { 3319 mHandler.postDelayed(mStartTracing, 3000); 3320 } 3321 3322 void vibrate() { 3323 android.os.Vibrator vib = (android.os.Vibrator)mContext.getSystemService( 3324 Context.VIBRATOR_SERVICE); 3325 vib.vibrate(250, VIBRATION_ATTRIBUTES); 3326 } 3327 3328 final Runnable mStartTracing = new Runnable() { 3329 @Override 3330 public void run() { 3331 vibrate(); 3332 SystemClock.sleep(250); 3333 Log.d(TAG, "startTracing"); 3334 android.os.Debug.startMethodTracing("/data/statusbar-traces/trace"); 3335 mHandler.postDelayed(mStopTracing, 10000); 3336 } 3337 }; 3338 3339 final Runnable mStopTracing = () -> { 3340 android.os.Debug.stopMethodTracing(); 3341 Log.d(TAG, "stopTracing"); 3342 vibrate(); 3343 }; 3344 3345 @Override 3346 public void postQSRunnableDismissingKeyguard(final Runnable runnable) { 3347 mHandler.post(() -> { 3348 mLeaveOpenOnKeyguardHide = true; 3349 executeRunnableDismissingKeyguard(() -> mHandler.post(runnable), null, false, false, 3350 false); 3351 }); 3352 } 3353 3354 @Override 3355 public void postStartActivityDismissingKeyguard(final PendingIntent intent) { 3356 mHandler.post(() -> startPendingIntentDismissingKeyguard(intent)); 3357 } 3358 3359 @Override 3360 public void postStartActivityDismissingKeyguard(final Intent intent, int delay) { 3361 mHandler.postDelayed(() -> 3362 handleStartActivityDismissingKeyguard(intent, true /*onlyProvisioned*/), delay); 3363 } 3364 3365 private void handleStartActivityDismissingKeyguard(Intent intent, boolean onlyProvisioned) { 3366 startActivityDismissingKeyguard(intent, onlyProvisioned, true /* dismissShade */); 3367 } 3368 3369 public void destroy() { 3370 // Begin old BaseStatusBar.destroy(). 3371 mContext.unregisterReceiver(mBannerActionBroadcastReceiver); 3372 mLockscreenUserManager.destroy(); 3373 try { 3374 mNotificationListener.unregisterAsSystemService(); 3375 } catch (RemoteException e) { 3376 // Ignore. 3377 } 3378 mEntryManager.destroy(); 3379 // End old BaseStatusBar.destroy(). 3380 if (mStatusBarWindow != null) { 3381 mWindowManager.removeViewImmediate(mStatusBarWindow); 3382 mStatusBarWindow = null; 3383 } 3384 if (mNavigationBarView != null) { 3385 mWindowManager.removeViewImmediate(mNavigationBarView); 3386 mNavigationBarView = null; 3387 } 3388 mContext.unregisterReceiver(mBroadcastReceiver); 3389 mContext.unregisterReceiver(mDemoReceiver); 3390 mAssistManager.destroy(); 3391 3392 if (mQSPanel != null && mQSPanel.getHost() != null) { 3393 mQSPanel.getHost().destroy(); 3394 } 3395 Dependency.get(ActivityStarterDelegate.class).setActivityStarterImpl(null); 3396 mDeviceProvisionedController.removeCallback(mUserSetupObserver); 3397 Dependency.get(ConfigurationController.class).removeCallback(this); 3398 mZenController.removeCallback(this); 3399 mAppOpsListener.destroy(); 3400 } 3401 3402 private boolean mDemoModeAllowed; 3403 private boolean mDemoMode; 3404 3405 @Override 3406 public void dispatchDemoCommand(String command, Bundle args) { 3407 if (!mDemoModeAllowed) { 3408 mDemoModeAllowed = Settings.Global.getInt(mContext.getContentResolver(), 3409 DEMO_MODE_ALLOWED, 0) != 0; 3410 } 3411 if (!mDemoModeAllowed) return; 3412 if (command.equals(COMMAND_ENTER)) { 3413 mDemoMode = true; 3414 } else if (command.equals(COMMAND_EXIT)) { 3415 mDemoMode = false; 3416 checkBarModes(); 3417 } else if (!mDemoMode) { 3418 // automatically enter demo mode on first demo command 3419 dispatchDemoCommand(COMMAND_ENTER, new Bundle()); 3420 } 3421 boolean modeChange = command.equals(COMMAND_ENTER) || command.equals(COMMAND_EXIT); 3422 if ((modeChange || command.equals(COMMAND_VOLUME)) && mVolumeComponent != null) { 3423 mVolumeComponent.dispatchDemoCommand(command, args); 3424 } 3425 if (modeChange || command.equals(COMMAND_CLOCK)) { 3426 dispatchDemoCommandToView(command, args, R.id.clock); 3427 } 3428 if (modeChange || command.equals(COMMAND_BATTERY)) { 3429 mBatteryController.dispatchDemoCommand(command, args); 3430 } 3431 if (modeChange || command.equals(COMMAND_STATUS)) { 3432 ((StatusBarIconControllerImpl) mIconController).dispatchDemoCommand(command, args); 3433 } 3434 if (mNetworkController != null && (modeChange || command.equals(COMMAND_NETWORK))) { 3435 mNetworkController.dispatchDemoCommand(command, args); 3436 } 3437 if (modeChange || command.equals(COMMAND_NOTIFICATIONS)) { 3438 View notifications = mStatusBarView == null ? null 3439 : mStatusBarView.findViewById(R.id.notification_icon_area); 3440 if (notifications != null) { 3441 String visible = args.getString("visible"); 3442 int vis = mDemoMode && "false".equals(visible) ? View.INVISIBLE : View.VISIBLE; 3443 notifications.setVisibility(vis); 3444 } 3445 } 3446 if (command.equals(COMMAND_BARS)) { 3447 String mode = args.getString("mode"); 3448 int barMode = "opaque".equals(mode) ? MODE_OPAQUE : 3449 "translucent".equals(mode) ? MODE_TRANSLUCENT : 3450 "semi-transparent".equals(mode) ? MODE_SEMI_TRANSPARENT : 3451 "transparent".equals(mode) ? MODE_TRANSPARENT : 3452 "warning".equals(mode) ? MODE_WARNING : 3453 -1; 3454 if (barMode != -1) { 3455 boolean animate = true; 3456 if (mStatusBarView != null) { 3457 mStatusBarView.getBarTransitions().transitionTo(barMode, animate); 3458 } 3459 if (mNavigationBar != null) { 3460 mNavigationBar.getBarTransitions().transitionTo(barMode, animate); 3461 } 3462 } 3463 } 3464 if (modeChange || command.equals(COMMAND_OPERATOR)) { 3465 dispatchDemoCommandToView(command, args, R.id.operator_name); 3466 } 3467 } 3468 3469 private void dispatchDemoCommandToView(String command, Bundle args, int id) { 3470 if (mStatusBarView == null) return; 3471 View v = mStatusBarView.findViewById(id); 3472 if (v instanceof DemoMode) { 3473 ((DemoMode)v).dispatchDemoCommand(command, args); 3474 } 3475 } 3476 3477 /** 3478 * @return The {@link StatusBarState} the status bar is in. 3479 */ 3480 public int getBarState() { 3481 return mState; 3482 } 3483 3484 @Override 3485 public boolean isPresenterFullyCollapsed() { 3486 return mNotificationPanel.isFullyCollapsed(); 3487 } 3488 3489 public void showKeyguard() { 3490 mKeyguardRequested = true; 3491 mLeaveOpenOnKeyguardHide = false; 3492 mPendingRemoteInputView = null; 3493 updateIsKeyguard(); 3494 mAssistManager.onLockscreenShown(); 3495 } 3496 3497 public boolean hideKeyguard() { 3498 mKeyguardRequested = false; 3499 return updateIsKeyguard(); 3500 } 3501 3502 /** 3503 * @return True if StatusBar state is FULLSCREEN_USER_SWITCHER. 3504 */ 3505 public boolean isFullScreenUserSwitcherState() { 3506 return mState == StatusBarState.FULLSCREEN_USER_SWITCHER; 3507 } 3508 3509 private boolean updateIsKeyguard() { 3510 boolean wakeAndUnlocking = mFingerprintUnlockController.getMode() 3511 == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK; 3512 3513 // For dozing, keyguard needs to be shown whenever the device is non-interactive. Otherwise 3514 // there's no surface we can show to the user. Note that the device goes fully interactive 3515 // late in the transition, so we also allow the device to start dozing once the screen has 3516 // turned off fully. 3517 boolean keyguardForDozing = mDozingRequested && 3518 (!mDeviceInteractive || isGoingToSleep() && (isScreenFullyOff() || mIsKeyguard)); 3519 boolean shouldBeKeyguard = (mKeyguardRequested || keyguardForDozing) && !wakeAndUnlocking; 3520 if (keyguardForDozing) { 3521 updatePanelExpansionForKeyguard(); 3522 } 3523 if (shouldBeKeyguard) { 3524 if (isGoingToSleep() 3525 && mScreenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_TURNING_OFF) { 3526 // Delay showing the keyguard until screen turned off. 3527 } else { 3528 showKeyguardImpl(); 3529 } 3530 } else { 3531 return hideKeyguardImpl(); 3532 } 3533 return false; 3534 } 3535 3536 public void showKeyguardImpl() { 3537 mIsKeyguard = true; 3538 if (mLaunchTransitionFadingAway) { 3539 mNotificationPanel.animate().cancel(); 3540 onLaunchTransitionFadingEnded(); 3541 } 3542 mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT); 3543 if (mUserSwitcherController != null && mUserSwitcherController.useFullscreenUserSwitcher()) { 3544 setBarState(StatusBarState.FULLSCREEN_USER_SWITCHER); 3545 } else { 3546 setBarState(StatusBarState.KEYGUARD); 3547 } 3548 updateKeyguardState(false /* goingToFullShade */, false /* fromShadeLocked */); 3549 updatePanelExpansionForKeyguard(); 3550 if (mDraggedDownRow != null) { 3551 mDraggedDownRow.setUserLocked(false); 3552 mDraggedDownRow.notifyHeightChanged(false /* needsAnimation */); 3553 mDraggedDownRow = null; 3554 } 3555 } 3556 3557 private void updatePanelExpansionForKeyguard() { 3558 if (mState == StatusBarState.KEYGUARD && mFingerprintUnlockController.getMode() 3559 != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK) { 3560 instantExpandNotificationsPanel(); 3561 } else if (mState == StatusBarState.FULLSCREEN_USER_SWITCHER) { 3562 instantCollapseNotificationPanel(); 3563 } 3564 } 3565 3566 private void onLaunchTransitionFadingEnded() { 3567 mNotificationPanel.setAlpha(1.0f); 3568 mNotificationPanel.onAffordanceLaunchEnded(); 3569 releaseGestureWakeLock(); 3570 runLaunchTransitionEndRunnable(); 3571 mLaunchTransitionFadingAway = false; 3572 updateMediaMetaData(true /* metaDataChanged */, true); 3573 } 3574 3575 public boolean isCollapsing() { 3576 return mNotificationPanel.isCollapsing() || mActivityLaunchAnimator.isAnimationPending(); 3577 } 3578 3579 public void addPostCollapseAction(Runnable r) { 3580 mPostCollapseRunnables.add(r); 3581 } 3582 3583 public boolean isInLaunchTransition() { 3584 return mNotificationPanel.isLaunchTransitionRunning() 3585 || mNotificationPanel.isLaunchTransitionFinished(); 3586 } 3587 3588 /** 3589 * Fades the content of the keyguard away after the launch transition is done. 3590 * 3591 * @param beforeFading the runnable to be run when the circle is fully expanded and the fading 3592 * starts 3593 * @param endRunnable the runnable to be run when the transition is done 3594 */ 3595 public void fadeKeyguardAfterLaunchTransition(final Runnable beforeFading, 3596 Runnable endRunnable) { 3597 mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT); 3598 mLaunchTransitionEndRunnable = endRunnable; 3599 Runnable hideRunnable = () -> { 3600 mLaunchTransitionFadingAway = true; 3601 if (beforeFading != null) { 3602 beforeFading.run(); 3603 } 3604 updateScrimController(); 3605 updateMediaMetaData(false, true); 3606 mNotificationPanel.setAlpha(1); 3607 mStackScroller.setParentNotFullyVisible(true); 3608 mNotificationPanel.animate() 3609 .alpha(0) 3610 .setStartDelay(FADE_KEYGUARD_START_DELAY) 3611 .setDuration(FADE_KEYGUARD_DURATION) 3612 .withLayer() 3613 .withEndAction(this::onLaunchTransitionFadingEnded); 3614 mCommandQueue.appTransitionStarting(SystemClock.uptimeMillis(), 3615 LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true); 3616 }; 3617 if (mNotificationPanel.isLaunchTransitionRunning()) { 3618 mNotificationPanel.setLaunchTransitionEndRunnable(hideRunnable); 3619 } else { 3620 hideRunnable.run(); 3621 } 3622 } 3623 3624 /** 3625 * Fades the content of the Keyguard while we are dozing and makes it invisible when finished 3626 * fading. 3627 */ 3628 public void fadeKeyguardWhilePulsing() { 3629 mNotificationPanel.notifyStartFading(); 3630 mNotificationPanel.animate() 3631 .alpha(0f) 3632 .setStartDelay(0) 3633 .setDuration(FADE_KEYGUARD_DURATION_PULSING) 3634 .setInterpolator(Interpolators.ALPHA_OUT) 3635 .withEndAction(()-> { 3636 hideKeyguard(); 3637 mStatusBarKeyguardViewManager.onKeyguardFadedAway(); 3638 }).start(); 3639 } 3640 3641 /** 3642 * Plays the animation when an activity that was occluding Keyguard goes away. 3643 */ 3644 public void animateKeyguardUnoccluding() { 3645 mNotificationPanel.setExpandedFraction(0f); 3646 animateExpandNotificationsPanel(); 3647 } 3648 3649 /** 3650 * Starts the timeout when we try to start the affordances on Keyguard. We usually rely that 3651 * Keyguard goes away via fadeKeyguardAfterLaunchTransition, however, that might not happen 3652 * because the launched app crashed or something else went wrong. 3653 */ 3654 public void startLaunchTransitionTimeout() { 3655 mHandler.sendEmptyMessageDelayed(MSG_LAUNCH_TRANSITION_TIMEOUT, 3656 LAUNCH_TRANSITION_TIMEOUT_MS); 3657 } 3658 3659 private void onLaunchTransitionTimeout() { 3660 Log.w(TAG, "Launch transition: Timeout!"); 3661 mNotificationPanel.onAffordanceLaunchEnded(); 3662 releaseGestureWakeLock(); 3663 mNotificationPanel.resetViews(); 3664 } 3665 3666 private void runLaunchTransitionEndRunnable() { 3667 if (mLaunchTransitionEndRunnable != null) { 3668 Runnable r = mLaunchTransitionEndRunnable; 3669 3670 // mLaunchTransitionEndRunnable might call showKeyguard, which would execute it again, 3671 // which would lead to infinite recursion. Protect against it. 3672 mLaunchTransitionEndRunnable = null; 3673 r.run(); 3674 } 3675 } 3676 3677 /** 3678 * @return true if we would like to stay in the shade, false if it should go away entirely 3679 */ 3680 public boolean hideKeyguardImpl() { 3681 mIsKeyguard = false; 3682 Trace.beginSection("StatusBar#hideKeyguard"); 3683 boolean staying = mLeaveOpenOnKeyguardHide; 3684 setBarState(StatusBarState.SHADE); 3685 View viewToClick = null; 3686 if (mLeaveOpenOnKeyguardHide) { 3687 if (!mKeyguardRequested) { 3688 mLeaveOpenOnKeyguardHide = false; 3689 } 3690 long delay = calculateGoingToFullShadeDelay(); 3691 mNotificationPanel.animateToFullShade(delay); 3692 if (mDraggedDownRow != null) { 3693 mDraggedDownRow.setUserLocked(false); 3694 mDraggedDownRow = null; 3695 } 3696 if (!mKeyguardRequested) { 3697 viewToClick = mPendingRemoteInputView; 3698 mPendingRemoteInputView = null; 3699 } 3700 3701 // Disable layout transitions in navbar for this transition because the load is just 3702 // too heavy for the CPU and GPU on any device. 3703 if (mNavigationBar != null) { 3704 mNavigationBar.disableAnimationsDuringHide(delay); 3705 } 3706 } else if (!mNotificationPanel.isCollapsing()) { 3707 instantCollapseNotificationPanel(); 3708 } 3709 updateKeyguardState(staying, false /* fromShadeLocked */); 3710 3711 if (viewToClick != null && viewToClick.isAttachedToWindow()) { 3712 viewToClick.callOnClick(); 3713 } 3714 3715 // Keyguard state has changed, but QS is not listening anymore. Make sure to update the tile 3716 // visibilities so next time we open the panel we know the correct height already. 3717 if (mQSPanel != null) { 3718 mQSPanel.refreshAllTiles(); 3719 } 3720 mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT); 3721 releaseGestureWakeLock(); 3722 mNotificationPanel.onAffordanceLaunchEnded(); 3723 mNotificationPanel.animate().cancel(); 3724 mNotificationPanel.setAlpha(1f); 3725 Trace.endSection(); 3726 return staying; 3727 } 3728 3729 private void releaseGestureWakeLock() { 3730 if (mGestureWakeLock.isHeld()) { 3731 mGestureWakeLock.release(); 3732 } 3733 } 3734 3735 public long calculateGoingToFullShadeDelay() { 3736 return mKeyguardFadingAwayDelay + mKeyguardFadingAwayDuration; 3737 } 3738 3739 /** 3740 * Notifies the status bar that Keyguard is going away very soon. 3741 */ 3742 public void keyguardGoingAway() { 3743 3744 // Treat Keyguard exit animation as an app transition to achieve nice transition for status 3745 // bar. 3746 mKeyguardMonitor.notifyKeyguardGoingAway(true); 3747 mCommandQueue.appTransitionPending(true); 3748 } 3749 3750 /** 3751 * Notifies the status bar the Keyguard is fading away with the specified timings. 3752 * 3753 * @param startTime the start time of the animations in uptime millis 3754 * @param delay the precalculated animation delay in milliseconds 3755 * @param fadeoutDuration the duration of the exit animation, in milliseconds 3756 */ 3757 public void setKeyguardFadingAway(long startTime, long delay, long fadeoutDuration) { 3758 mKeyguardFadingAway = true; 3759 mKeyguardFadingAwayDelay = delay; 3760 mKeyguardFadingAwayDuration = fadeoutDuration; 3761 mCommandQueue.appTransitionStarting(startTime + fadeoutDuration 3762 - LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, 3763 LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true); 3764 recomputeDisableFlags(fadeoutDuration > 0 /* animate */); 3765 mCommandQueue.appTransitionStarting( 3766 startTime - LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, 3767 LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true); 3768 mKeyguardMonitor.notifyKeyguardFadingAway(delay, fadeoutDuration); 3769 } 3770 3771 public boolean isKeyguardFadingAway() { 3772 return mKeyguardFadingAway; 3773 } 3774 3775 /** 3776 * Notifies that the Keyguard fading away animation is done. 3777 */ 3778 public void finishKeyguardFadingAway() { 3779 mKeyguardFadingAway = false; 3780 mKeyguardMonitor.notifyKeyguardDoneFading(); 3781 mScrimController.setExpansionAffectsAlpha(true); 3782 } 3783 3784 // TODO: Move this to NotificationLockscreenUserManager. 3785 private void updatePublicMode() { 3786 final boolean showingKeyguard = mStatusBarKeyguardViewManager.isShowing(); 3787 final boolean devicePublic = showingKeyguard 3788 && mStatusBarKeyguardViewManager.isSecure( 3789 mLockscreenUserManager.getCurrentUserId()); 3790 3791 // Look for public mode users. Users are considered public in either case of: 3792 // - device keyguard is shown in secure mode; 3793 // - profile is locked with a work challenge. 3794 SparseArray<UserInfo> currentProfiles = mLockscreenUserManager.getCurrentProfiles(); 3795 for (int i = currentProfiles.size() - 1; i >= 0; i--) { 3796 final int userId = currentProfiles.valueAt(i).id; 3797 boolean isProfilePublic = devicePublic; 3798 if (!devicePublic && userId != mLockscreenUserManager.getCurrentUserId()) { 3799 // We can't rely on KeyguardManager#isDeviceLocked() for unified profile challenge 3800 // due to a race condition where this code could be called before 3801 // TrustManagerService updates its internal records, resulting in an incorrect 3802 // state being cached in mLockscreenPublicMode. (b/35951989) 3803 if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId) 3804 && mStatusBarKeyguardViewManager.isSecure(userId)) { 3805 isProfilePublic = mKeyguardManager.isDeviceLocked(userId); 3806 } 3807 } 3808 mLockscreenUserManager.setLockscreenPublicMode(isProfilePublic, userId); 3809 } 3810 } 3811 3812 protected void updateKeyguardState(boolean goingToFullShade, boolean fromShadeLocked) { 3813 Trace.beginSection("StatusBar#updateKeyguardState"); 3814 if (mState == StatusBarState.KEYGUARD) { 3815 mKeyguardIndicationController.setVisible(true); 3816 mNotificationPanel.resetViews(); 3817 if (mKeyguardUserSwitcher != null) { 3818 mKeyguardUserSwitcher.setKeyguard(true, fromShadeLocked); 3819 } 3820 if (mStatusBarView != null) mStatusBarView.removePendingHideExpandedRunnables(); 3821 if (mAmbientIndicationContainer != null) { 3822 mAmbientIndicationContainer.setVisibility(View.VISIBLE); 3823 } 3824 } else { 3825 mKeyguardIndicationController.setVisible(false); 3826 if (mKeyguardUserSwitcher != null) { 3827 mKeyguardUserSwitcher.setKeyguard(false, 3828 goingToFullShade || 3829 mState == StatusBarState.SHADE_LOCKED || 3830 fromShadeLocked); 3831 } 3832 if (mAmbientIndicationContainer != null) { 3833 mAmbientIndicationContainer.setVisibility(View.INVISIBLE); 3834 } 3835 } 3836 mNotificationPanel.setBarState(mState, mKeyguardFadingAway, goingToFullShade); 3837 updateTheme(); 3838 updateDozingState(); 3839 updatePublicMode(); 3840 updateStackScrollerState(goingToFullShade, fromShadeLocked); 3841 mEntryManager.updateNotifications(); 3842 checkBarModes(); 3843 updateScrimController(); 3844 updateMediaMetaData(false, mState != StatusBarState.KEYGUARD); 3845 mKeyguardMonitor.notifyKeyguardState(mStatusBarKeyguardViewManager.isShowing(), 3846 mUnlockMethodCache.isMethodSecure(), 3847 mStatusBarKeyguardViewManager.isOccluded()); 3848 Trace.endSection(); 3849 } 3850 3851 /** 3852 * Switches theme from light to dark and vice-versa. 3853 */ 3854 protected void updateTheme() { 3855 final boolean inflated = mStackScroller != null; 3856 3857 // The system wallpaper defines if QS should be light or dark. 3858 WallpaperColors systemColors = mColorExtractor 3859 .getWallpaperColors(WallpaperManager.FLAG_SYSTEM); 3860 final boolean useDarkTheme = systemColors != null 3861 && (systemColors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_THEME) != 0; 3862 if (isUsingDarkTheme() != useDarkTheme) { 3863 mUiOffloadThread.submit(() -> { 3864 try { 3865 mOverlayManager.setEnabled("com.android.systemui.theme.dark", 3866 useDarkTheme, mLockscreenUserManager.getCurrentUserId()); 3867 } catch (RemoteException e) { 3868 Log.w(TAG, "Can't change theme", e); 3869 } 3870 }); 3871 } 3872 3873 // Lock wallpaper defines the color of the majority of the views, hence we'll use it 3874 // to set our default theme. 3875 final boolean lockDarkText = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK, true 3876 /* ignoreVisibility */).supportsDarkText(); 3877 final int themeResId = lockDarkText ? R.style.Theme_SystemUI_Light : R.style.Theme_SystemUI; 3878 if (mContext.getThemeResId() != themeResId) { 3879 mContext.setTheme(themeResId); 3880 if (inflated) { 3881 onThemeChanged(); 3882 } 3883 } 3884 3885 if (inflated) { 3886 int which; 3887 if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) { 3888 which = WallpaperManager.FLAG_LOCK; 3889 } else { 3890 which = WallpaperManager.FLAG_SYSTEM; 3891 } 3892 final boolean useDarkText = mColorExtractor.getColors(which, 3893 true /* ignoreVisibility */).supportsDarkText(); 3894 mStackScroller.updateDecorViews(useDarkText); 3895 3896 // Make sure we have the correct navbar/statusbar colors. 3897 mStatusBarWindowManager.setKeyguardDark(useDarkText); 3898 } 3899 } 3900 3901 private void updateDozingState() { 3902 Trace.traceCounter(Trace.TRACE_TAG_APP, "dozing", mDozing ? 1 : 0); 3903 Trace.beginSection("StatusBar#updateDozingState"); 3904 3905 boolean sleepingFromKeyguard = 3906 mStatusBarKeyguardViewManager.isGoingToSleepVisibleNotOccluded(); 3907 boolean animate = (!mDozing && mDozeServiceHost.shouldAnimateWakeup()) 3908 || (mDozing && mDozeServiceHost.shouldAnimateScreenOff() && sleepingFromKeyguard); 3909 3910 mStackScroller.setDark(mDozing, animate, mWakeUpTouchLocation); 3911 mDozeScrimController.setDozing(mDozing); 3912 mKeyguardIndicationController.setDozing(mDozing); 3913 mNotificationPanel.setDozing(mDozing, animate); 3914 updateQsExpansionEnabled(); 3915 Trace.endSection(); 3916 } 3917 3918 public void updateStackScrollerState(boolean goingToFullShade, boolean fromShadeLocked) { 3919 if (mStackScroller == null) return; 3920 boolean onKeyguard = mState == StatusBarState.KEYGUARD; 3921 boolean publicMode = mLockscreenUserManager.isAnyProfilePublicMode(); 3922 if (mHeadsUpAppearanceController != null) { 3923 mHeadsUpAppearanceController.setPublicMode(publicMode); 3924 } 3925 mStackScroller.setHideSensitive(publicMode, goingToFullShade); 3926 mStackScroller.setDimmed(onKeyguard, fromShadeLocked /* animate */); 3927 mStackScroller.setExpandingEnabled(!onKeyguard); 3928 ActivatableNotificationView activatedChild = mStackScroller.getActivatedChild(); 3929 mStackScroller.setActivatedChild(null); 3930 if (activatedChild != null) { 3931 activatedChild.makeInactive(false /* animate */); 3932 } 3933 } 3934 3935 public void userActivity() { 3936 if (mState == StatusBarState.KEYGUARD) { 3937 mKeyguardViewMediatorCallback.userActivity(); 3938 } 3939 } 3940 3941 public boolean interceptMediaKey(KeyEvent event) { 3942 return mState == StatusBarState.KEYGUARD 3943 && mStatusBarKeyguardViewManager.interceptMediaKey(event); 3944 } 3945 3946 protected boolean shouldUnlockOnMenuPressed() { 3947 return mDeviceInteractive && mState != StatusBarState.SHADE 3948 && mStatusBarKeyguardViewManager.shouldDismissOnMenuPressed(); 3949 } 3950 3951 public boolean onMenuPressed() { 3952 if (shouldUnlockOnMenuPressed()) { 3953 animateCollapsePanels( 3954 CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL /* flags */, true /* force */); 3955 return true; 3956 } 3957 return false; 3958 } 3959 3960 public void endAffordanceLaunch() { 3961 releaseGestureWakeLock(); 3962 mNotificationPanel.onAffordanceLaunchEnded(); 3963 } 3964 3965 public boolean onBackPressed() { 3966 boolean isScrimmedBouncer = mScrimController.getState() == ScrimState.BOUNCER_SCRIMMED; 3967 if (mStatusBarKeyguardViewManager.onBackPressed(isScrimmedBouncer /* hideImmediately */)) { 3968 if (!isScrimmedBouncer) { 3969 mNotificationPanel.expandWithoutQs(); 3970 } 3971 return true; 3972 } 3973 if (mNotificationPanel.isQsExpanded()) { 3974 if (mNotificationPanel.isQsDetailShowing()) { 3975 mNotificationPanel.closeQsDetail(); 3976 } else { 3977 mNotificationPanel.animateCloseQs(); 3978 } 3979 return true; 3980 } 3981 if (mState != StatusBarState.KEYGUARD && mState != StatusBarState.SHADE_LOCKED) { 3982 animateCollapsePanels(); 3983 return true; 3984 } 3985 if (mKeyguardUserSwitcher != null && mKeyguardUserSwitcher.hideIfNotSimple(true)) { 3986 return true; 3987 } 3988 return false; 3989 } 3990 3991 public boolean onSpacePressed() { 3992 if (mDeviceInteractive && mState != StatusBarState.SHADE) { 3993 animateCollapsePanels( 3994 CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL /* flags */, true /* force */); 3995 return true; 3996 } 3997 return false; 3998 } 3999 4000 private void showBouncerIfKeyguard() { 4001 if ((mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) 4002 && !mKeyguardViewMediator.isHiding()) { 4003 showBouncer(true /* scrimmed */); 4004 } 4005 } 4006 4007 protected void showBouncer(boolean scrimmed) { 4008 mStatusBarKeyguardViewManager.showBouncer(scrimmed); 4009 } 4010 4011 private void instantExpandNotificationsPanel() { 4012 // Make our window larger and the panel expanded. 4013 makeExpandedVisible(true); 4014 mNotificationPanel.expand(false /* animate */); 4015 recomputeDisableFlags(false /* animate */); 4016 } 4017 4018 private void instantCollapseNotificationPanel() { 4019 mNotificationPanel.instantCollapse(); 4020 runPostCollapseRunnables(); 4021 } 4022 4023 @Override 4024 public void onActivated(ActivatableNotificationView view) { 4025 onActivated((View) view); 4026 mStackScroller.setActivatedChild(view); 4027 } 4028 4029 public void onActivated(View view) { 4030 mLockscreenGestureLogger.write( 4031 MetricsEvent.ACTION_LS_NOTE, 4032 0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */); 4033 mKeyguardIndicationController.showTransientIndication(R.string.notification_tap_again); 4034 ActivatableNotificationView previousView = mStackScroller.getActivatedChild(); 4035 if (previousView != null) { 4036 previousView.makeInactive(true /* animate */); 4037 } 4038 } 4039 4040 /** 4041 * @param state The {@link StatusBarState} to set. 4042 */ 4043 public void setBarState(int state) { 4044 // If we're visible and switched to SHADE_LOCKED (the user dragged 4045 // down on the lockscreen), clear notification LED, vibration, 4046 // ringing. 4047 // Other transitions are covered in handleVisibleToUserChanged(). 4048 if (state != mState && mVisible && (state == StatusBarState.SHADE_LOCKED 4049 || (state == StatusBarState.SHADE && isGoingToNotificationShade()))) { 4050 clearNotificationEffects(); 4051 } 4052 if (state == StatusBarState.KEYGUARD) { 4053 mRemoteInputManager.removeRemoteInputEntriesKeptUntilCollapsed(); 4054 maybeEscalateHeadsUp(); 4055 } 4056 mState = state; 4057 mGroupManager.setStatusBarState(state); 4058 mHeadsUpManager.setStatusBarState(state); 4059 mFalsingManager.setStatusBarState(state); 4060 mStatusBarWindowManager.setStatusBarState(state); 4061 mStackScroller.setStatusBarState(state); 4062 updateReportRejectedTouchVisibility(); 4063 updateDozing(); 4064 updateTheme(); 4065 touchAutoDim(); 4066 mNotificationShelf.setStatusBarState(state); 4067 } 4068 4069 @Override 4070 public void onActivationReset(ActivatableNotificationView view) { 4071 if (view == mStackScroller.getActivatedChild()) { 4072 mStackScroller.setActivatedChild(null); 4073 onActivationReset((View)view); 4074 } 4075 } 4076 4077 public void onActivationReset(View view) { 4078 mKeyguardIndicationController.hideTransientIndication(); 4079 } 4080 4081 public void onTrackingStarted() { 4082 runPostCollapseRunnables(); 4083 } 4084 4085 public void onClosingFinished() { 4086 runPostCollapseRunnables(); 4087 if (!isPresenterFullyCollapsed()) { 4088 // if we set it not to be focusable when collapsing, we have to undo it when we aborted 4089 // the closing 4090 mStatusBarWindowManager.setStatusBarFocusable(true); 4091 } 4092 } 4093 4094 public void onUnlockHintStarted() { 4095 mFalsingManager.onUnlockHintStarted(); 4096 mKeyguardIndicationController.showTransientIndication(R.string.keyguard_unlock); 4097 } 4098 4099 public void onHintFinished() { 4100 // Delay the reset a bit so the user can read the text. 4101 mKeyguardIndicationController.hideTransientIndicationDelayed(HINT_RESET_DELAY_MS); 4102 } 4103 4104 public void onCameraHintStarted() { 4105 mFalsingManager.onCameraHintStarted(); 4106 mKeyguardIndicationController.showTransientIndication(R.string.camera_hint); 4107 } 4108 4109 public void onVoiceAssistHintStarted() { 4110 mFalsingManager.onLeftAffordanceHintStarted(); 4111 mKeyguardIndicationController.showTransientIndication(R.string.voice_hint); 4112 } 4113 4114 public void onPhoneHintStarted() { 4115 mFalsingManager.onLeftAffordanceHintStarted(); 4116 mKeyguardIndicationController.showTransientIndication(R.string.phone_hint); 4117 } 4118 4119 public void onTrackingStopped(boolean expand) { 4120 if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) { 4121 if (!expand && !mUnlockMethodCache.canSkipBouncer()) { 4122 showBouncer(false /* scrimmed */); 4123 } 4124 } 4125 } 4126 4127 @Override 4128 public int getMaxNotificationsWhileLocked(boolean recompute) { 4129 if (recompute) { 4130 mMaxKeyguardNotifications = Math.max(1, 4131 mNotificationPanel.computeMaxKeyguardNotifications( 4132 mMaxAllowedKeyguardNotifications)); 4133 return mMaxKeyguardNotifications; 4134 } 4135 return mMaxKeyguardNotifications; 4136 } 4137 4138 public int getMaxNotificationsWhileLocked() { 4139 return getMaxNotificationsWhileLocked(false /* recompute */); 4140 } 4141 4142 // TODO: Figure out way to remove these. 4143 public NavigationBarView getNavigationBarView() { 4144 return (mNavigationBar != null ? (NavigationBarView) mNavigationBar.getView() : null); 4145 } 4146 4147 public View getNavigationBarWindow() { 4148 return mNavigationBarView; 4149 } 4150 4151 /** 4152 * TODO: Remove this method. Views should not be passed forward. Will cause theme issues. 4153 * @return bottom area view 4154 */ 4155 public KeyguardBottomAreaView getKeyguardBottomAreaView() { 4156 return mNotificationPanel.getKeyguardBottomAreaView(); 4157 } 4158 4159 // ---------------------- DragDownHelper.OnDragDownListener ------------------------------------ 4160 4161 4162 /* Only ever called as a consequence of a lockscreen expansion gesture. */ 4163 @Override 4164 public boolean onDraggedDown(View startingChild, int dragLengthY) { 4165 if (mState == StatusBarState.KEYGUARD 4166 && hasActiveNotifications() && (!isDozing() || isPulsing())) { 4167 mLockscreenGestureLogger.write( 4168 MetricsEvent.ACTION_LS_SHADE, 4169 (int) (dragLengthY / mDisplayMetrics.density), 4170 0 /* velocityDp - N/A */); 4171 4172 // We have notifications, go to locked shade. 4173 goToLockedShade(startingChild); 4174 if (startingChild instanceof ExpandableNotificationRow) { 4175 ExpandableNotificationRow row = (ExpandableNotificationRow) startingChild; 4176 row.onExpandedByGesture(true /* drag down is always an open */); 4177 } 4178 return true; 4179 } else { 4180 // abort gesture. 4181 return false; 4182 } 4183 } 4184 4185 @Override 4186 public void onDragDownReset() { 4187 mStackScroller.setDimmed(true /* dimmed */, true /* animated */); 4188 mStackScroller.resetScrollPosition(); 4189 mStackScroller.resetCheckSnoozeLeavebehind(); 4190 } 4191 4192 @Override 4193 public void onCrossedThreshold(boolean above) { 4194 mStackScroller.setDimmed(!above /* dimmed */, true /* animate */); 4195 } 4196 4197 @Override 4198 public void onTouchSlopExceeded() { 4199 mStackScroller.cancelLongPress(); 4200 mStackScroller.checkSnoozeLeavebehind(); 4201 } 4202 4203 @Override 4204 public void setEmptyDragAmount(float amount) { 4205 mNotificationPanel.setEmptyDragAmount(amount); 4206 } 4207 4208 @Override 4209 public boolean isFalsingCheckNeeded() { 4210 return mState == StatusBarState.KEYGUARD; 4211 } 4212 4213 /** 4214 * If secure with redaction: Show bouncer, go to unlocked shade. 4215 * 4216 * <p>If secure without redaction or no security: Go to {@link StatusBarState#SHADE_LOCKED}.</p> 4217 * 4218 * @param expandView The view to expand after going to the shade. 4219 */ 4220 public void goToLockedShade(View expandView) { 4221 if ((mDisabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0) { 4222 return; 4223 } 4224 4225 int userId = mLockscreenUserManager.getCurrentUserId(); 4226 ExpandableNotificationRow row = null; 4227 if (expandView instanceof ExpandableNotificationRow) { 4228 row = (ExpandableNotificationRow) expandView; 4229 row.setUserExpanded(true /* userExpanded */, true /* allowChildExpansion */); 4230 // Indicate that the group expansion is changing at this time -- this way the group 4231 // and children backgrounds / divider animations will look correct. 4232 row.setGroupExpansionChanging(true); 4233 if (row.getStatusBarNotification() != null) { 4234 userId = row.getStatusBarNotification().getUserId(); 4235 } 4236 } 4237 boolean fullShadeNeedsBouncer = !mLockscreenUserManager. 4238 userAllowsPrivateNotificationsInPublic(mLockscreenUserManager.getCurrentUserId()) 4239 || !mLockscreenUserManager.shouldShowLockscreenNotifications() 4240 || mFalsingManager.shouldEnforceBouncer(); 4241 if (mLockscreenUserManager.isLockscreenPublicMode(userId) && fullShadeNeedsBouncer) { 4242 mLeaveOpenOnKeyguardHide = true; 4243 showBouncerIfKeyguard(); 4244 mDraggedDownRow = row; 4245 mPendingRemoteInputView = null; 4246 } else { 4247 mNotificationPanel.animateToFullShade(0 /* delay */); 4248 setBarState(StatusBarState.SHADE_LOCKED); 4249 updateKeyguardState(false /* goingToFullShade */, false /* fromShadeLocked */); 4250 } 4251 } 4252 4253 public void onLockedNotificationImportanceChange(OnDismissAction dismissAction) { 4254 mLeaveOpenOnKeyguardHide = true; 4255 dismissKeyguardThenExecute(dismissAction, true /* afterKeyguardGone */); 4256 } 4257 4258 @Override 4259 public void onLockedRemoteInput(ExpandableNotificationRow row, View clicked) { 4260 mLeaveOpenOnKeyguardHide = true; 4261 showBouncer(true /* scrimmed */); 4262 mPendingRemoteInputView = clicked; 4263 } 4264 4265 @Override 4266 public void onMakeExpandedVisibleForRemoteInput(ExpandableNotificationRow row, 4267 View clickedView) { 4268 if (isKeyguardShowing()) { 4269 onLockedRemoteInput(row, clickedView); 4270 } else { 4271 row.setUserExpanded(true); 4272 row.getPrivateLayout().setOnExpandedVisibleListener(clickedView::performClick); 4273 } 4274 } 4275 4276 @Override 4277 public boolean shouldHandleRemoteInput(View view, PendingIntent pendingIntent) { 4278 // Skip remote input as doing so will expand the notification shade. 4279 return (mDisabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0; 4280 } 4281 4282 @Override 4283 public boolean handleRemoteViewClick(View view, PendingIntent pendingIntent, 4284 Intent fillInIntent, NotificationRemoteInputManager.ClickHandler defaultHandler) { 4285 final boolean isActivity = pendingIntent.isActivity(); 4286 if (isActivity) { 4287 final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity( 4288 mContext, pendingIntent.getIntent(), mLockscreenUserManager.getCurrentUserId()); 4289 dismissKeyguardThenExecute(() -> { 4290 try { 4291 ActivityManager.getService().resumeAppSwitches(); 4292 } catch (RemoteException e) { 4293 } 4294 4295 boolean handled = defaultHandler.handleClick(); 4296 4297 // close the shade if it was open 4298 if (handled && !mNotificationPanel.isFullyCollapsed()) { 4299 animateCollapsePanels( 4300 CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */); 4301 visibilityChanged(false); 4302 mAssistManager.hideAssist(); 4303 4304 // Wait for activity start. 4305 return true; 4306 } else { 4307 return false; 4308 } 4309 4310 }, afterKeyguardGone); 4311 return true; 4312 } else { 4313 return defaultHandler.handleClick(); 4314 } 4315 } 4316 4317 protected boolean startWorkChallengeIfNecessary(int userId, IntentSender intendSender, 4318 String notificationKey) { 4319 // Clear pending remote view, as we do not want to trigger pending remote input view when 4320 // it's called by other code 4321 mPendingWorkRemoteInputView = null; 4322 // Begin old BaseStatusBar.startWorkChallengeIfNecessary. 4323 final Intent newIntent = mKeyguardManager.createConfirmDeviceCredentialIntent(null, 4324 null, userId); 4325 if (newIntent == null) { 4326 return false; 4327 } 4328 final Intent callBackIntent = new Intent(NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION); 4329 callBackIntent.putExtra(Intent.EXTRA_INTENT, intendSender); 4330 callBackIntent.putExtra(Intent.EXTRA_INDEX, notificationKey); 4331 callBackIntent.setPackage(mContext.getPackageName()); 4332 4333 PendingIntent callBackPendingIntent = PendingIntent.getBroadcast( 4334 mContext, 4335 0, 4336 callBackIntent, 4337 PendingIntent.FLAG_CANCEL_CURRENT | 4338 PendingIntent.FLAG_ONE_SHOT | 4339 PendingIntent.FLAG_IMMUTABLE); 4340 newIntent.putExtra( 4341 Intent.EXTRA_INTENT, 4342 callBackPendingIntent.getIntentSender()); 4343 try { 4344 ActivityManager.getService().startConfirmDeviceCredentialIntent(newIntent, 4345 null /*options*/); 4346 } catch (RemoteException ex) { 4347 // ignore 4348 } 4349 return true; 4350 // End old BaseStatusBar.startWorkChallengeIfNecessary. 4351 } 4352 4353 @Override 4354 public void onLockedWorkRemoteInput(int userId, ExpandableNotificationRow row, 4355 View clicked) { 4356 // Collapse notification and show work challenge 4357 animateCollapsePanels(); 4358 startWorkChallengeIfNecessary(userId, null, null); 4359 // Add pending remote input view after starting work challenge, as starting work challenge 4360 // will clear all previous pending review view 4361 mPendingWorkRemoteInputView = clicked; 4362 } 4363 4364 @Override 4365 public void onWorkChallengeChanged() { 4366 updatePublicMode(); 4367 mEntryManager.updateNotifications(); 4368 if (mPendingWorkRemoteInputView != null 4369 && !mLockscreenUserManager.isAnyProfilePublicMode()) { 4370 // Expand notification panel and the notification row, then click on remote input view 4371 final Runnable clickPendingViewRunnable = () -> { 4372 final View pendingWorkRemoteInputView = mPendingWorkRemoteInputView; 4373 if (pendingWorkRemoteInputView == null) { 4374 return; 4375 } 4376 4377 // Climb up the hierarchy until we get to the container for this row. 4378 ViewParent p = pendingWorkRemoteInputView.getParent(); 4379 while (!(p instanceof ExpandableNotificationRow)) { 4380 if (p == null) { 4381 return; 4382 } 4383 p = p.getParent(); 4384 } 4385 4386 final ExpandableNotificationRow row = (ExpandableNotificationRow) p; 4387 ViewParent viewParent = row.getParent(); 4388 if (viewParent instanceof NotificationStackScrollLayout) { 4389 final NotificationStackScrollLayout scrollLayout = 4390 (NotificationStackScrollLayout) viewParent; 4391 row.makeActionsVisibile(); 4392 row.post(() -> { 4393 final Runnable finishScrollingCallback = () -> { 4394 mPendingWorkRemoteInputView.callOnClick(); 4395 mPendingWorkRemoteInputView = null; 4396 scrollLayout.setFinishScrollingCallback(null); 4397 }; 4398 if (scrollLayout.scrollTo(row)) { 4399 // It scrolls! So call it when it's finished. 4400 scrollLayout.setFinishScrollingCallback(finishScrollingCallback); 4401 } else { 4402 // It does not scroll, so call it now! 4403 finishScrollingCallback.run(); 4404 } 4405 }); 4406 } 4407 }; 4408 mNotificationPanel.getViewTreeObserver().addOnGlobalLayoutListener( 4409 new ViewTreeObserver.OnGlobalLayoutListener() { 4410 @Override 4411 public void onGlobalLayout() { 4412 if (mNotificationPanel.mStatusBar.getStatusBarWindow() 4413 .getHeight() != mNotificationPanel.mStatusBar 4414 .getStatusBarHeight()) { 4415 mNotificationPanel.getViewTreeObserver() 4416 .removeOnGlobalLayoutListener(this); 4417 mNotificationPanel.post(clickPendingViewRunnable); 4418 } 4419 } 4420 }); 4421 instantExpandNotificationsPanel(); 4422 } 4423 } 4424 4425 @Override 4426 public void onExpandClicked(Entry clickedEntry, boolean nowExpanded) { 4427 mHeadsUpManager.setExpanded(clickedEntry, nowExpanded); 4428 if (mState == StatusBarState.KEYGUARD && nowExpanded) { 4429 goToLockedShade(clickedEntry.row); 4430 } 4431 } 4432 4433 /** 4434 * Goes back to the keyguard after hanging around in {@link StatusBarState#SHADE_LOCKED}. 4435 */ 4436 public void goToKeyguard() { 4437 if (mState == StatusBarState.SHADE_LOCKED) { 4438 mStackScroller.onGoToKeyguard(); 4439 setBarState(StatusBarState.KEYGUARD); 4440 updateKeyguardState(false /* goingToFullShade */, true /* fromShadeLocked*/); 4441 } 4442 } 4443 4444 public long getKeyguardFadingAwayDelay() { 4445 return mKeyguardFadingAwayDelay; 4446 } 4447 4448 public long getKeyguardFadingAwayDuration() { 4449 return mKeyguardFadingAwayDuration; 4450 } 4451 4452 public void setBouncerShowing(boolean bouncerShowing) { 4453 mBouncerShowing = bouncerShowing; 4454 if (mStatusBarView != null) mStatusBarView.setBouncerShowing(bouncerShowing); 4455 updateHideIconsForBouncer(true /* animate */); 4456 recomputeDisableFlags(true /* animate */); 4457 updateScrimController(); 4458 } 4459 4460 public void cancelCurrentTouch() { 4461 if (mNotificationPanel.isTracking()) { 4462 mStatusBarWindow.cancelCurrentTouch(); 4463 if (mState == StatusBarState.SHADE) { 4464 animateCollapsePanels(); 4465 } 4466 } 4467 } 4468 4469 final WakefulnessLifecycle.Observer mWakefulnessObserver = new WakefulnessLifecycle.Observer() { 4470 @Override 4471 public void onFinishedGoingToSleep() { 4472 mNotificationPanel.onAffordanceLaunchEnded(); 4473 releaseGestureWakeLock(); 4474 mLaunchCameraOnScreenTurningOn = false; 4475 mDeviceInteractive = false; 4476 mWakeUpComingFromTouch = false; 4477 mWakeUpTouchLocation = null; 4478 mStackScroller.setAnimationsEnabled(false); 4479 mVisualStabilityManager.setScreenOn(false); 4480 updateVisibleToUser(); 4481 4482 // We need to disable touch events because these might 4483 // collapse the panel after we expanded it, and thus we would end up with a blank 4484 // Keyguard. 4485 mNotificationPanel.setTouchDisabled(true); 4486 mStatusBarWindow.cancelCurrentTouch(); 4487 if (mLaunchCameraOnFinishedGoingToSleep) { 4488 mLaunchCameraOnFinishedGoingToSleep = false; 4489 4490 // This gets executed before we will show Keyguard, so post it in order that the state 4491 // is correct. 4492 mHandler.post(() -> onCameraLaunchGestureDetected(mLastCameraLaunchSource)); 4493 } 4494 updateIsKeyguard(); 4495 } 4496 4497 @Override 4498 public void onStartedGoingToSleep() { 4499 notifyHeadsUpGoingToSleep(); 4500 dismissVolumeDialog(); 4501 } 4502 4503 @Override 4504 public void onStartedWakingUp() { 4505 mDeviceInteractive = true; 4506 mStackScroller.setAnimationsEnabled(true); 4507 mVisualStabilityManager.setScreenOn(true); 4508 mNotificationPanel.setTouchDisabled(false); 4509 mDozeServiceHost.stopDozing(); 4510 updateVisibleToUser(); 4511 updateIsKeyguard(); 4512 updateScrimController(); 4513 } 4514 }; 4515 4516 final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() { 4517 @Override 4518 public void onScreenTurningOn() { 4519 mFalsingManager.onScreenTurningOn(); 4520 mNotificationPanel.onScreenTurningOn(); 4521 4522 if (mLaunchCameraOnScreenTurningOn) { 4523 mNotificationPanel.launchCamera(false, mLastCameraLaunchSource); 4524 mLaunchCameraOnScreenTurningOn = false; 4525 } 4526 4527 updateScrimController(); 4528 } 4529 4530 @Override 4531 public void onScreenTurnedOn() { 4532 mScrimController.onScreenTurnedOn(); 4533 } 4534 4535 @Override 4536 public void onScreenTurnedOff() { 4537 mFalsingManager.onScreenOff(); 4538 mScrimController.onScreenTurnedOff(); 4539 // If we pulse in from AOD, we turn the screen off first. However, updatingIsKeyguard 4540 // in that case destroys the HeadsUpManager state, so don't do it in that case. 4541 if (!isPulsing()) { 4542 updateIsKeyguard(); 4543 } 4544 } 4545 }; 4546 4547 public int getWakefulnessState() { 4548 return mWakefulnessLifecycle.getWakefulness(); 4549 } 4550 4551 private void vibrateForCameraGesture() { 4552 // Make sure to pass -1 for repeat so VibratorService doesn't stop us when going to sleep. 4553 mVibrator.vibrate(mCameraLaunchGestureVibePattern, -1 /* repeat */); 4554 } 4555 4556 /** 4557 * @return true if the screen is currently fully off, i.e. has finished turning off and has 4558 * since not started turning on. 4559 */ 4560 public boolean isScreenFullyOff() { 4561 return mScreenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_OFF; 4562 } 4563 4564 @Override 4565 public void showScreenPinningRequest(int taskId) { 4566 if (mKeyguardMonitor.isShowing()) { 4567 // Don't allow apps to trigger this from keyguard. 4568 return; 4569 } 4570 // Show screen pinning request, since this comes from an app, show 'no thanks', button. 4571 showScreenPinningRequest(taskId, true); 4572 } 4573 4574 public void showScreenPinningRequest(int taskId, boolean allowCancel) { 4575 mScreenPinningRequest.showPrompt(taskId, allowCancel); 4576 } 4577 4578 public boolean hasActiveNotifications() { 4579 return !mEntryManager.getNotificationData().getActiveNotifications().isEmpty(); 4580 } 4581 4582 @Override 4583 public void wakeUpIfDozing(long time, View where) { 4584 if (mDozing) { 4585 PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 4586 pm.wakeUp(time, "com.android.systemui:NODOZE"); 4587 mWakeUpComingFromTouch = true; 4588 where.getLocationInWindow(mTmpInt2); 4589 mWakeUpTouchLocation = new PointF(mTmpInt2[0] + where.getWidth() / 2, 4590 mTmpInt2[1] + where.getHeight() / 2); 4591 mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested(); 4592 mFalsingManager.onScreenOnFromTouch(); 4593 } 4594 } 4595 4596 @Override 4597 public boolean isDeviceLocked(int userId) { 4598 return mKeyguardManager.isDeviceLocked(userId); 4599 } 4600 4601 @Override 4602 public void appTransitionCancelled() { 4603 EventBus.getDefault().send(new AppTransitionFinishedEvent()); 4604 } 4605 4606 @Override 4607 public void appTransitionFinished() { 4608 EventBus.getDefault().send(new AppTransitionFinishedEvent()); 4609 } 4610 4611 @Override 4612 public void onCameraLaunchGestureDetected(int source) { 4613 mLastCameraLaunchSource = source; 4614 if (isGoingToSleep()) { 4615 if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Finish going to sleep before launching camera"); 4616 mLaunchCameraOnFinishedGoingToSleep = true; 4617 return; 4618 } 4619 if (!mNotificationPanel.canCameraGestureBeLaunched( 4620 mStatusBarKeyguardViewManager.isShowing() && mExpandedVisible)) { 4621 if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Can't launch camera right now, mExpandedVisible: " + 4622 mExpandedVisible); 4623 return; 4624 } 4625 if (!mDeviceInteractive) { 4626 PowerManager pm = mContext.getSystemService(PowerManager.class); 4627 pm.wakeUp(SystemClock.uptimeMillis(), "com.android.systemui:CAMERA_GESTURE"); 4628 mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested(); 4629 } 4630 vibrateForCameraGesture(); 4631 if (!mStatusBarKeyguardViewManager.isShowing()) { 4632 startActivityDismissingKeyguard(KeyguardBottomAreaView.INSECURE_CAMERA_INTENT, 4633 false /* onlyProvisioned */, true /* dismissShade */, 4634 true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */, 0); 4635 } else { 4636 if (!mDeviceInteractive) { 4637 // Avoid flickering of the scrim when we instant launch the camera and the bouncer 4638 // comes on. 4639 mGestureWakeLock.acquire(LAUNCH_TRANSITION_TIMEOUT_MS + 1000L); 4640 } 4641 if (isScreenTurningOnOrOn()) { 4642 if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Launching camera"); 4643 if (mStatusBarKeyguardViewManager.isBouncerShowing()) { 4644 mStatusBarKeyguardViewManager.reset(true /* hide */); 4645 } 4646 mNotificationPanel.launchCamera(mDeviceInteractive /* animate */, source); 4647 updateScrimController(); 4648 } else { 4649 // We need to defer the camera launch until the screen comes on, since otherwise 4650 // we will dismiss us too early since we are waiting on an activity to be drawn and 4651 // incorrectly get notified because of the screen on event (which resumes and pauses 4652 // some activities) 4653 if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Deferring until screen turns on"); 4654 mLaunchCameraOnScreenTurningOn = true; 4655 } 4656 } 4657 } 4658 4659 boolean isCameraAllowedByAdmin() { 4660 if (mDevicePolicyManager.getCameraDisabled(null, 4661 mLockscreenUserManager.getCurrentUserId())) { 4662 return false; 4663 } else if (mStatusBarKeyguardViewManager == null || 4664 (isKeyguardShowing() && isKeyguardSecure())) { 4665 // Check if the admin has disabled the camera specifically for the keyguard 4666 return (mDevicePolicyManager. 4667 getKeyguardDisabledFeatures(null, mLockscreenUserManager.getCurrentUserId()) 4668 & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) == 0; 4669 } 4670 4671 return true; 4672 } 4673 4674 private boolean isGoingToSleep() { 4675 return mWakefulnessLifecycle.getWakefulness() 4676 == WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP; 4677 } 4678 4679 private boolean isScreenTurningOnOrOn() { 4680 return mScreenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_TURNING_ON 4681 || mScreenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_ON; 4682 } 4683 4684 public void notifyFpAuthModeChanged() { 4685 updateDozing(); 4686 updateScrimController(); 4687 } 4688 4689 private void updateDozing() { 4690 Trace.beginSection("StatusBar#updateDozing"); 4691 // When in wake-and-unlock while pulsing, keep dozing state until fully unlocked. 4692 boolean dozing = mDozingRequested && mState == StatusBarState.KEYGUARD 4693 || mFingerprintUnlockController.getMode() 4694 == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING; 4695 final boolean alwaysOn = DozeParameters.getInstance(mContext).getAlwaysOn(); 4696 // When in wake-and-unlock we may not have received a change to mState 4697 // but we still should not be dozing, manually set to false. 4698 if (mFingerprintUnlockController.getMode() == 4699 FingerprintUnlockController.MODE_WAKE_AND_UNLOCK) { 4700 dozing = false; 4701 } 4702 if (mDozing != dozing) { 4703 mDozing = dozing; 4704 mKeyguardViewMediator.setAodShowing(mDozing && alwaysOn); 4705 mStatusBarWindowManager.setDozing(mDozing); 4706 mStatusBarKeyguardViewManager.setDozing(mDozing); 4707 if (mAmbientIndicationContainer instanceof DozeReceiver) { 4708 ((DozeReceiver) mAmbientIndicationContainer).setDozing(mDozing); 4709 } 4710 mEntryManager.updateNotifications(); 4711 updateDozingState(); 4712 updateReportRejectedTouchVisibility(); 4713 } 4714 Trace.endSection(); 4715 } 4716 4717 @VisibleForTesting 4718 void updateScrimController() { 4719 Trace.beginSection("StatusBar#updateScrimController"); 4720 4721 // We don't want to end up in KEYGUARD state when we're unlocking with 4722 // fingerprint from doze. We should cross fade directly from black. 4723 boolean wakeAndUnlocking = mFingerprintUnlockController.isWakeAndUnlock(); 4724 4725 // Do not animate the scrim expansion when triggered by the fingerprint sensor. 4726 mScrimController.setExpansionAffectsAlpha( 4727 !mFingerprintUnlockController.isFingerprintUnlock()); 4728 4729 if (mBouncerShowing) { 4730 // Bouncer needs the front scrim when it's on top of an activity, 4731 // tapping on a notification, editing QS or being dismissed by 4732 // FLAG_DISMISS_KEYGUARD_ACTIVITY. 4733 ScrimState state = mIsOccluded || mStatusBarKeyguardViewManager.bouncerNeedsScrimming() 4734 || mStatusBarKeyguardViewManager.willDismissWithAction() 4735 || mStatusBarKeyguardViewManager.isFullscreenBouncer() ? 4736 ScrimState.BOUNCER_SCRIMMED : ScrimState.BOUNCER; 4737 mScrimController.transitionTo(state); 4738 } else if (mLaunchCameraOnScreenTurningOn || isInLaunchTransition()) { 4739 mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback); 4740 } else if (mBrightnessMirrorVisible) { 4741 mScrimController.transitionTo(ScrimState.BRIGHTNESS_MIRROR); 4742 } else if (isPulsing()) { 4743 // Handled in DozeScrimController#setPulsing 4744 } else if (mDozing) { 4745 mScrimController.transitionTo(ScrimState.AOD); 4746 } else if (mIsKeyguard && !wakeAndUnlocking) { 4747 mScrimController.transitionTo(ScrimState.KEYGUARD); 4748 } else { 4749 mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback); 4750 } 4751 Trace.endSection(); 4752 } 4753 4754 public boolean isKeyguardShowing() { 4755 if (mStatusBarKeyguardViewManager == null) { 4756 Slog.i(TAG, "isKeyguardShowing() called before startKeyguard(), returning true"); 4757 return true; 4758 } 4759 return mStatusBarKeyguardViewManager.isShowing(); 4760 } 4761 4762 private final class DozeServiceHost implements DozeHost { 4763 private final ArrayList<Callback> mCallbacks = new ArrayList<>(); 4764 private boolean mAnimateWakeup; 4765 private boolean mAnimateScreenOff; 4766 private boolean mIgnoreTouchWhilePulsing; 4767 4768 @Override 4769 public String toString() { 4770 return "PSB.DozeServiceHost[mCallbacks=" + mCallbacks.size() + "]"; 4771 } 4772 4773 public void firePowerSaveChanged(boolean active) { 4774 for (Callback callback : mCallbacks) { 4775 callback.onPowerSaveChanged(active); 4776 } 4777 } 4778 4779 public void fireNotificationHeadsUp() { 4780 for (Callback callback : mCallbacks) { 4781 callback.onNotificationHeadsUp(); 4782 } 4783 } 4784 4785 @Override 4786 public void addCallback(@NonNull Callback callback) { 4787 mCallbacks.add(callback); 4788 } 4789 4790 @Override 4791 public void removeCallback(@NonNull Callback callback) { 4792 mCallbacks.remove(callback); 4793 } 4794 4795 @Override 4796 public void startDozing() { 4797 if (!mDozingRequested) { 4798 mDozingRequested = true; 4799 DozeLog.traceDozing(mContext, mDozing); 4800 updateDozing(); 4801 updateIsKeyguard(); 4802 } 4803 } 4804 4805 @Override 4806 public void pulseWhileDozing(@NonNull PulseCallback callback, int reason) { 4807 if (reason == DozeLog.PULSE_REASON_SENSOR_LONG_PRESS) { 4808 mPowerManager.wakeUp(SystemClock.uptimeMillis(), "com.android.systemui:NODOZE"); 4809 startAssist(new Bundle()); 4810 return; 4811 } 4812 4813 mDozeScrimController.pulse(new PulseCallback() { 4814 @Override 4815 public void onPulseStarted() { 4816 callback.onPulseStarted(); 4817 if (mHeadsUpManager.hasHeadsUpNotifications()) { 4818 // Only pulse the stack scroller if there's actually something to show. 4819 // Otherwise just show the always-on screen. 4820 setPulsing(true); 4821 } 4822 } 4823 4824 @Override 4825 public void onPulseFinished() { 4826 callback.onPulseFinished(); 4827 setPulsing(false); 4828 } 4829 4830 private void setPulsing(boolean pulsing) { 4831 mNotificationPanel.setPulsing(pulsing); 4832 mVisualStabilityManager.setPulsing(pulsing); 4833 mIgnoreTouchWhilePulsing = false; 4834 } 4835 }, reason); 4836 } 4837 4838 @Override 4839 public void stopDozing() { 4840 if (mDozingRequested) { 4841 mDozingRequested = false; 4842 DozeLog.traceDozing(mContext, mDozing); 4843 mWakefulnessLifecycle.dispatchStartedWakingUp(); 4844 updateDozing(); 4845 } 4846 } 4847 4848 @Override 4849 public void onIgnoreTouchWhilePulsing(boolean ignore) { 4850 if (ignore != mIgnoreTouchWhilePulsing) { 4851 DozeLog.tracePulseTouchDisabledByProx(mContext, ignore); 4852 } 4853 mIgnoreTouchWhilePulsing = ignore; 4854 if (isDozing() && ignore) { 4855 mStatusBarWindow.cancelCurrentTouch(); 4856 } 4857 } 4858 4859 @Override 4860 public void dozeTimeTick() { 4861 mNotificationPanel.dozeTimeTick(); 4862 } 4863 4864 @Override 4865 public boolean isPowerSaveActive() { 4866 return mBatteryController.isAodPowerSave(); 4867 } 4868 4869 @Override 4870 public boolean isPulsingBlocked() { 4871 return mFingerprintUnlockController.getMode() 4872 == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK; 4873 } 4874 4875 @Override 4876 public boolean isProvisioned() { 4877 return mDeviceProvisionedController.isDeviceProvisioned() 4878 && mDeviceProvisionedController.isCurrentUserSetup(); 4879 } 4880 4881 @Override 4882 public boolean isBlockingDoze() { 4883 if (mFingerprintUnlockController.hasPendingAuthentication()) { 4884 Log.i(TAG, "Blocking AOD because fingerprint has authenticated"); 4885 return true; 4886 } 4887 return false; 4888 } 4889 4890 @Override 4891 public void startPendingIntentDismissingKeyguard(PendingIntent intent) { 4892 StatusBar.this.startPendingIntentDismissingKeyguard(intent); 4893 } 4894 4895 @Override 4896 public void extendPulse() { 4897 mDozeScrimController.extendPulse(); 4898 } 4899 4900 @Override 4901 public void setAnimateWakeup(boolean animateWakeup) { 4902 if (mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_AWAKE 4903 || mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_WAKING) { 4904 // Too late to change the wakeup animation. 4905 return; 4906 } 4907 mAnimateWakeup = animateWakeup; 4908 } 4909 4910 @Override 4911 public void setAnimateScreenOff(boolean animateScreenOff) { 4912 mAnimateScreenOff = animateScreenOff; 4913 } 4914 4915 @Override 4916 public void onDoubleTap(float screenX, float screenY) { 4917 if (screenX > 0 && screenY > 0 && mAmbientIndicationContainer != null 4918 && mAmbientIndicationContainer.getVisibility() == View.VISIBLE) { 4919 mAmbientIndicationContainer.getLocationOnScreen(mTmpInt2); 4920 float viewX = screenX - mTmpInt2[0]; 4921 float viewY = screenY - mTmpInt2[1]; 4922 if (0 <= viewX && viewX <= mAmbientIndicationContainer.getWidth() 4923 && 0 <= viewY && viewY <= mAmbientIndicationContainer.getHeight()) { 4924 dispatchDoubleTap(viewX, viewY); 4925 } 4926 } 4927 } 4928 4929 @Override 4930 public void setDozeScreenBrightness(int value) { 4931 mStatusBarWindowManager.setDozeScreenBrightness(value); 4932 } 4933 4934 @Override 4935 public void setAodDimmingScrim(float scrimOpacity) { 4936 mScrimController.setAodFrontScrimAlpha(scrimOpacity); 4937 } 4938 4939 public void dispatchDoubleTap(float viewX, float viewY) { 4940 dispatchTap(mAmbientIndicationContainer, viewX, viewY); 4941 dispatchTap(mAmbientIndicationContainer, viewX, viewY); 4942 } 4943 4944 private void dispatchTap(View view, float x, float y) { 4945 long now = SystemClock.elapsedRealtime(); 4946 dispatchTouchEvent(view, x, y, now, MotionEvent.ACTION_DOWN); 4947 dispatchTouchEvent(view, x, y, now, MotionEvent.ACTION_UP); 4948 } 4949 4950 private void dispatchTouchEvent(View view, float x, float y, long now, int action) { 4951 MotionEvent ev = MotionEvent.obtain(now, now, action, x, y, 0 /* meta */); 4952 view.dispatchTouchEvent(ev); 4953 ev.recycle(); 4954 } 4955 4956 private boolean shouldAnimateWakeup() { 4957 return mAnimateWakeup; 4958 } 4959 4960 public boolean shouldAnimateScreenOff() { 4961 return mAnimateScreenOff; 4962 } 4963 } 4964 4965 public boolean shouldIgnoreTouch() { 4966 return isDozing() && mDozeServiceHost.mIgnoreTouchWhilePulsing; 4967 } 4968 4969 // Begin Extra BaseStatusBar methods. 4970 4971 protected CommandQueue mCommandQueue; 4972 protected IStatusBarService mBarService; 4973 4974 // all notifications 4975 protected NotificationStackScrollLayout mStackScroller; 4976 4977 protected NotificationGroupManager mGroupManager; 4978 4979 4980 // for heads up notifications 4981 protected HeadsUpManagerPhone mHeadsUpManager; 4982 4983 private AboveShelfObserver mAboveShelfObserver; 4984 4985 // handling reordering 4986 protected VisualStabilityManager mVisualStabilityManager; 4987 4988 protected AccessibilityManager mAccessibilityManager; 4989 4990 protected boolean mDeviceInteractive; 4991 4992 protected boolean mVisible; 4993 4994 // mScreenOnFromKeyguard && mVisible. 4995 private boolean mVisibleToUser; 4996 4997 protected DevicePolicyManager mDevicePolicyManager; 4998 protected PowerManager mPowerManager; 4999 protected StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; 5000 5001 protected KeyguardManager mKeyguardManager; 5002 private LockPatternUtils mLockPatternUtils; 5003 private DeviceProvisionedController mDeviceProvisionedController 5004 = Dependency.get(DeviceProvisionedController.class); 5005 5006 // UI-specific methods 5007 5008 protected WindowManager mWindowManager; 5009 protected IWindowManager mWindowManagerService; 5010 5011 protected Display mDisplay; 5012 5013 protected RecentsComponent mRecents; 5014 5015 protected NotificationShelf mNotificationShelf; 5016 protected FooterView mFooterView; 5017 protected EmptyShadeView mEmptyShadeView; 5018 5019 protected AssistManager mAssistManager; 5020 5021 protected boolean mVrMode; 5022 5023 public boolean isDeviceInteractive() { 5024 return mDeviceInteractive; 5025 } 5026 5027 @Override // NotificationData.Environment 5028 public boolean isDeviceProvisioned() { 5029 return mDeviceProvisionedController.isDeviceProvisioned(); 5030 } 5031 5032 private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() { 5033 @Override 5034 public void onVrStateChanged(boolean enabled) { 5035 mVrMode = enabled; 5036 } 5037 }; 5038 5039 public boolean isDeviceInVrMode() { 5040 return mVrMode; 5041 } 5042 5043 private final BroadcastReceiver mBannerActionBroadcastReceiver = new BroadcastReceiver() { 5044 @Override 5045 public void onReceive(Context context, Intent intent) { 5046 String action = intent.getAction(); 5047 if (BANNER_ACTION_CANCEL.equals(action) || BANNER_ACTION_SETUP.equals(action)) { 5048 NotificationManager noMan = (NotificationManager) 5049 mContext.getSystemService(Context.NOTIFICATION_SERVICE); 5050 noMan.cancel(com.android.internal.messages.nano.SystemMessageProto.SystemMessage. 5051 NOTE_HIDDEN_NOTIFICATIONS); 5052 5053 Settings.Secure.putInt(mContext.getContentResolver(), 5054 Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0); 5055 if (BANNER_ACTION_SETUP.equals(action)) { 5056 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, 5057 true /* force */); 5058 mContext.startActivity(new Intent(Settings.ACTION_APP_NOTIFICATION_REDACTION) 5059 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 5060 5061 ); 5062 } 5063 } 5064 } 5065 }; 5066 5067 @Override 5068 public void onNotificationClicked(StatusBarNotification sbn, ExpandableNotificationRow row) { 5069 RemoteInputController controller = mRemoteInputManager.getController(); 5070 if (controller.isRemoteInputActive(row.getEntry()) 5071 && !TextUtils.isEmpty(row.getActiveRemoteInputText())) { 5072 // We have an active remote input typed and the user clicked on the notification. 5073 // this was probably unintentional, so we're closing the edit text instead. 5074 controller.closeRemoteInputs(); 5075 return; 5076 } 5077 Notification notification = sbn.getNotification(); 5078 final PendingIntent intent = notification.contentIntent != null 5079 ? notification.contentIntent 5080 : notification.fullScreenIntent; 5081 final String notificationKey = sbn.getKey(); 5082 5083 final boolean afterKeyguardGone = intent.isActivity() 5084 && PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(), 5085 mLockscreenUserManager.getCurrentUserId()); 5086 final boolean wasOccluded = mIsOccluded; 5087 dismissKeyguardThenExecute(() -> { 5088 // TODO: Some of this code may be able to move to NotificationEntryManager. 5089 if (mHeadsUpManager != null && mHeadsUpManager.isHeadsUp(notificationKey)) { 5090 // Release the HUN notification to the shade. 5091 5092 if (isPresenterFullyCollapsed()) { 5093 HeadsUpUtil.setIsClickedHeadsUpNotification(row, true); 5094 } 5095 // 5096 // In most cases, when FLAG_AUTO_CANCEL is set, the notification will 5097 // become canceled shortly by NoMan, but we can't assume that. 5098 mHeadsUpManager.releaseImmediately(notificationKey); 5099 } 5100 StatusBarNotification parentToCancel = null; 5101 if (shouldAutoCancel(sbn) && mGroupManager.isOnlyChildInGroup(sbn)) { 5102 StatusBarNotification summarySbn = 5103 mGroupManager.getLogicalGroupSummary(sbn).getStatusBarNotification(); 5104 if (shouldAutoCancel(summarySbn)) { 5105 parentToCancel = summarySbn; 5106 } 5107 } 5108 final StatusBarNotification parentToCancelFinal = parentToCancel; 5109 final Runnable runnable = () -> { 5110 try { 5111 // The intent we are sending is for the application, which 5112 // won't have permission to immediately start an activity after 5113 // the user switches to home. We know it is safe to do at this 5114 // point, so make sure new activity switches are now allowed. 5115 ActivityManager.getService().resumeAppSwitches(); 5116 } catch (RemoteException e) { 5117 } 5118 int launchResult = ActivityManager.START_CANCELED; 5119 if (intent != null) { 5120 // If we are launching a work activity and require to launch 5121 // separate work challenge, we defer the activity action and cancel 5122 // notification until work challenge is unlocked. 5123 if (intent.isActivity()) { 5124 final int userId = intent.getCreatorUserHandle().getIdentifier(); 5125 if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId) 5126 && mKeyguardManager.isDeviceLocked(userId)) { 5127 // TODO(b/28935539): should allow certain activities to 5128 // bypass work challenge 5129 if (startWorkChallengeIfNecessary(userId, intent.getIntentSender(), 5130 notificationKey)) { 5131 // Show work challenge, do not run PendingIntent and 5132 // remove notification 5133 collapseOnMainThread(); 5134 return; 5135 } 5136 } 5137 } 5138 Intent fillInIntent = null; 5139 Entry entry = row.getEntry(); 5140 CharSequence remoteInputText = null; 5141 if (!TextUtils.isEmpty(entry.remoteInputText)) { 5142 remoteInputText = entry.remoteInputText; 5143 } 5144 if (!TextUtils.isEmpty(remoteInputText) 5145 && !controller.isSpinning(entry.key)) { 5146 fillInIntent = new Intent().putExtra(Notification.EXTRA_REMOTE_INPUT_DRAFT, 5147 remoteInputText.toString()); 5148 } 5149 RemoteAnimationAdapter adapter = mActivityLaunchAnimator.getLaunchAnimation( 5150 row, wasOccluded); 5151 try { 5152 if (adapter != null) { 5153 ActivityManager.getService() 5154 .registerRemoteAnimationForNextActivityStart( 5155 intent.getCreatorPackage(), adapter); 5156 } 5157 launchResult = intent.sendAndReturnResult(mContext, 0, fillInIntent, null, 5158 null, null, getActivityOptions(adapter)); 5159 mActivityLaunchAnimator.setLaunchResult(launchResult); 5160 } catch (RemoteException | PendingIntent.CanceledException e) { 5161 // the stack trace isn't very helpful here. 5162 // Just log the exception message. 5163 Log.w(TAG, "Sending contentIntent failed: " + e); 5164 5165 // TODO: Dismiss Keyguard. 5166 } 5167 if (intent.isActivity()) { 5168 mAssistManager.hideAssist(); 5169 } 5170 } 5171 if (shouldCollapse()) { 5172 collapseOnMainThread(); 5173 } 5174 5175 final int count = 5176 mEntryManager.getNotificationData().getActiveNotifications().size(); 5177 final int rank = mEntryManager.getNotificationData().getRank(notificationKey); 5178 final NotificationVisibility nv = NotificationVisibility.obtain(notificationKey, 5179 rank, count, true); 5180 try { 5181 mBarService.onNotificationClick(notificationKey, nv); 5182 } catch (RemoteException ex) { 5183 // system process is dead if we're here. 5184 } 5185 if (parentToCancelFinal != null) { 5186 removeNotification(parentToCancelFinal); 5187 } 5188 if (shouldAutoCancel(sbn) 5189 || mEntryManager.isNotificationKeptForRemoteInput(notificationKey)) { 5190 // Automatically remove all notifications that we may have kept around longer 5191 removeNotification(sbn); 5192 } 5193 }; 5194 5195 if (mStatusBarKeyguardViewManager.isShowing() 5196 && mStatusBarKeyguardViewManager.isOccluded()) { 5197 mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(runnable); 5198 collapsePanel(true /* animate */); 5199 } else { 5200 new Thread(runnable).start(); 5201 } 5202 5203 return !mNotificationPanel.isFullyCollapsed(); 5204 }, afterKeyguardGone); 5205 } 5206 5207 private void collapseOnMainThread() { 5208 if (Looper.getMainLooper().isCurrentThread()) { 5209 collapsePanel(); 5210 } else { 5211 mStackScroller.post(this::collapsePanel); 5212 } 5213 } 5214 5215 private boolean shouldCollapse() { 5216 return mState != StatusBarState.SHADE || !mActivityLaunchAnimator.isAnimationPending(); 5217 } 5218 5219 public void collapsePanel(boolean animate) { 5220 if (animate) { 5221 collapsePanel(); 5222 } else if (!isPresenterFullyCollapsed()) { 5223 instantCollapseNotificationPanel(); 5224 visibilityChanged(false); 5225 } else { 5226 runPostCollapseRunnables(); 5227 } 5228 } 5229 5230 private boolean collapsePanel() { 5231 if (!mNotificationPanel.isFullyCollapsed()) { 5232 // close the shade if it was open 5233 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */, 5234 true /* delayed */); 5235 visibilityChanged(false); 5236 5237 return true; 5238 } else { 5239 return false; 5240 } 5241 } 5242 5243 private void removeNotification(StatusBarNotification notification) { 5244 // We have to post it to the UI thread for synchronization 5245 mHandler.post(() -> { 5246 Runnable removeRunnable = 5247 () -> mEntryManager.performRemoveNotification(notification); 5248 if (isCollapsing()) { 5249 // To avoid lags we're only performing the remove 5250 // after the shade was collapsed 5251 addPostCollapseAction(removeRunnable); 5252 } else { 5253 removeRunnable.run(); 5254 } 5255 }); 5256 } 5257 5258 protected NotificationListener mNotificationListener; 5259 5260 @Override // NotificationData.Environment 5261 public boolean isNotificationForCurrentProfiles(StatusBarNotification n) { 5262 final int notificationUserId = n.getUserId(); 5263 if (DEBUG && MULTIUSER_DEBUG) { 5264 Log.v(TAG, String.format("%s: current userid: %d, notification userid: %d", n, 5265 mLockscreenUserManager.getCurrentUserId(), notificationUserId)); 5266 } 5267 return mLockscreenUserManager.isCurrentProfile(notificationUserId); 5268 } 5269 5270 @Override 5271 public NotificationGroupManager getGroupManager() { 5272 return mGroupManager; 5273 } 5274 5275 @Override 5276 public void startNotificationGutsIntent(final Intent intent, final int appUid, 5277 ExpandableNotificationRow row) { 5278 dismissKeyguardThenExecute(() -> { 5279 AsyncTask.execute(() -> { 5280 int launchResult = TaskStackBuilder.create(mContext) 5281 .addNextIntentWithParentStack(intent) 5282 .startActivities(getActivityOptions( 5283 mActivityLaunchAnimator.getLaunchAnimation(row, mIsOccluded)), 5284 new UserHandle(UserHandle.getUserId(appUid))); 5285 mActivityLaunchAnimator.setLaunchResult(launchResult); 5286 if (shouldCollapse()) { 5287 // Putting it back on the main thread, since we're touching views 5288 mStatusBarWindow.post(() -> animateCollapsePanels( 5289 CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */)); 5290 } 5291 }); 5292 return true; 5293 }, false /* afterKeyguardGone */); 5294 } 5295 5296 public void setNotificationSnoozed(StatusBarNotification sbn, SnoozeOption snoozeOption) { 5297 if (snoozeOption.getSnoozeCriterion() != null) { 5298 mNotificationListener.snoozeNotification(sbn.getKey(), 5299 snoozeOption.getSnoozeCriterion().getId()); 5300 } else { 5301 mNotificationListener.snoozeNotification(sbn.getKey(), 5302 snoozeOption.getMinutesToSnoozeFor() * 60 * 1000); 5303 } 5304 } 5305 5306 @Override 5307 public void toggleSplitScreen() { 5308 toggleSplitScreenMode(-1 /* metricsDockAction */, -1 /* metricsUndockAction */); 5309 } 5310 5311 void awakenDreams() { 5312 SystemServicesProxy.getInstance(mContext).awakenDreamsAsync(); 5313 } 5314 5315 @Override 5316 public void preloadRecentApps() { 5317 int msg = MSG_PRELOAD_RECENT_APPS; 5318 mHandler.removeMessages(msg); 5319 mHandler.sendEmptyMessage(msg); 5320 } 5321 5322 @Override 5323 public void cancelPreloadRecentApps() { 5324 int msg = MSG_CANCEL_PRELOAD_RECENT_APPS; 5325 mHandler.removeMessages(msg); 5326 mHandler.sendEmptyMessage(msg); 5327 } 5328 5329 @Override 5330 public void dismissKeyboardShortcutsMenu() { 5331 int msg = MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU; 5332 mHandler.removeMessages(msg); 5333 mHandler.sendEmptyMessage(msg); 5334 } 5335 5336 @Override 5337 public void toggleKeyboardShortcutsMenu(int deviceId) { 5338 int msg = MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU; 5339 mHandler.removeMessages(msg); 5340 mHandler.obtainMessage(msg, deviceId, 0).sendToTarget(); 5341 } 5342 5343 @Override 5344 public void setTopAppHidesStatusBar(boolean topAppHidesStatusBar) { 5345 mTopHidesStatusBar = topAppHidesStatusBar; 5346 if (!topAppHidesStatusBar && mWereIconsJustHidden) { 5347 // Immediately update the icon hidden state, since that should only apply if we're 5348 // staying fullscreen. 5349 mWereIconsJustHidden = false; 5350 recomputeDisableFlags(true); 5351 } 5352 updateHideIconsForBouncer(true /* animate */); 5353 } 5354 5355 protected void toggleKeyboardShortcuts(int deviceId) { 5356 KeyboardShortcuts.toggle(mContext, deviceId); 5357 } 5358 5359 protected void dismissKeyboardShortcuts() { 5360 KeyboardShortcuts.dismiss(); 5361 } 5362 5363 @Override // NotificationData.Environment 5364 public boolean shouldHideNotifications(int userId) { 5365 return mLockscreenUserManager.shouldHideNotifications(userId); 5366 } 5367 5368 @Override // NotificationDate.Environment 5369 public boolean shouldHideNotifications(String key) { 5370 return mLockscreenUserManager.shouldHideNotifications(key); 5371 } 5372 5373 /** 5374 * Returns true if we're on a secure lockscreen. 5375 */ 5376 @Override // NotificationData.Environment 5377 public boolean isSecurelyLocked(int userId) { 5378 return mLockscreenUserManager.isLockscreenPublicMode(userId); 5379 } 5380 5381 /** 5382 * Called when the notification panel layouts 5383 */ 5384 public void onPanelLaidOut() { 5385 updateKeyguardMaxNotifications(); 5386 } 5387 5388 public void updateKeyguardMaxNotifications() { 5389 if (mState == StatusBarState.KEYGUARD) { 5390 // Since the number of notifications is determined based on the height of the view, we 5391 // need to update them. 5392 int maxBefore = getMaxNotificationsWhileLocked(false /* recompute */); 5393 int maxNotifications = getMaxNotificationsWhileLocked(true /* recompute */); 5394 if (maxBefore != maxNotifications) { 5395 mViewHierarchyManager.updateRowStates(); 5396 } 5397 } 5398 } 5399 5400 public void startPendingIntentDismissingKeyguard(final PendingIntent intent) { 5401 if (!isDeviceProvisioned()) return; 5402 5403 final boolean afterKeyguardGone = intent.isActivity() 5404 && PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(), 5405 mLockscreenUserManager.getCurrentUserId()); 5406 dismissKeyguardThenExecute(() -> { 5407 new Thread(() -> { 5408 try { 5409 // The intent we are sending is for the application, which 5410 // won't have permission to immediately start an activity after 5411 // the user switches to home. We know it is safe to do at this 5412 // point, so make sure new activity switches are now allowed. 5413 ActivityManager.getService().resumeAppSwitches(); 5414 } catch (RemoteException e) { 5415 } 5416 try { 5417 intent.send(null, 0, null, null, null, null, getActivityOptions( 5418 null /* animationAdapter */)); 5419 } catch (PendingIntent.CanceledException e) { 5420 // the stack trace isn't very helpful here. 5421 // Just log the exception message. 5422 Log.w(TAG, "Sending intent failed: " + e); 5423 5424 // TODO: Dismiss Keyguard. 5425 } 5426 if (intent.isActivity()) { 5427 mAssistManager.hideAssist(); 5428 } 5429 }).start(); 5430 5431 return collapsePanel(); 5432 }, afterKeyguardGone); 5433 } 5434 5435 private boolean shouldAutoCancel(StatusBarNotification sbn) { 5436 int flags = sbn.getNotification().flags; 5437 if ((flags & Notification.FLAG_AUTO_CANCEL) != Notification.FLAG_AUTO_CANCEL) { 5438 return false; 5439 } 5440 if ((flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) { 5441 return false; 5442 } 5443 return true; 5444 } 5445 5446 protected Bundle getActivityOptions(@Nullable RemoteAnimationAdapter animationAdapter) { 5447 ActivityOptions options; 5448 if (animationAdapter != null) { 5449 options = ActivityOptions.makeRemoteAnimation(animationAdapter); 5450 } else { 5451 options = ActivityOptions.makeBasic(); 5452 } 5453 // Anything launched from the notification shade should always go into the secondary 5454 // split-screen windowing mode. 5455 options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY); 5456 return options.toBundle(); 5457 } 5458 5459 protected void visibilityChanged(boolean visible) { 5460 if (mVisible != visible) { 5461 mVisible = visible; 5462 if (!visible) { 5463 mGutsManager.closeAndSaveGuts(true /* removeLeavebehind */, true /* force */, 5464 true /* removeControls */, -1 /* x */, -1 /* y */, true /* resetMenu */); 5465 } 5466 } 5467 updateVisibleToUser(); 5468 } 5469 5470 protected void updateVisibleToUser() { 5471 boolean oldVisibleToUser = mVisibleToUser; 5472 mVisibleToUser = mVisible && mDeviceInteractive; 5473 5474 if (oldVisibleToUser != mVisibleToUser) { 5475 handleVisibleToUserChanged(mVisibleToUser); 5476 } 5477 } 5478 5479 /** 5480 * Clear Buzz/Beep/Blink. 5481 */ 5482 public void clearNotificationEffects() { 5483 try { 5484 mBarService.clearNotificationEffects(); 5485 } catch (RemoteException e) { 5486 // Won't fail unless the world has ended. 5487 } 5488 } 5489 5490 /** 5491 * Updates expanded, dimmed and locked states of notification rows. 5492 */ 5493 @Override 5494 public void onUpdateRowStates() { 5495 // The following views will be moved to the end of mStackScroller. This counter represents 5496 // the offset from the last child. Initialized to 1 for the very last position. It is post- 5497 // incremented in the following "changeViewPosition" calls so that its value is correct for 5498 // subsequent calls. 5499 int offsetFromEnd = 1; 5500 if (mFooterView != null) { 5501 mStackScroller.changeViewPosition(mFooterView, 5502 mStackScroller.getChildCount() - offsetFromEnd++); 5503 } 5504 5505 mStackScroller.changeViewPosition(mEmptyShadeView, 5506 mStackScroller.getChildCount() - offsetFromEnd++); 5507 5508 // No post-increment for this call because it is the last one. Make sure to add one if 5509 // another "changeViewPosition" call is ever added. 5510 mStackScroller.changeViewPosition(mNotificationShelf, 5511 mStackScroller.getChildCount() - offsetFromEnd); 5512 5513 // Scrim opacity varies based on notification count 5514 mScrimController.setNotificationCount(mStackScroller.getNotGoneChildCount()); 5515 } 5516 5517 protected void notifyHeadsUpGoingToSleep() { 5518 maybeEscalateHeadsUp(); 5519 } 5520 5521 /** 5522 * @return Whether the security bouncer from Keyguard is showing. 5523 */ 5524 public boolean isBouncerShowing() { 5525 return mBouncerShowing; 5526 } 5527 5528 /** 5529 * @return a PackageManger for userId or if userId is < 0 (USER_ALL etc) then 5530 * return PackageManager for mContext 5531 */ 5532 public static PackageManager getPackageManagerForUser(Context context, int userId) { 5533 Context contextForUser = context; 5534 // UserHandle defines special userId as negative values, e.g. USER_ALL 5535 if (userId >= 0) { 5536 try { 5537 // Create a context for the correct user so if a package isn't installed 5538 // for user 0 we can still load information about the package. 5539 contextForUser = 5540 context.createPackageContextAsUser(context.getPackageName(), 5541 Context.CONTEXT_RESTRICTED, 5542 new UserHandle(userId)); 5543 } catch (NameNotFoundException e) { 5544 // Shouldn't fail to find the package name for system ui. 5545 } 5546 } 5547 return contextForUser.getPackageManager(); 5548 } 5549 5550 public boolean isKeyguardSecure() { 5551 if (mStatusBarKeyguardViewManager == null) { 5552 // startKeyguard() hasn't been called yet, so we don't know. 5553 // Make sure anything that needs to know isKeyguardSecure() checks and re-checks this 5554 // value onVisibilityChanged(). 5555 Slog.w(TAG, "isKeyguardSecure() called before startKeyguard(), returning false", 5556 new Throwable()); 5557 return false; 5558 } 5559 return mStatusBarKeyguardViewManager.isSecure(); 5560 } 5561 5562 @Override 5563 public void onZenChanged(int zen) { 5564 updateEmptyShadeView(); 5565 } 5566 5567 @Override 5568 public void showAssistDisclosure() { 5569 if (mAssistManager != null) { 5570 mAssistManager.showDisclosure(); 5571 } 5572 } 5573 5574 public NotificationPanelView getPanel() { 5575 return mNotificationPanel; 5576 } 5577 5578 @Override 5579 public void startAssist(Bundle args) { 5580 if (mAssistManager != null) { 5581 mAssistManager.startAssist(args); 5582 } 5583 } 5584 // End Extra BaseStatusBarMethods. 5585 5586 private final Runnable mAutoDim = () -> { 5587 if (mNavigationBar != null) { 5588 mNavigationBar.getBarTransitions().setAutoDim(true); 5589 } 5590 }; 5591 5592 public NotificationGutsManager getGutsManager() { 5593 return mGutsManager; 5594 } 5595 5596 @Override 5597 public boolean isPresenterLocked() { 5598 return mState == StatusBarState.KEYGUARD; 5599 } 5600 5601 @Override 5602 public Handler getHandler() { 5603 return mHandler; 5604 } 5605 5606 private final NotificationInfo.CheckSaveListener mCheckSaveListener = 5607 (Runnable saveImportance, StatusBarNotification sbn) -> { 5608 // If the user has security enabled, show challenge if the setting is changed. 5609 if (mLockscreenUserManager.isLockscreenPublicMode(sbn.getUser().getIdentifier()) 5610 && (mState == StatusBarState.KEYGUARD || 5611 mState == StatusBarState.SHADE_LOCKED)) { 5612 onLockedNotificationImportanceChange(() -> { 5613 saveImportance.run(); 5614 return true; 5615 }); 5616 } else { 5617 saveImportance.run(); 5618 } 5619 }; 5620 } 5621