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 23 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP; 24 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE; 25 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_WAKING; 26 import static com.android.systemui.statusbar.notification.NotificationInflater.InflationCallback; 27 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT; 28 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT; 29 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE; 30 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT; 31 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSLUCENT; 32 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT; 33 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_WARNING; 34 35 import android.animation.Animator; 36 import android.animation.AnimatorListenerAdapter; 37 import android.annotation.NonNull; 38 import android.annotation.Nullable; 39 import android.app.ActivityManager; 40 import android.app.ActivityManager.StackId; 41 import android.app.ActivityOptions; 42 import android.app.INotificationManager; 43 import android.app.KeyguardManager; 44 import android.app.Notification; 45 import android.app.NotificationChannel; 46 import android.app.NotificationManager; 47 import android.app.PendingIntent; 48 import android.app.RemoteInput; 49 import android.app.StatusBarManager; 50 import android.app.TaskStackBuilder; 51 import android.app.WallpaperColors; 52 import android.app.WallpaperManager; 53 import android.app.admin.DevicePolicyManager; 54 import android.content.BroadcastReceiver; 55 import android.content.ComponentCallbacks2; 56 import android.content.ComponentName; 57 import android.content.Context; 58 import android.content.Intent; 59 import android.content.IntentFilter; 60 import android.content.IntentSender; 61 import android.content.om.IOverlayManager; 62 import android.content.om.OverlayInfo; 63 import android.content.pm.ApplicationInfo; 64 import android.content.pm.IPackageManager; 65 import android.content.pm.PackageManager; 66 import android.content.pm.PackageManager.NameNotFoundException; 67 import android.content.pm.UserInfo; 68 import android.content.res.Configuration; 69 import android.content.res.Resources; 70 import android.database.ContentObserver; 71 import android.graphics.Bitmap; 72 import android.graphics.Canvas; 73 import android.graphics.ColorFilter; 74 import android.graphics.PixelFormat; 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.media.session.MediaController; 86 import android.media.session.MediaSession; 87 import android.media.session.MediaSessionManager; 88 import android.media.session.PlaybackState; 89 import android.metrics.LogMaker; 90 import android.net.Uri; 91 import android.os.AsyncTask; 92 import android.os.Build; 93 import android.os.Bundle; 94 import android.os.Handler; 95 import android.os.IBinder; 96 import android.os.Message; 97 import android.os.PowerManager; 98 import android.os.RemoteException; 99 import android.os.ServiceManager; 100 import android.os.SystemClock; 101 import android.os.SystemProperties; 102 import android.os.Trace; 103 import android.os.UserHandle; 104 import android.os.UserManager; 105 import android.os.Vibrator; 106 import android.provider.Settings; 107 import android.service.notification.NotificationListenerService.RankingMap; 108 import android.service.notification.StatusBarNotification; 109 import android.service.vr.IVrManager; 110 import android.service.vr.IVrStateCallbacks; 111 import android.text.TextUtils; 112 import android.util.ArraySet; 113 import android.util.DisplayMetrics; 114 import android.util.EventLog; 115 import android.util.Log; 116 import android.util.Slog; 117 import android.util.SparseArray; 118 import android.util.SparseBooleanArray; 119 import android.view.Display; 120 import android.view.HapticFeedbackConstants; 121 import android.view.IWindowManager; 122 import android.view.KeyEvent; 123 import android.view.LayoutInflater; 124 import android.view.MotionEvent; 125 import android.view.ThreadedRenderer; 126 import android.view.View; 127 import android.view.ViewAnimationUtils; 128 import android.view.ViewGroup; 129 import android.view.ViewParent; 130 import android.view.ViewStub; 131 import android.view.ViewTreeObserver; 132 import android.view.WindowManager; 133 import android.view.WindowManagerGlobal; 134 import android.view.accessibility.AccessibilityManager; 135 import android.view.animation.AccelerateInterpolator; 136 import android.view.animation.Interpolator; 137 import android.widget.DateTimeView; 138 import android.widget.ImageView; 139 import android.widget.RemoteViews; 140 import android.widget.TextView; 141 import android.widget.Toast; 142 143 import com.android.internal.annotations.VisibleForTesting; 144 import com.android.internal.colorextraction.ColorExtractor; 145 import com.android.internal.logging.MetricsLogger; 146 import com.android.internal.logging.nano.MetricsProto.MetricsEvent; 147 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; 148 import com.android.internal.statusbar.IStatusBarService; 149 import com.android.internal.statusbar.NotificationVisibility; 150 import com.android.internal.statusbar.StatusBarIcon; 151 import com.android.internal.util.NotificationMessagingUtil; 152 import com.android.internal.widget.LockPatternUtils; 153 import com.android.keyguard.KeyguardHostView.OnDismissAction; 154 import com.android.keyguard.KeyguardUpdateMonitor; 155 import com.android.keyguard.KeyguardUpdateMonitorCallback; 156 import com.android.keyguard.ViewMediatorCallback; 157 import com.android.systemui.ActivityStarterDelegate; 158 import com.android.systemui.AutoReinflateContainer; 159 import com.android.systemui.DejankUtils; 160 import com.android.systemui.DemoMode; 161 import com.android.systemui.Dependency; 162 import com.android.systemui.EventLogTags; 163 import com.android.systemui.ForegroundServiceController; 164 import com.android.systemui.Interpolators; 165 import com.android.systemui.Prefs; 166 import com.android.systemui.R; 167 import com.android.systemui.RecentsComponent; 168 import com.android.systemui.SwipeHelper; 169 import com.android.systemui.SystemUI; 170 import com.android.systemui.SystemUIFactory; 171 import com.android.systemui.UiOffloadThread; 172 import com.android.systemui.assist.AssistManager; 173 import com.android.systemui.classifier.FalsingLog; 174 import com.android.systemui.classifier.FalsingManager; 175 import com.android.systemui.colorextraction.SysuiColorExtractor; 176 import com.android.systemui.doze.DozeHost; 177 import com.android.systemui.doze.DozeLog; 178 import com.android.systemui.doze.DozeReceiver; 179 import com.android.systemui.fragments.ExtensionFragmentListener; 180 import com.android.systemui.fragments.FragmentHostManager; 181 import com.android.systemui.keyguard.KeyguardViewMediator; 182 import com.android.systemui.keyguard.ScreenLifecycle; 183 import com.android.systemui.keyguard.WakefulnessLifecycle; 184 import com.android.systemui.plugins.ActivityStarter; 185 import com.android.systemui.plugins.qs.QS; 186 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem; 187 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption; 188 import com.android.systemui.qs.QSFragment; 189 import com.android.systemui.qs.QSPanel; 190 import com.android.systemui.qs.QSTileHost; 191 import com.android.systemui.qs.car.CarQSFragment; 192 import com.android.systemui.recents.Recents; 193 import com.android.systemui.recents.ScreenPinningRequest; 194 import com.android.systemui.recents.events.EventBus; 195 import com.android.systemui.recents.events.activity.AppTransitionFinishedEvent; 196 import com.android.systemui.recents.events.activity.UndockingTaskEvent; 197 import com.android.systemui.recents.misc.SystemServicesProxy; 198 import com.android.systemui.stackdivider.Divider; 199 import com.android.systemui.stackdivider.WindowManagerProxy; 200 import com.android.systemui.statusbar.ActivatableNotificationView; 201 import com.android.systemui.statusbar.BackDropView; 202 import com.android.systemui.statusbar.CommandQueue; 203 import com.android.systemui.statusbar.DismissView; 204 import com.android.systemui.statusbar.DragDownHelper; 205 import com.android.systemui.statusbar.EmptyShadeView; 206 import com.android.systemui.statusbar.ExpandableNotificationRow; 207 import com.android.systemui.statusbar.GestureRecorder; 208 import com.android.systemui.statusbar.KeyboardShortcuts; 209 import com.android.systemui.statusbar.KeyguardIndicationController; 210 import com.android.systemui.statusbar.NotificationData; 211 import com.android.systemui.statusbar.NotificationData.Entry; 212 import com.android.systemui.statusbar.NotificationGuts; 213 import com.android.systemui.statusbar.NotificationInfo; 214 import com.android.systemui.statusbar.NotificationShelf; 215 import com.android.systemui.statusbar.NotificationSnooze; 216 import com.android.systemui.statusbar.RemoteInputController; 217 import com.android.systemui.statusbar.ScrimView; 218 import com.android.systemui.statusbar.SignalClusterView; 219 import com.android.systemui.statusbar.StatusBarState; 220 import com.android.systemui.statusbar.notification.AboveShelfObserver; 221 import com.android.systemui.statusbar.notification.InflationException; 222 import com.android.systemui.statusbar.notification.RowInflaterTask; 223 import com.android.systemui.statusbar.notification.VisualStabilityManager; 224 import com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChangedListener; 225 import com.android.systemui.statusbar.policy.BatteryController; 226 import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback; 227 import com.android.systemui.statusbar.policy.BrightnessMirrorController; 228 import com.android.systemui.statusbar.policy.ConfigurationController; 229 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener; 230 import com.android.systemui.statusbar.policy.DarkIconDispatcher; 231 import com.android.systemui.statusbar.policy.DeviceProvisionedController; 232 import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener; 233 import com.android.systemui.statusbar.policy.ExtensionController; 234 import com.android.systemui.statusbar.policy.HeadsUpManager; 235 import com.android.systemui.statusbar.policy.KeyguardMonitor; 236 import com.android.systemui.statusbar.policy.KeyguardMonitorImpl; 237 import com.android.systemui.statusbar.policy.KeyguardUserSwitcher; 238 import com.android.systemui.statusbar.policy.NetworkController; 239 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; 240 import com.android.systemui.statusbar.policy.PreviewInflater; 241 import com.android.systemui.statusbar.policy.RemoteInputView; 242 import com.android.systemui.statusbar.policy.UserInfoController; 243 import com.android.systemui.statusbar.policy.UserInfoControllerImpl; 244 import com.android.systemui.statusbar.policy.UserSwitcherController; 245 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout; 246 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout 247 .OnChildLocationsChangedListener; 248 import com.android.systemui.statusbar.stack.StackStateAnimator; 249 import com.android.systemui.util.NotificationChannels; 250 import com.android.systemui.util.leak.LeakDetector; 251 import com.android.systemui.volume.VolumeComponent; 252 253 import java.io.FileDescriptor; 254 import java.io.PrintWriter; 255 import java.io.StringWriter; 256 import java.util.ArrayList; 257 import java.util.Collection; 258 import java.util.Collections; 259 import java.util.HashMap; 260 import java.util.HashSet; 261 import java.util.List; 262 import java.util.Locale; 263 import java.util.Map; 264 import java.util.Set; 265 import java.util.Stack; 266 267 public class StatusBar extends SystemUI implements DemoMode, 268 DragDownHelper.DragDownCallback, ActivityStarter, OnUnlockMethodChangedListener, 269 OnHeadsUpChangedListener, VisualStabilityManager.Callback, CommandQueue.Callbacks, 270 ActivatableNotificationView.OnActivatedListener, 271 ExpandableNotificationRow.ExpansionLogger, NotificationData.Environment, 272 ExpandableNotificationRow.OnExpandClickListener, InflationCallback, 273 ColorExtractor.OnColorsChangedListener, ConfigurationListener { 274 public static final boolean MULTIUSER_DEBUG = false; 275 276 public static final boolean ENABLE_REMOTE_INPUT = 277 SystemProperties.getBoolean("debug.enable_remote_input", true); 278 public static final boolean ENABLE_CHILD_NOTIFICATIONS 279 = SystemProperties.getBoolean("debug.child_notifs", true); 280 public static final boolean FORCE_REMOTE_INPUT_HISTORY = 281 SystemProperties.getBoolean("debug.force_remoteinput_history", false); 282 private static boolean ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT = false; 283 284 protected static final int MSG_SHOW_RECENT_APPS = 1019; 285 protected static final int MSG_HIDE_RECENT_APPS = 1020; 286 protected static final int MSG_TOGGLE_RECENTS_APPS = 1021; 287 protected static final int MSG_PRELOAD_RECENT_APPS = 1022; 288 protected static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 1023; 289 protected static final int MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU = 1026; 290 protected static final int MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU = 1027; 291 292 protected static final boolean ENABLE_HEADS_UP = true; 293 protected static final String SETTING_HEADS_UP_TICKER = "ticker_gets_heads_up"; 294 295 // Must match constant in Settings. Used to highlight preferences when linking to Settings. 296 private static final String EXTRA_FRAGMENT_ARG_KEY = ":settings:fragment_args_key"; 297 298 private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF"; 299 300 // Should match the values in PhoneWindowManager 301 public static final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey"; 302 public static final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps"; 303 static public final String SYSTEM_DIALOG_REASON_SCREENSHOT = "screenshot"; 304 305 private static final String BANNER_ACTION_CANCEL = 306 "com.android.systemui.statusbar.banner_action_cancel"; 307 private static final String BANNER_ACTION_SETUP = 308 "com.android.systemui.statusbar.banner_action_setup"; 309 private static final String NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION 310 = "com.android.systemui.statusbar.work_challenge_unlocked_notification_action"; 311 public static final String TAG = "StatusBar"; 312 public static final boolean DEBUG = false; 313 public static final boolean SPEW = false; 314 public static final boolean DUMPTRUCK = true; // extra dumpsys info 315 public static final boolean DEBUG_GESTURES = false; 316 public static final boolean DEBUG_MEDIA = false; 317 public static final boolean DEBUG_MEDIA_FAKE_ARTWORK = false; 318 public static final boolean DEBUG_CAMERA_LIFT = false; 319 320 public static final boolean DEBUG_WINDOW_STATE = false; 321 322 // additional instrumentation for testing purposes; intended to be left on during development 323 public static final boolean CHATTY = DEBUG; 324 325 public static final boolean SHOW_LOCKSCREEN_MEDIA_ARTWORK = true; 326 327 public static final String ACTION_FAKE_ARTWORK = "fake_artwork"; 328 329 private static final int MSG_OPEN_NOTIFICATION_PANEL = 1000; 330 private static final int MSG_CLOSE_PANELS = 1001; 331 private static final int MSG_OPEN_SETTINGS_PANEL = 1002; 332 private static final int MSG_LAUNCH_TRANSITION_TIMEOUT = 1003; 333 // 1020-1040 reserved for BaseStatusBar 334 335 // Time after we abort the launch transition. 336 private static final long LAUNCH_TRANSITION_TIMEOUT_MS = 5000; 337 338 private static final boolean CLOSE_PANEL_WHEN_EMPTIED = true; 339 340 private static final int STATUS_OR_NAV_TRANSIENT = 341 View.STATUS_BAR_TRANSIENT | View.NAVIGATION_BAR_TRANSIENT; 342 private static final long AUTOHIDE_TIMEOUT_MS = 2250; 343 344 /** The minimum delay in ms between reports of notification visibility. */ 345 private static final int VISIBILITY_REPORT_MIN_DELAY_MS = 500; 346 347 /** 348 * The delay to reset the hint text when the hint animation is finished running. 349 */ 350 private static final int HINT_RESET_DELAY_MS = 1200; 351 352 private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder() 353 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) 354 .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION) 355 .build(); 356 357 public static final int FADE_KEYGUARD_START_DELAY = 100; 358 public static final int FADE_KEYGUARD_DURATION = 300; 359 public static final int FADE_KEYGUARD_DURATION_PULSING = 96; 360 361 /** If true, the system is in the half-boot-to-decryption-screen state. 362 * Prudently disable QS and notifications. */ 363 private static final boolean ONLY_CORE_APPS; 364 365 /** If true, the lockscreen will show a distinct wallpaper */ 366 private static final boolean ENABLE_LOCKSCREEN_WALLPAPER = true; 367 368 /* If true, the device supports freeform window management. 369 * This affects the status bar UI. */ 370 private static final boolean FREEFORM_WINDOW_MANAGEMENT; 371 372 /** 373 * How long to wait before auto-dismissing a notification that was kept for remote input, and 374 * has now sent a remote input. We auto-dismiss, because the app may not see a reason to cancel 375 * these given that they technically don't exist anymore. We wait a bit in case the app issues 376 * an update. 377 */ 378 private static final int REMOTE_INPUT_KEPT_ENTRY_AUTO_CANCEL_DELAY = 200; 379 380 /** 381 * Never let the alpha become zero for surfaces that draw with SRC - otherwise the RenderNode 382 * won't draw anything and uninitialized memory will show through 383 * if mScrimSrcModeEnabled. Note that 0.001 is rounded down to 0 in 384 * libhwui. 385 */ 386 private static final float SRC_MIN_ALPHA = 0.002f; 387 388 static { 389 boolean onlyCoreApps; 390 boolean freeformWindowManagement; 391 try { 392 IPackageManager packageManager = 393 IPackageManager.Stub.asInterface(ServiceManager.getService("package")); 394 onlyCoreApps = packageManager.isOnlyCoreApps(); 395 freeformWindowManagement = packageManager.hasSystemFeature( 396 PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT, 0); 397 } catch (RemoteException e) { 398 onlyCoreApps = false; 399 freeformWindowManagement = false; 400 } 401 ONLY_CORE_APPS = onlyCoreApps; 402 FREEFORM_WINDOW_MANAGEMENT = freeformWindowManagement; 403 } 404 405 /** 406 * The {@link StatusBarState} of the status bar. 407 */ 408 protected int mState; 409 protected boolean mBouncerShowing; 410 protected boolean mShowLockscreenNotifications; 411 protected boolean mAllowLockscreenRemoteInput; 412 413 PhoneStatusBarPolicy mIconPolicy; 414 415 VolumeComponent mVolumeComponent; 416 BrightnessMirrorController mBrightnessMirrorController; 417 protected FingerprintUnlockController mFingerprintUnlockController; 418 LightBarController mLightBarController; 419 protected LockscreenWallpaper mLockscreenWallpaper; 420 421 int mNaturalBarHeight = -1; 422 423 Point mCurrentDisplaySize = new Point(); 424 425 protected StatusBarWindowView mStatusBarWindow; 426 protected PhoneStatusBarView mStatusBarView; 427 private int mStatusBarWindowState = WINDOW_STATE_SHOWING; 428 protected StatusBarWindowManager mStatusBarWindowManager; 429 protected UnlockMethodCache mUnlockMethodCache; 430 private DozeServiceHost mDozeServiceHost = new DozeServiceHost(); 431 private boolean mWakeUpComingFromTouch; 432 private PointF mWakeUpTouchLocation; 433 434 int mPixelFormat; 435 Object mQueueLock = new Object(); 436 437 protected StatusBarIconController mIconController; 438 439 // expanded notifications 440 protected NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window 441 View mExpandedContents; 442 TextView mNotificationPanelDebugText; 443 444 /** 445 * {@code true} if notifications not part of a group should by default be rendered in their 446 * expanded state. If {@code false}, then only the first notification will be expanded if 447 * possible. 448 */ 449 private boolean mAlwaysExpandNonGroupedNotification; 450 451 // settings 452 private QSPanel mQSPanel; 453 454 // top bar 455 protected KeyguardStatusBarView mKeyguardStatusBar; 456 boolean mLeaveOpenOnKeyguardHide; 457 KeyguardIndicationController mKeyguardIndicationController; 458 459 // Keyguard is going away soon. 460 private boolean mKeyguardGoingAway; 461 // Keyguard is actually fading away now. 462 protected boolean mKeyguardFadingAway; 463 protected long mKeyguardFadingAwayDelay; 464 protected long mKeyguardFadingAwayDuration; 465 466 // RemoteInputView to be activated after unlock 467 private View mPendingRemoteInputView; 468 private View mPendingWorkRemoteInputView; 469 470 private View mReportRejectedTouch; 471 472 int mMaxAllowedKeyguardNotifications; 473 474 boolean mExpandedVisible; 475 476 // the tracker view 477 int mTrackingPosition; // the position of the top of the tracking view. 478 479 // Tracking finger for opening/closing. 480 boolean mTracking; 481 482 int[] mAbsPos = new int[2]; 483 ArrayList<Runnable> mPostCollapseRunnables = new ArrayList<>(); 484 485 // for disabling the status bar 486 int mDisabled1 = 0; 487 int mDisabled2 = 0; 488 489 // tracking calls to View.setSystemUiVisibility() 490 int mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE; 491 private final Rect mLastFullscreenStackBounds = new Rect(); 492 private final Rect mLastDockedStackBounds = new Rect(); 493 private final Rect mTmpRect = new Rect(); 494 495 // last value sent to window manager 496 private int mLastDispatchedSystemUiVisibility = ~View.SYSTEM_UI_FLAG_VISIBLE; 497 498 DisplayMetrics mDisplayMetrics = new DisplayMetrics(); 499 500 // XXX: gesture research 501 private final GestureRecorder mGestureRec = DEBUG_GESTURES 502 ? new GestureRecorder("/sdcard/statusbar_gestures.dat") 503 : null; 504 505 private ScreenPinningRequest mScreenPinningRequest; 506 507 private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class); 508 509 // ensure quick settings is disabled until the current user makes it through the setup wizard 510 private boolean mUserSetup = false; 511 private DeviceProvisionedListener mUserSetupObserver = new DeviceProvisionedListener() { 512 @Override 513 public void onUserSetupChanged() { 514 final boolean userSetup = mDeviceProvisionedController.isUserSetup( 515 mDeviceProvisionedController.getCurrentUser()); 516 if (MULTIUSER_DEBUG) Log.d(TAG, String.format("User setup changed: " + 517 "userSetup=%s mUserSetup=%s", userSetup, mUserSetup)); 518 519 if (userSetup != mUserSetup) { 520 mUserSetup = userSetup; 521 if (!mUserSetup && mStatusBarView != null) 522 animateCollapseQuickSettings(); 523 if (mNotificationPanel != null) { 524 mNotificationPanel.setUserSetupComplete(mUserSetup); 525 } 526 updateQsExpansionEnabled(); 527 } 528 } 529 }; 530 531 protected H mHandler = createHandler(); 532 final private ContentObserver mHeadsUpObserver = new ContentObserver(mHandler) { 533 @Override 534 public void onChange(boolean selfChange) { 535 boolean wasUsing = mUseHeadsUp; 536 mUseHeadsUp = ENABLE_HEADS_UP && !mDisableNotificationAlerts 537 && Settings.Global.HEADS_UP_OFF != Settings.Global.getInt( 538 mContext.getContentResolver(), Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED, 539 Settings.Global.HEADS_UP_OFF); 540 mHeadsUpTicker = mUseHeadsUp && 0 != Settings.Global.getInt( 541 mContext.getContentResolver(), SETTING_HEADS_UP_TICKER, 0); 542 Log.d(TAG, "heads up is " + (mUseHeadsUp ? "enabled" : "disabled")); 543 if (wasUsing != mUseHeadsUp) { 544 if (!mUseHeadsUp) { 545 Log.d(TAG, "dismissing any existing heads up notification on disable event"); 546 mHeadsUpManager.releaseAllImmediately(); 547 } 548 } 549 } 550 }; 551 552 private int mInteractingWindows; 553 private boolean mAutohideSuspended; 554 private int mStatusBarMode; 555 private int mMaxKeyguardNotifications; 556 557 private ViewMediatorCallback mKeyguardViewMediatorCallback; 558 protected ScrimController mScrimController; 559 protected DozeScrimController mDozeScrimController; 560 private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class); 561 562 private final Runnable mAutohide = () -> { 563 int requested = mSystemUiVisibility & ~STATUS_OR_NAV_TRANSIENT; 564 if (mSystemUiVisibility != requested) { 565 notifyUiVisibilityChanged(requested); 566 } 567 }; 568 569 private boolean mWaitingForKeyguardExit; 570 protected boolean mDozing; 571 private boolean mDozingRequested; 572 protected boolean mScrimSrcModeEnabled; 573 574 public static final Interpolator ALPHA_IN = Interpolators.ALPHA_IN; 575 public static final Interpolator ALPHA_OUT = Interpolators.ALPHA_OUT; 576 577 protected BackDropView mBackdrop; 578 protected ImageView mBackdropFront, mBackdropBack; 579 protected PorterDuffXfermode mSrcXferMode = new PorterDuffXfermode(PorterDuff.Mode.SRC); 580 protected PorterDuffXfermode mSrcOverXferMode = 581 new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER); 582 583 private MediaSessionManager mMediaSessionManager; 584 private MediaController mMediaController; 585 private String mMediaNotificationKey; 586 private MediaMetadata mMediaMetadata; 587 private MediaController.Callback mMediaListener 588 = new MediaController.Callback() { 589 @Override 590 public void onPlaybackStateChanged(PlaybackState state) { 591 super.onPlaybackStateChanged(state); 592 if (DEBUG_MEDIA) Log.v(TAG, "DEBUG_MEDIA: onPlaybackStateChanged: " + state); 593 if (state != null) { 594 if (!isPlaybackActive(state.getState())) { 595 clearCurrentMediaNotification(); 596 updateMediaMetaData(true, true); 597 } 598 } 599 } 600 601 @Override 602 public void onMetadataChanged(MediaMetadata metadata) { 603 super.onMetadataChanged(metadata); 604 if (DEBUG_MEDIA) Log.v(TAG, "DEBUG_MEDIA: onMetadataChanged: " + metadata); 605 mMediaMetadata = metadata; 606 updateMediaMetaData(true, true); 607 } 608 }; 609 610 private final OnChildLocationsChangedListener mOnChildLocationsChangedListener = 611 new OnChildLocationsChangedListener() { 612 @Override 613 public void onChildLocationsChanged(NotificationStackScrollLayout stackScrollLayout) { 614 userActivity(); 615 } 616 }; 617 618 private int mDisabledUnmodified1; 619 private int mDisabledUnmodified2; 620 621 /** Keys of notifications currently visible to the user. */ 622 private final ArraySet<NotificationVisibility> mCurrentlyVisibleNotifications = 623 new ArraySet<>(); 624 private long mLastVisibilityReportUptimeMs; 625 626 private Runnable mLaunchTransitionEndRunnable; 627 protected boolean mLaunchTransitionFadingAway; 628 private ExpandableNotificationRow mDraggedDownRow; 629 private boolean mLaunchCameraOnScreenTurningOn; 630 private boolean mLaunchCameraOnFinishedGoingToSleep; 631 private int mLastCameraLaunchSource; 632 private PowerManager.WakeLock mGestureWakeLock; 633 private Vibrator mVibrator; 634 private long[] mCameraLaunchGestureVibePattern; 635 636 private final int[] mTmpInt2 = new int[2]; 637 638 // Fingerprint (as computed by getLoggingFingerprint() of the last logged state. 639 private int mLastLoggedStateFingerprint; 640 private boolean mTopHidesStatusBar; 641 private boolean mStatusBarWindowHidden; 642 private boolean mHideIconsForBouncer; 643 private boolean mIsOccluded; 644 private boolean mWereIconsJustHidden; 645 private boolean mBouncerWasShowingWhenHidden; 646 647 public boolean isStartedGoingToSleep() { 648 return mStartedGoingToSleep; 649 } 650 651 /** 652 * If set, the device has started going to sleep but isn't fully non-interactive yet. 653 */ 654 protected boolean mStartedGoingToSleep; 655 656 private final OnChildLocationsChangedListener mNotificationLocationsChangedListener = 657 new OnChildLocationsChangedListener() { 658 @Override 659 public void onChildLocationsChanged( 660 NotificationStackScrollLayout stackScrollLayout) { 661 if (mHandler.hasCallbacks(mVisibilityReporter)) { 662 // Visibilities will be reported when the existing 663 // callback is executed. 664 return; 665 } 666 // Calculate when we're allowed to run the visibility 667 // reporter. Note that this timestamp might already have 668 // passed. That's OK, the callback will just be executed 669 // ASAP. 670 long nextReportUptimeMs = 671 mLastVisibilityReportUptimeMs + VISIBILITY_REPORT_MIN_DELAY_MS; 672 mHandler.postAtTime(mVisibilityReporter, nextReportUptimeMs); 673 } 674 }; 675 676 // Tracks notifications currently visible in mNotificationStackScroller and 677 // emits visibility events via NoMan on changes. 678 protected final Runnable mVisibilityReporter = new Runnable() { 679 private final ArraySet<NotificationVisibility> mTmpNewlyVisibleNotifications = 680 new ArraySet<>(); 681 private final ArraySet<NotificationVisibility> mTmpCurrentlyVisibleNotifications = 682 new ArraySet<>(); 683 private final ArraySet<NotificationVisibility> mTmpNoLongerVisibleNotifications = 684 new ArraySet<>(); 685 686 @Override 687 public void run() { 688 mLastVisibilityReportUptimeMs = SystemClock.uptimeMillis(); 689 final String mediaKey = getCurrentMediaNotificationKey(); 690 691 // 1. Loop over mNotificationData entries: 692 // A. Keep list of visible notifications. 693 // B. Keep list of previously hidden, now visible notifications. 694 // 2. Compute no-longer visible notifications by removing currently 695 // visible notifications from the set of previously visible 696 // notifications. 697 // 3. Report newly visible and no-longer visible notifications. 698 // 4. Keep currently visible notifications for next report. 699 ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications(); 700 int N = activeNotifications.size(); 701 for (int i = 0; i < N; i++) { 702 Entry entry = activeNotifications.get(i); 703 String key = entry.notification.getKey(); 704 boolean isVisible = mStackScroller.isInVisibleLocation(entry.row); 705 NotificationVisibility visObj = NotificationVisibility.obtain(key, i, isVisible); 706 boolean previouslyVisible = mCurrentlyVisibleNotifications.contains(visObj); 707 if (isVisible) { 708 // Build new set of visible notifications. 709 mTmpCurrentlyVisibleNotifications.add(visObj); 710 if (!previouslyVisible) { 711 mTmpNewlyVisibleNotifications.add(visObj); 712 } 713 } else { 714 // release object 715 visObj.recycle(); 716 } 717 } 718 mTmpNoLongerVisibleNotifications.addAll(mCurrentlyVisibleNotifications); 719 mTmpNoLongerVisibleNotifications.removeAll(mTmpCurrentlyVisibleNotifications); 720 721 logNotificationVisibilityChanges( 722 mTmpNewlyVisibleNotifications, mTmpNoLongerVisibleNotifications); 723 724 recycleAllVisibilityObjects(mCurrentlyVisibleNotifications); 725 mCurrentlyVisibleNotifications.addAll(mTmpCurrentlyVisibleNotifications); 726 727 recycleAllVisibilityObjects(mTmpNoLongerVisibleNotifications); 728 mTmpCurrentlyVisibleNotifications.clear(); 729 mTmpNewlyVisibleNotifications.clear(); 730 mTmpNoLongerVisibleNotifications.clear(); 731 } 732 }; 733 734 private NotificationMessagingUtil mMessagingUtil; 735 private KeyguardUserSwitcher mKeyguardUserSwitcher; 736 private UserSwitcherController mUserSwitcherController; 737 private NetworkController mNetworkController; 738 private KeyguardMonitorImpl mKeyguardMonitor 739 = (KeyguardMonitorImpl) Dependency.get(KeyguardMonitor.class); 740 private BatteryController mBatteryController; 741 protected boolean mPanelExpanded; 742 private IOverlayManager mOverlayManager; 743 private boolean mKeyguardRequested; 744 private boolean mIsKeyguard; 745 private LogMaker mStatusBarStateLog; 746 private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger(); 747 protected NotificationIconAreaController mNotificationIconAreaController; 748 private boolean mReinflateNotificationsOnUserSwitched; 749 private HashMap<String, Entry> mPendingNotifications = new HashMap<>(); 750 private boolean mClearAllEnabled; 751 @Nullable private View mAmbientIndicationContainer; 752 private String mKeyToRemoveOnGutsClosed; 753 private SysuiColorExtractor mColorExtractor; 754 private ForegroundServiceController mForegroundServiceController; 755 private ScreenLifecycle mScreenLifecycle; 756 @VisibleForTesting WakefulnessLifecycle mWakefulnessLifecycle; 757 758 private void recycleAllVisibilityObjects(ArraySet<NotificationVisibility> array) { 759 final int N = array.size(); 760 for (int i = 0 ; i < N; i++) { 761 array.valueAt(i).recycle(); 762 } 763 array.clear(); 764 } 765 766 private final View.OnClickListener mGoToLockedShadeListener = v -> { 767 if (mState == StatusBarState.KEYGUARD) { 768 wakeUpIfDozing(SystemClock.uptimeMillis(), v); 769 goToLockedShade(null); 770 } 771 }; 772 private HashMap<ExpandableNotificationRow, List<ExpandableNotificationRow>> mTmpChildOrderMap 773 = new HashMap<>(); 774 private RankingMap mLatestRankingMap; 775 private boolean mNoAnimationOnNextBarModeChange; 776 private FalsingManager mFalsingManager; 777 778 private KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() { 779 @Override 780 public void onDreamingStateChanged(boolean dreaming) { 781 if (dreaming) { 782 maybeEscalateHeadsUp(); 783 } 784 } 785 }; 786 787 private NavigationBarFragment mNavigationBar; 788 private View mNavigationBarView; 789 790 @Override 791 public void start() { 792 mNetworkController = Dependency.get(NetworkController.class); 793 mUserSwitcherController = Dependency.get(UserSwitcherController.class); 794 mScreenLifecycle = Dependency.get(ScreenLifecycle.class); 795 mScreenLifecycle.addObserver(mScreenObserver); 796 mWakefulnessLifecycle = Dependency.get(WakefulnessLifecycle.class); 797 mWakefulnessLifecycle.addObserver(mWakefulnessObserver); 798 mBatteryController = Dependency.get(BatteryController.class); 799 mAssistManager = Dependency.get(AssistManager.class); 800 mSystemServicesProxy = SystemServicesProxy.getInstance(mContext); 801 mOverlayManager = IOverlayManager.Stub.asInterface( 802 ServiceManager.getService(Context.OVERLAY_SERVICE)); 803 804 mColorExtractor = Dependency.get(SysuiColorExtractor.class); 805 mColorExtractor.addOnColorsChangedListener(this); 806 807 mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); 808 809 mForegroundServiceController = Dependency.get(ForegroundServiceController.class); 810 811 mDisplay = mWindowManager.getDefaultDisplay(); 812 updateDisplaySize(); 813 814 Resources res = mContext.getResources(); 815 mScrimSrcModeEnabled = res.getBoolean(R.bool.config_status_bar_scrim_behind_use_src); 816 mClearAllEnabled = res.getBoolean(R.bool.config_enableNotificationsClearAll); 817 mAlwaysExpandNonGroupedNotification = 818 res.getBoolean(R.bool.config_alwaysExpandNonGroupedNotifications); 819 820 DateTimeView.setReceiverHandler(Dependency.get(Dependency.TIME_TICK_HANDLER)); 821 putComponent(StatusBar.class, this); 822 823 // start old BaseStatusBar.start(). 824 mWindowManagerService = WindowManagerGlobal.getWindowManagerService(); 825 mDevicePolicyManager = (DevicePolicyManager) mContext.getSystemService( 826 Context.DEVICE_POLICY_SERVICE); 827 828 mNotificationData = new NotificationData(this); 829 mMessagingUtil = new NotificationMessagingUtil(mContext); 830 831 mAccessibilityManager = (AccessibilityManager) 832 mContext.getSystemService(Context.ACCESSIBILITY_SERVICE); 833 834 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 835 836 mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class); 837 mDeviceProvisionedController.addCallback(mDeviceProvisionedListener); 838 mContext.getContentResolver().registerContentObserver( 839 Settings.Global.getUriFor(Settings.Global.ZEN_MODE), false, 840 mSettingsObserver); 841 mContext.getContentResolver().registerContentObserver( 842 Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS), false, 843 mLockscreenSettingsObserver, 844 UserHandle.USER_ALL); 845 if (ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT) { 846 mContext.getContentResolver().registerContentObserver( 847 Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT), 848 false, 849 mSettingsObserver, 850 UserHandle.USER_ALL); 851 } 852 853 mContext.getContentResolver().registerContentObserver( 854 Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS), 855 true, 856 mLockscreenSettingsObserver, 857 UserHandle.USER_ALL); 858 859 mBarService = IStatusBarService.Stub.asInterface( 860 ServiceManager.getService(Context.STATUS_BAR_SERVICE)); 861 862 mRecents = getComponent(Recents.class); 863 864 final Configuration currentConfig = res.getConfiguration(); 865 mLocale = currentConfig.locale; 866 mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(mLocale); 867 868 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 869 mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE); 870 mLockPatternUtils = new LockPatternUtils(mContext); 871 872 // Connect in to the status bar manager service 873 mCommandQueue = getComponent(CommandQueue.class); 874 mCommandQueue.addCallbacks(this); 875 876 int[] switches = new int[9]; 877 ArrayList<IBinder> binders = new ArrayList<>(); 878 ArrayList<String> iconSlots = new ArrayList<>(); 879 ArrayList<StatusBarIcon> icons = new ArrayList<>(); 880 Rect fullscreenStackBounds = new Rect(); 881 Rect dockedStackBounds = new Rect(); 882 try { 883 mBarService.registerStatusBar(mCommandQueue, iconSlots, icons, switches, binders, 884 fullscreenStackBounds, dockedStackBounds); 885 } catch (RemoteException ex) { 886 // If the system process isn't there we're doomed anyway. 887 } 888 889 createAndAddWindows(); 890 891 mSettingsObserver.onChange(false); // set up 892 mCommandQueue.disable(switches[0], switches[6], false /* animate */); 893 setSystemUiVisibility(switches[1], switches[7], switches[8], 0xffffffff, 894 fullscreenStackBounds, dockedStackBounds); 895 topAppWindowChanged(switches[2] != 0); 896 // StatusBarManagerService has a back up of IME token and it's restored here. 897 setImeWindowStatus(binders.get(0), switches[3], switches[4], switches[5] != 0); 898 899 // Set up the initial icon state 900 int N = iconSlots.size(); 901 for (int i=0; i < N; i++) { 902 mCommandQueue.setIcon(iconSlots.get(i), icons.get(i)); 903 } 904 905 // Set up the initial notification state. 906 try { 907 mNotificationListener.registerAsSystemService(mContext, 908 new ComponentName(mContext.getPackageName(), getClass().getCanonicalName()), 909 UserHandle.USER_ALL); 910 } catch (RemoteException e) { 911 Log.e(TAG, "Unable to register notification listener", e); 912 } 913 914 915 if (DEBUG) { 916 Log.d(TAG, String.format( 917 "init: icons=%d disabled=0x%08x lights=0x%08x menu=0x%08x imeButton=0x%08x", 918 icons.size(), 919 switches[0], 920 switches[1], 921 switches[2], 922 switches[3] 923 )); 924 } 925 926 mCurrentUserId = ActivityManager.getCurrentUser(); 927 setHeadsUpUser(mCurrentUserId); 928 929 IntentFilter filter = new IntentFilter(); 930 filter.addAction(Intent.ACTION_USER_SWITCHED); 931 filter.addAction(Intent.ACTION_USER_ADDED); 932 filter.addAction(Intent.ACTION_USER_PRESENT); 933 mContext.registerReceiver(mBaseBroadcastReceiver, filter); 934 935 IntentFilter internalFilter = new IntentFilter(); 936 internalFilter.addAction(NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION); 937 internalFilter.addAction(BANNER_ACTION_CANCEL); 938 internalFilter.addAction(BANNER_ACTION_SETUP); 939 mContext.registerReceiver(mBaseBroadcastReceiver, internalFilter, PERMISSION_SELF, null); 940 941 IntentFilter allUsersFilter = new IntentFilter(); 942 allUsersFilter.addAction( 943 DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED); 944 allUsersFilter.addAction(Intent.ACTION_DEVICE_LOCKED_CHANGED); 945 mContext.registerReceiverAsUser(mAllUsersReceiver, UserHandle.ALL, allUsersFilter, 946 null, null); 947 updateCurrentProfilesCache(); 948 949 IVrManager vrManager = IVrManager.Stub.asInterface(ServiceManager.getService( 950 Context.VR_SERVICE)); 951 try { 952 vrManager.registerListener(mVrStateCallbacks); 953 } catch (RemoteException e) { 954 Slog.e(TAG, "Failed to register VR mode state listener: " + e); 955 } 956 957 mNonBlockablePkgs = new HashSet<>(); 958 Collections.addAll(mNonBlockablePkgs, res.getStringArray( 959 com.android.internal.R.array.config_nonBlockableNotificationPackages)); 960 // end old BaseStatusBar.start(). 961 962 mMediaSessionManager 963 = (MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE); 964 // TODO: use MediaSessionManager.SessionListener to hook us up to future updates 965 // in session state 966 967 // Lastly, call to the icon policy to install/update all the icons. 968 mIconPolicy = new PhoneStatusBarPolicy(mContext, mIconController); 969 mSettingsObserver.onChange(false); // set up 970 971 mHeadsUpObserver.onChange(true); // set up 972 if (ENABLE_HEADS_UP) { 973 mContext.getContentResolver().registerContentObserver( 974 Settings.Global.getUriFor(Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED), true, 975 mHeadsUpObserver); 976 mContext.getContentResolver().registerContentObserver( 977 Settings.Global.getUriFor(SETTING_HEADS_UP_TICKER), true, 978 mHeadsUpObserver); 979 } 980 mUnlockMethodCache = UnlockMethodCache.getInstance(mContext); 981 mUnlockMethodCache.addListener(this); 982 startKeyguard(); 983 984 KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateCallback); 985 putComponent(DozeHost.class, mDozeServiceHost); 986 987 notifyUserAboutHiddenNotifications(); 988 989 mScreenPinningRequest = new ScreenPinningRequest(mContext); 990 mFalsingManager = FalsingManager.getInstance(mContext); 991 992 Dependency.get(ActivityStarterDelegate.class).setActivityStarterImpl(this); 993 994 Dependency.get(ConfigurationController.class).addCallback(this); 995 } 996 997 protected void createIconController() { 998 } 999 1000 // ================================================================================ 1001 // Constructing the view 1002 // ================================================================================ 1003 protected void makeStatusBarView() { 1004 final Context context = mContext; 1005 updateDisplaySize(); // populates mDisplayMetrics 1006 updateResources(); 1007 updateTheme(); 1008 1009 inflateStatusBarWindow(context); 1010 mStatusBarWindow.setService(this); 1011 mStatusBarWindow.setOnTouchListener(getStatusBarWindowTouchListener()); 1012 1013 // TODO: Deal with the ugliness that comes from having some of the statusbar broken out 1014 // into fragments, but the rest here, it leaves some awkward lifecycle and whatnot. 1015 mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById( 1016 R.id.notification_panel); 1017 mStackScroller = (NotificationStackScrollLayout) mStatusBarWindow.findViewById( 1018 R.id.notification_stack_scroller); 1019 mNotificationPanel.setStatusBar(this); 1020 mNotificationPanel.setGroupManager(mGroupManager); 1021 mAboveShelfObserver = new AboveShelfObserver(mStackScroller); 1022 mAboveShelfObserver.setListener(mStatusBarWindow.findViewById( 1023 R.id.notification_container_parent)); 1024 mKeyguardStatusBar = (KeyguardStatusBarView) mStatusBarWindow.findViewById(R.id.keyguard_header); 1025 1026 mNotificationIconAreaController = SystemUIFactory.getInstance() 1027 .createNotificationIconAreaController(context, this); 1028 inflateShelf(); 1029 mNotificationIconAreaController.setupShelf(mNotificationShelf); 1030 Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mNotificationIconAreaController); 1031 FragmentHostManager.get(mStatusBarWindow) 1032 .addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> { 1033 CollapsedStatusBarFragment statusBarFragment = 1034 (CollapsedStatusBarFragment) fragment; 1035 statusBarFragment.initNotificationIconArea(mNotificationIconAreaController); 1036 mStatusBarView = (PhoneStatusBarView) fragment.getView(); 1037 mStatusBarView.setBar(this); 1038 mStatusBarView.setPanel(mNotificationPanel); 1039 mStatusBarView.setScrimController(mScrimController); 1040 mStatusBarView.setBouncerShowing(mBouncerShowing); 1041 setAreThereNotifications(); 1042 checkBarModes(); 1043 }).getFragmentManager() 1044 .beginTransaction() 1045 .replace(R.id.status_bar_container, new CollapsedStatusBarFragment(), 1046 CollapsedStatusBarFragment.TAG) 1047 .commit(); 1048 mIconController = Dependency.get(StatusBarIconController.class); 1049 1050 mHeadsUpManager = new HeadsUpManager(context, mStatusBarWindow, mGroupManager); 1051 mHeadsUpManager.setBar(this); 1052 mHeadsUpManager.addListener(this); 1053 mHeadsUpManager.addListener(mNotificationPanel); 1054 mHeadsUpManager.addListener(mGroupManager); 1055 mHeadsUpManager.addListener(mVisualStabilityManager); 1056 mNotificationPanel.setHeadsUpManager(mHeadsUpManager); 1057 mNotificationData.setHeadsUpManager(mHeadsUpManager); 1058 mGroupManager.setHeadsUpManager(mHeadsUpManager); 1059 mHeadsUpManager.setVisualStabilityManager(mVisualStabilityManager); 1060 1061 if (MULTIUSER_DEBUG) { 1062 mNotificationPanelDebugText = (TextView) mNotificationPanel.findViewById( 1063 R.id.header_debug_info); 1064 mNotificationPanelDebugText.setVisibility(View.VISIBLE); 1065 } 1066 1067 try { 1068 boolean showNav = mWindowManagerService.hasNavigationBar(); 1069 if (DEBUG) Log.v(TAG, "hasNavigationBar=" + showNav); 1070 if (showNav) { 1071 createNavigationBar(); 1072 } 1073 } catch (RemoteException ex) { 1074 // no window manager? good luck with that 1075 } 1076 1077 // figure out which pixel-format to use for the status bar. 1078 mPixelFormat = PixelFormat.OPAQUE; 1079 1080 mStackScroller.setLongPressListener(getNotificationLongClicker()); 1081 mStackScroller.setStatusBar(this); 1082 mStackScroller.setGroupManager(mGroupManager); 1083 mStackScroller.setHeadsUpManager(mHeadsUpManager); 1084 mGroupManager.setOnGroupChangeListener(mStackScroller); 1085 mVisualStabilityManager.setVisibilityLocationProvider(mStackScroller); 1086 1087 inflateEmptyShadeView(); 1088 inflateDismissView(); 1089 mExpandedContents = mStackScroller; 1090 1091 mBackdrop = (BackDropView) mStatusBarWindow.findViewById(R.id.backdrop); 1092 mBackdropFront = (ImageView) mBackdrop.findViewById(R.id.backdrop_front); 1093 mBackdropBack = (ImageView) mBackdrop.findViewById(R.id.backdrop_back); 1094 1095 if (ENABLE_LOCKSCREEN_WALLPAPER) { 1096 mLockscreenWallpaper = new LockscreenWallpaper(mContext, this, mHandler); 1097 } 1098 1099 mKeyguardIndicationController = 1100 SystemUIFactory.getInstance().createKeyguardIndicationController(mContext, 1101 (ViewGroup) mStatusBarWindow.findViewById(R.id.keyguard_indication_area), 1102 mNotificationPanel.getLockIcon()); 1103 mNotificationPanel.setKeyguardIndicationController(mKeyguardIndicationController); 1104 1105 1106 mAmbientIndicationContainer = mStatusBarWindow.findViewById( 1107 R.id.ambient_indication_container); 1108 1109 // set the initial view visibility 1110 setAreThereNotifications(); 1111 1112 // TODO: Find better place for this callback. 1113 mBatteryController.addCallback(new BatteryStateChangeCallback() { 1114 @Override 1115 public void onPowerSaveChanged(boolean isPowerSave) { 1116 mHandler.post(mCheckBarModes); 1117 if (mDozeServiceHost != null) { 1118 mDozeServiceHost.firePowerSaveChanged(isPowerSave); 1119 } 1120 } 1121 1122 @Override 1123 public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) { 1124 // noop 1125 } 1126 }); 1127 1128 mLightBarController = Dependency.get(LightBarController.class); 1129 if (mNavigationBar != null) { 1130 mNavigationBar.setLightBarController(mLightBarController); 1131 } 1132 1133 ScrimView scrimBehind = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_behind); 1134 ScrimView scrimInFront = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_in_front); 1135 View headsUpScrim = mStatusBarWindow.findViewById(R.id.heads_up_scrim); 1136 mScrimController = SystemUIFactory.getInstance().createScrimController(mLightBarController, 1137 scrimBehind, scrimInFront, headsUpScrim, mLockscreenWallpaper, 1138 scrimsVisible -> { 1139 if (mStatusBarWindowManager != null) { 1140 mStatusBarWindowManager.setScrimsVisible(scrimsVisible); 1141 } 1142 }); 1143 if (mScrimSrcModeEnabled) { 1144 Runnable runnable = new Runnable() { 1145 @Override 1146 public void run() { 1147 boolean asSrc = mBackdrop.getVisibility() != View.VISIBLE; 1148 mScrimController.setDrawBehindAsSrc(asSrc); 1149 mStackScroller.setDrawBackgroundAsSrc(asSrc); 1150 } 1151 }; 1152 mBackdrop.setOnVisibilityChangedRunnable(runnable); 1153 runnable.run(); 1154 } 1155 mHeadsUpManager.addListener(mScrimController); 1156 mStackScroller.setScrimController(mScrimController); 1157 mDozeScrimController = new DozeScrimController(mScrimController, context); 1158 1159 // Other icons 1160 mVolumeComponent = getComponent(VolumeComponent.class); 1161 1162 mNotificationPanel.setUserSetupComplete(mUserSetup); 1163 if (UserManager.get(mContext).isUserSwitcherEnabled()) { 1164 createUserSwitcher(); 1165 } 1166 1167 // Set up the quick settings tile panel 1168 View container = mStatusBarWindow.findViewById(R.id.qs_frame); 1169 if (container != null) { 1170 FragmentHostManager fragmentHostManager = FragmentHostManager.get(container); 1171 ExtensionFragmentListener.attachExtensonToFragment(container, QS.TAG, R.id.qs_frame, 1172 Dependency.get(ExtensionController.class).newExtension(QS.class) 1173 .withPlugin(QS.class) 1174 .withFeature( 1175 PackageManager.FEATURE_AUTOMOTIVE, () -> new CarQSFragment()) 1176 .withDefault(() -> new QSFragment()) 1177 .build()); 1178 final QSTileHost qsh = SystemUIFactory.getInstance().createQSTileHost(mContext, this, 1179 mIconController); 1180 mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow, 1181 mScrimController); 1182 fragmentHostManager.addTagListener(QS.TAG, (tag, f) -> { 1183 QS qs = (QS) f; 1184 if (qs instanceof QSFragment) { 1185 ((QSFragment) qs).setHost(qsh); 1186 mQSPanel = ((QSFragment) qs).getQsPanel(); 1187 mQSPanel.setBrightnessMirror(mBrightnessMirrorController); 1188 mKeyguardStatusBar.setQSPanel(mQSPanel); 1189 } 1190 }); 1191 } 1192 1193 mReportRejectedTouch = mStatusBarWindow.findViewById(R.id.report_rejected_touch); 1194 if (mReportRejectedTouch != null) { 1195 updateReportRejectedTouchVisibility(); 1196 mReportRejectedTouch.setOnClickListener(v -> { 1197 Uri session = mFalsingManager.reportRejectedTouch(); 1198 if (session == null) { return; } 1199 1200 StringWriter message = new StringWriter(); 1201 message.write("Build info: "); 1202 message.write(SystemProperties.get("ro.build.description")); 1203 message.write("\nSerial number: "); 1204 message.write(SystemProperties.get("ro.serialno")); 1205 message.write("\n"); 1206 1207 PrintWriter falsingPw = new PrintWriter(message); 1208 FalsingLog.dump(falsingPw); 1209 falsingPw.flush(); 1210 1211 startActivityDismissingKeyguard(Intent.createChooser(new Intent(Intent.ACTION_SEND) 1212 .setType("*/*") 1213 .putExtra(Intent.EXTRA_SUBJECT, "Rejected touch report") 1214 .putExtra(Intent.EXTRA_STREAM, session) 1215 .putExtra(Intent.EXTRA_TEXT, message.toString()), 1216 "Share rejected touch report") 1217 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), 1218 true /* onlyProvisioned */, true /* dismissShade */); 1219 }); 1220 } 1221 1222 PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 1223 if (!pm.isScreenOn()) { 1224 mBroadcastReceiver.onReceive(mContext, new Intent(Intent.ACTION_SCREEN_OFF)); 1225 } 1226 mGestureWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, 1227 "GestureWakeLock"); 1228 mVibrator = mContext.getSystemService(Vibrator.class); 1229 int[] pattern = mContext.getResources().getIntArray( 1230 R.array.config_cameraLaunchGestureVibePattern); 1231 mCameraLaunchGestureVibePattern = new long[pattern.length]; 1232 for (int i = 0; i < pattern.length; i++) { 1233 mCameraLaunchGestureVibePattern[i] = pattern[i]; 1234 } 1235 1236 // receive broadcasts 1237 IntentFilter filter = new IntentFilter(); 1238 filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); 1239 filter.addAction(Intent.ACTION_SCREEN_OFF); 1240 filter.addAction(DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG); 1241 context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null); 1242 1243 IntentFilter demoFilter = new IntentFilter(); 1244 if (DEBUG_MEDIA_FAKE_ARTWORK) { 1245 demoFilter.addAction(ACTION_FAKE_ARTWORK); 1246 } 1247 demoFilter.addAction(ACTION_DEMO); 1248 context.registerReceiverAsUser(mDemoReceiver, UserHandle.ALL, demoFilter, 1249 android.Manifest.permission.DUMP, null); 1250 1251 // listen for USER_SETUP_COMPLETE setting (per-user) 1252 mDeviceProvisionedController.addCallback(mUserSetupObserver); 1253 mUserSetupObserver.onUserSetupChanged(); 1254 1255 // disable profiling bars, since they overlap and clutter the output on app windows 1256 ThreadedRenderer.overrideProperty("disableProfileBars", "true"); 1257 1258 // Private API call to make the shadows look better for Recents 1259 ThreadedRenderer.overrideProperty("ambientRatio", String.valueOf(1.5f)); 1260 } 1261 1262 protected void createNavigationBar() { 1263 mNavigationBarView = NavigationBarFragment.create(mContext, (tag, fragment) -> { 1264 mNavigationBar = (NavigationBarFragment) fragment; 1265 if (mLightBarController != null) { 1266 mNavigationBar.setLightBarController(mLightBarController); 1267 } 1268 mNavigationBar.setCurrentSysuiVisibility(mSystemUiVisibility); 1269 }); 1270 } 1271 1272 /** 1273 * Returns the {@link android.view.View.OnTouchListener} that will be invoked when the 1274 * background window of the status bar is clicked. 1275 */ 1276 protected View.OnTouchListener getStatusBarWindowTouchListener() { 1277 return (v, event) -> { 1278 checkUserAutohide(v, event); 1279 checkRemoteInputOutside(event); 1280 if (event.getAction() == MotionEvent.ACTION_DOWN) { 1281 if (mExpandedVisible) { 1282 animateCollapsePanels(); 1283 } 1284 } 1285 return mStatusBarWindow.onTouchEvent(event); 1286 }; 1287 } 1288 1289 private void inflateShelf() { 1290 mNotificationShelf = 1291 (NotificationShelf) LayoutInflater.from(mContext).inflate( 1292 R.layout.status_bar_notification_shelf, mStackScroller, false); 1293 mNotificationShelf.setOnActivatedListener(this); 1294 mStackScroller.setShelf(mNotificationShelf); 1295 mNotificationShelf.setOnClickListener(mGoToLockedShadeListener); 1296 mNotificationShelf.setStatusBarState(mState); 1297 } 1298 1299 public void onDensityOrFontScaleChanged() { 1300 // start old BaseStatusBar.onDensityOrFontScaleChanged(). 1301 if (!KeyguardUpdateMonitor.getInstance(mContext).isSwitchingUser()) { 1302 updateNotificationsOnDensityOrFontScaleChanged(); 1303 } else { 1304 mReinflateNotificationsOnUserSwitched = true; 1305 } 1306 // end old BaseStatusBar.onDensityOrFontScaleChanged(). 1307 mScrimController.onDensityOrFontScaleChanged(); 1308 // TODO: Remove this. 1309 if (mStatusBarView != null) mStatusBarView.onDensityOrFontScaleChanged(); 1310 if (mBrightnessMirrorController != null) { 1311 mBrightnessMirrorController.onDensityOrFontScaleChanged(); 1312 } 1313 mStatusBarKeyguardViewManager.onDensityOrFontScaleChanged(); 1314 // TODO: Bring these out of StatusBar. 1315 ((UserInfoControllerImpl) Dependency.get(UserInfoController.class)) 1316 .onDensityOrFontScaleChanged(); 1317 Dependency.get(UserSwitcherController.class).onDensityOrFontScaleChanged(); 1318 if (mKeyguardUserSwitcher != null) { 1319 mKeyguardUserSwitcher.onDensityOrFontScaleChanged(); 1320 } 1321 mNotificationIconAreaController.onDensityOrFontScaleChanged(mContext); 1322 1323 reevaluateStyles(); 1324 } 1325 1326 private void reinflateViews() { 1327 reevaluateStyles(); 1328 1329 // Clock and bottom icons 1330 mNotificationPanel.onOverlayChanged(); 1331 // The status bar on the keyguard is a special layout. 1332 if (mKeyguardStatusBar != null) mKeyguardStatusBar.onOverlayChanged(); 1333 // Recreate Indication controller because internal references changed 1334 mKeyguardIndicationController = 1335 SystemUIFactory.getInstance().createKeyguardIndicationController(mContext, 1336 mStatusBarWindow.findViewById(R.id.keyguard_indication_area), 1337 mNotificationPanel.getLockIcon()); 1338 mNotificationPanel.setKeyguardIndicationController(mKeyguardIndicationController); 1339 mKeyguardIndicationController 1340 .setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager); 1341 mKeyguardIndicationController.setVisible(mState == StatusBarState.KEYGUARD); 1342 mKeyguardIndicationController.setDozing(mDozing); 1343 if (mBrightnessMirrorController != null) { 1344 mBrightnessMirrorController.onOverlayChanged(); 1345 } 1346 if (mStatusBarKeyguardViewManager != null) { 1347 mStatusBarKeyguardViewManager.onOverlayChanged(); 1348 } 1349 if (mAmbientIndicationContainer instanceof AutoReinflateContainer) { 1350 ((AutoReinflateContainer) mAmbientIndicationContainer).inflateLayout(); 1351 } 1352 } 1353 1354 protected void reevaluateStyles() { 1355 inflateSignalClusters(); 1356 inflateDismissView(); 1357 updateClearAll(); 1358 inflateEmptyShadeView(); 1359 updateEmptyShadeView(); 1360 } 1361 1362 private void updateNotificationsOnDensityOrFontScaleChanged() { 1363 ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications(); 1364 for (int i = 0; i < activeNotifications.size(); i++) { 1365 Entry entry = activeNotifications.get(i); 1366 boolean exposedGuts = mNotificationGutsExposed != null 1367 && entry.row.getGuts() == mNotificationGutsExposed; 1368 entry.row.onDensityOrFontScaleChanged(); 1369 if (exposedGuts) { 1370 mNotificationGutsExposed = entry.row.getGuts(); 1371 bindGuts(entry.row, mGutsMenuItem); 1372 } 1373 } 1374 } 1375 1376 private void inflateSignalClusters() { 1377 if (mKeyguardStatusBar != null) reinflateSignalCluster(mKeyguardStatusBar); 1378 } 1379 1380 public static SignalClusterView reinflateSignalCluster(View view) { 1381 Context context = view.getContext(); 1382 SignalClusterView signalCluster = 1383 (SignalClusterView) view.findViewById(R.id.signal_cluster); 1384 if (signalCluster != null) { 1385 ViewParent parent = signalCluster.getParent(); 1386 if (parent instanceof ViewGroup) { 1387 ViewGroup viewParent = (ViewGroup) parent; 1388 int index = viewParent.indexOfChild(signalCluster); 1389 viewParent.removeView(signalCluster); 1390 SignalClusterView newCluster = (SignalClusterView) LayoutInflater.from(context) 1391 .inflate(R.layout.signal_cluster_view, viewParent, false); 1392 ViewGroup.MarginLayoutParams layoutParams = 1393 (ViewGroup.MarginLayoutParams) viewParent.getLayoutParams(); 1394 layoutParams.setMarginsRelative( 1395 context.getResources().getDimensionPixelSize( 1396 R.dimen.signal_cluster_margin_start), 1397 0, 0, 0); 1398 newCluster.setLayoutParams(layoutParams); 1399 viewParent.addView(newCluster, index); 1400 return newCluster; 1401 } 1402 return signalCluster; 1403 } 1404 return null; 1405 } 1406 1407 private void inflateEmptyShadeView() { 1408 if (mStackScroller == null) { 1409 return; 1410 } 1411 mEmptyShadeView = (EmptyShadeView) LayoutInflater.from(mContext).inflate( 1412 R.layout.status_bar_no_notifications, mStackScroller, false); 1413 mStackScroller.setEmptyShadeView(mEmptyShadeView); 1414 } 1415 1416 private void inflateDismissView() { 1417 if (!mClearAllEnabled || mStackScroller == null) { 1418 return; 1419 } 1420 1421 mDismissView = (DismissView) LayoutInflater.from(mContext).inflate( 1422 R.layout.status_bar_notification_dismiss_all, mStackScroller, false); 1423 mDismissView.setOnButtonClickListener(new View.OnClickListener() { 1424 @Override 1425 public void onClick(View v) { 1426 mMetricsLogger.action(MetricsEvent.ACTION_DISMISS_ALL_NOTES); 1427 clearAllNotifications(); 1428 } 1429 }); 1430 mStackScroller.setDismissView(mDismissView); 1431 } 1432 1433 protected void createUserSwitcher() { 1434 mKeyguardUserSwitcher = new KeyguardUserSwitcher(mContext, 1435 (ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_user_switcher), 1436 mKeyguardStatusBar, mNotificationPanel); 1437 } 1438 1439 protected void inflateStatusBarWindow(Context context) { 1440 mStatusBarWindow = (StatusBarWindowView) View.inflate(context, 1441 R.layout.super_status_bar, null); 1442 } 1443 1444 public void clearAllNotifications() { 1445 1446 // animate-swipe all dismissable notifications, then animate the shade closed 1447 int numChildren = mStackScroller.getChildCount(); 1448 1449 final ArrayList<View> viewsToHide = new ArrayList<View>(numChildren); 1450 final ArrayList<ExpandableNotificationRow> viewsToRemove = new ArrayList<>(numChildren); 1451 for (int i = 0; i < numChildren; i++) { 1452 final View child = mStackScroller.getChildAt(i); 1453 if (child instanceof ExpandableNotificationRow) { 1454 ExpandableNotificationRow row = (ExpandableNotificationRow) child; 1455 boolean parentVisible = false; 1456 boolean hasClipBounds = child.getClipBounds(mTmpRect); 1457 if (mStackScroller.canChildBeDismissed(child)) { 1458 viewsToRemove.add(row); 1459 if (child.getVisibility() == View.VISIBLE 1460 && (!hasClipBounds || mTmpRect.height() > 0)) { 1461 viewsToHide.add(child); 1462 parentVisible = true; 1463 } 1464 } else if (child.getVisibility() == View.VISIBLE 1465 && (!hasClipBounds || mTmpRect.height() > 0)) { 1466 parentVisible = true; 1467 } 1468 List<ExpandableNotificationRow> children = row.getNotificationChildren(); 1469 if (children != null) { 1470 for (ExpandableNotificationRow childRow : children) { 1471 viewsToRemove.add(childRow); 1472 if (parentVisible && row.areChildrenExpanded() 1473 && mStackScroller.canChildBeDismissed(childRow)) { 1474 hasClipBounds = childRow.getClipBounds(mTmpRect); 1475 if (childRow.getVisibility() == View.VISIBLE 1476 && (!hasClipBounds || mTmpRect.height() > 0)) { 1477 viewsToHide.add(childRow); 1478 } 1479 } 1480 } 1481 } 1482 } 1483 } 1484 if (viewsToRemove.isEmpty()) { 1485 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE); 1486 return; 1487 } 1488 1489 addPostCollapseAction(new Runnable() { 1490 @Override 1491 public void run() { 1492 mStackScroller.setDismissAllInProgress(false); 1493 for (ExpandableNotificationRow rowToRemove : viewsToRemove) { 1494 if (mStackScroller.canChildBeDismissed(rowToRemove)) { 1495 removeNotification(rowToRemove.getEntry().key, null); 1496 } else { 1497 rowToRemove.resetTranslation(); 1498 } 1499 } 1500 try { 1501 mBarService.onClearAllNotifications(mCurrentUserId); 1502 } catch (Exception ex) { } 1503 } 1504 }); 1505 1506 performDismissAllAnimations(viewsToHide); 1507 1508 } 1509 1510 private void performDismissAllAnimations(ArrayList<View> hideAnimatedList) { 1511 Runnable animationFinishAction = new Runnable() { 1512 @Override 1513 public void run() { 1514 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE); 1515 } 1516 }; 1517 1518 // let's disable our normal animations 1519 mStackScroller.setDismissAllInProgress(true); 1520 1521 // Decrease the delay for every row we animate to give the sense of 1522 // accelerating the swipes 1523 int rowDelayDecrement = 10; 1524 int currentDelay = 140; 1525 int totalDelay = 180; 1526 int numItems = hideAnimatedList.size(); 1527 for (int i = numItems - 1; i >= 0; i--) { 1528 View view = hideAnimatedList.get(i); 1529 Runnable endRunnable = null; 1530 if (i == 0) { 1531 endRunnable = animationFinishAction; 1532 } 1533 mStackScroller.dismissViewAnimated(view, endRunnable, totalDelay, 260); 1534 currentDelay = Math.max(50, currentDelay - rowDelayDecrement); 1535 totalDelay += currentDelay; 1536 } 1537 } 1538 1539 protected void setZenMode(int mode) { 1540 // start old BaseStatusBar.setZenMode(). 1541 if (isDeviceProvisioned()) { 1542 mZenMode = mode; 1543 updateNotifications(); 1544 } 1545 // end old BaseStatusBar.setZenMode(). 1546 } 1547 1548 protected void startKeyguard() { 1549 Trace.beginSection("StatusBar#startKeyguard"); 1550 KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class); 1551 mFingerprintUnlockController = new FingerprintUnlockController(mContext, 1552 mDozeScrimController, keyguardViewMediator, 1553 mScrimController, this, UnlockMethodCache.getInstance(mContext)); 1554 mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this, 1555 getBouncerContainer(), mScrimController, 1556 mFingerprintUnlockController); 1557 mKeyguardIndicationController 1558 .setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager); 1559 mFingerprintUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager); 1560 mRemoteInputController.addCallback(mStatusBarKeyguardViewManager); 1561 1562 mRemoteInputController.addCallback(new RemoteInputController.Callback() { 1563 @Override 1564 public void onRemoteInputSent(Entry entry) { 1565 if (FORCE_REMOTE_INPUT_HISTORY && mKeysKeptForRemoteInput.contains(entry.key)) { 1566 removeNotification(entry.key, null); 1567 } else if (mRemoteInputEntriesToRemoveOnCollapse.contains(entry)) { 1568 // We're currently holding onto this notification, but from the apps point of 1569 // view it is already canceled, so we'll need to cancel it on the apps behalf 1570 // after sending - unless the app posts an update in the mean time, so wait a 1571 // bit. 1572 mHandler.postDelayed(() -> { 1573 if (mRemoteInputEntriesToRemoveOnCollapse.remove(entry)) { 1574 removeNotification(entry.key, null); 1575 } 1576 }, REMOTE_INPUT_KEPT_ENTRY_AUTO_CANCEL_DELAY); 1577 } 1578 } 1579 }); 1580 1581 mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback(); 1582 mLightBarController.setFingerprintUnlockController(mFingerprintUnlockController); 1583 Trace.endSection(); 1584 } 1585 1586 protected View getStatusBarView() { 1587 return mStatusBarView; 1588 } 1589 1590 public StatusBarWindowView getStatusBarWindow() { 1591 return mStatusBarWindow; 1592 } 1593 1594 protected ViewGroup getBouncerContainer() { 1595 return mStatusBarWindow; 1596 } 1597 1598 public int getStatusBarHeight() { 1599 if (mNaturalBarHeight < 0) { 1600 final Resources res = mContext.getResources(); 1601 mNaturalBarHeight = 1602 res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height); 1603 } 1604 return mNaturalBarHeight; 1605 } 1606 1607 protected boolean toggleSplitScreenMode(int metricsDockAction, int metricsUndockAction) { 1608 if (mRecents == null) { 1609 return false; 1610 } 1611 int dockSide = WindowManagerProxy.getInstance().getDockSide(); 1612 if (dockSide == WindowManager.DOCKED_INVALID) { 1613 return mRecents.dockTopTask(NavigationBarGestureHelper.DRAG_MODE_NONE, 1614 ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, null, metricsDockAction); 1615 } else { 1616 Divider divider = getComponent(Divider.class); 1617 if (divider != null && divider.isMinimized() && !divider.isHomeStackResizable()) { 1618 // Undocking from the minimized state is not supported 1619 return false; 1620 } else { 1621 EventBus.getDefault().send(new UndockingTaskEvent()); 1622 if (metricsUndockAction != -1) { 1623 mMetricsLogger.action(metricsUndockAction); 1624 } 1625 } 1626 } 1627 return true; 1628 } 1629 1630 void awakenDreams() { 1631 SystemServicesProxy.getInstance(mContext).awakenDreamsAsync(); 1632 } 1633 1634 public UserHandle getCurrentUserHandle() { 1635 return new UserHandle(mCurrentUserId); 1636 } 1637 1638 public void addNotification(StatusBarNotification notification, RankingMap ranking) 1639 throws InflationException { 1640 String key = notification.getKey(); 1641 if (DEBUG) Log.d(TAG, "addNotification key=" + key); 1642 1643 mNotificationData.updateRanking(ranking); 1644 Entry shadeEntry = createNotificationViews(notification); 1645 boolean isHeadsUped = shouldPeek(shadeEntry); 1646 if (!isHeadsUped && notification.getNotification().fullScreenIntent != null) { 1647 if (shouldSuppressFullScreenIntent(key)) { 1648 if (DEBUG) { 1649 Log.d(TAG, "No Fullscreen intent: suppressed by DND: " + key); 1650 } 1651 } else if (mNotificationData.getImportance(key) 1652 < NotificationManager.IMPORTANCE_HIGH) { 1653 if (DEBUG) { 1654 Log.d(TAG, "No Fullscreen intent: not important enough: " 1655 + key); 1656 } 1657 } else { 1658 // Stop screensaver if the notification has a full-screen intent. 1659 // (like an incoming phone call) 1660 awakenDreams(); 1661 1662 // not immersive & a full-screen alert should be shown 1663 if (DEBUG) 1664 Log.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent"); 1665 try { 1666 EventLog.writeEvent(EventLogTags.SYSUI_FULLSCREEN_NOTIFICATION, 1667 key); 1668 notification.getNotification().fullScreenIntent.send(); 1669 shadeEntry.notifyFullScreenIntentLaunched(); 1670 mMetricsLogger.count("note_fullscreen", 1); 1671 } catch (PendingIntent.CanceledException e) { 1672 } 1673 } 1674 } 1675 abortExistingInflation(key); 1676 1677 mForegroundServiceController.addNotification(notification, 1678 mNotificationData.getImportance(key)); 1679 1680 mPendingNotifications.put(key, shadeEntry); 1681 } 1682 1683 private void abortExistingInflation(String key) { 1684 if (mPendingNotifications.containsKey(key)) { 1685 Entry entry = mPendingNotifications.get(key); 1686 entry.abortTask(); 1687 mPendingNotifications.remove(key); 1688 } 1689 Entry addedEntry = mNotificationData.get(key); 1690 if (addedEntry != null) { 1691 addedEntry.abortTask(); 1692 } 1693 } 1694 1695 private void addEntry(Entry shadeEntry) { 1696 boolean isHeadsUped = shouldPeek(shadeEntry); 1697 if (isHeadsUped) { 1698 mHeadsUpManager.showNotification(shadeEntry); 1699 // Mark as seen immediately 1700 setNotificationShown(shadeEntry.notification); 1701 } 1702 addNotificationViews(shadeEntry); 1703 // Recalculate the position of the sliding windows and the titles. 1704 setAreThereNotifications(); 1705 } 1706 1707 @Override 1708 public void handleInflationException(StatusBarNotification notification, Exception e) { 1709 handleNotificationError(notification, e.getMessage()); 1710 } 1711 1712 @Override 1713 public void onAsyncInflationFinished(Entry entry) { 1714 mPendingNotifications.remove(entry.key); 1715 // If there was an async task started after the removal, we don't want to add it back to 1716 // the list, otherwise we might get leaks. 1717 boolean isNew = mNotificationData.get(entry.key) == null; 1718 if (isNew && !entry.row.isRemoved()) { 1719 addEntry(entry); 1720 } else if (!isNew && entry.row.hasLowPriorityStateUpdated()) { 1721 mVisualStabilityManager.onLowPriorityUpdated(entry); 1722 updateNotificationShade(); 1723 } 1724 entry.row.setLowPriorityStateUpdated(false); 1725 } 1726 1727 private boolean shouldSuppressFullScreenIntent(String key) { 1728 if (isDeviceInVrMode()) { 1729 return true; 1730 } 1731 1732 if (mPowerManager.isInteractive()) { 1733 return mNotificationData.shouldSuppressScreenOn(key); 1734 } else { 1735 return mNotificationData.shouldSuppressScreenOff(key); 1736 } 1737 } 1738 1739 protected void updateNotificationRanking(RankingMap ranking) { 1740 mNotificationData.updateRanking(ranking); 1741 updateNotifications(); 1742 } 1743 1744 public void removeNotification(String key, RankingMap ranking) { 1745 boolean deferRemoval = false; 1746 abortExistingInflation(key); 1747 if (mHeadsUpManager.isHeadsUp(key)) { 1748 // A cancel() in repsonse to a remote input shouldn't be delayed, as it makes the 1749 // sending look longer than it takes. 1750 // Also we should not defer the removal if reordering isn't allowed since otherwise 1751 // some notifications can't disappear before the panel is closed. 1752 boolean ignoreEarliestRemovalTime = mRemoteInputController.isSpinning(key) 1753 && !FORCE_REMOTE_INPUT_HISTORY 1754 || !mVisualStabilityManager.isReorderingAllowed(); 1755 deferRemoval = !mHeadsUpManager.removeNotification(key, ignoreEarliestRemovalTime); 1756 } 1757 if (key.equals(mMediaNotificationKey)) { 1758 clearCurrentMediaNotification(); 1759 updateMediaMetaData(true, true); 1760 } 1761 if (FORCE_REMOTE_INPUT_HISTORY && mRemoteInputController.isSpinning(key)) { 1762 Entry entry = mNotificationData.get(key); 1763 StatusBarNotification sbn = entry.notification; 1764 1765 Notification.Builder b = Notification.Builder 1766 .recoverBuilder(mContext, sbn.getNotification().clone()); 1767 CharSequence[] oldHistory = sbn.getNotification().extras 1768 .getCharSequenceArray(Notification.EXTRA_REMOTE_INPUT_HISTORY); 1769 CharSequence[] newHistory; 1770 if (oldHistory == null) { 1771 newHistory = new CharSequence[1]; 1772 } else { 1773 newHistory = new CharSequence[oldHistory.length + 1]; 1774 for (int i = 0; i < oldHistory.length; i++) { 1775 newHistory[i + 1] = oldHistory[i]; 1776 } 1777 } 1778 newHistory[0] = String.valueOf(entry.remoteInputText); 1779 b.setRemoteInputHistory(newHistory); 1780 1781 Notification newNotification = b.build(); 1782 1783 // Undo any compatibility view inflation 1784 newNotification.contentView = sbn.getNotification().contentView; 1785 newNotification.bigContentView = sbn.getNotification().bigContentView; 1786 newNotification.headsUpContentView = sbn.getNotification().headsUpContentView; 1787 1788 StatusBarNotification newSbn = new StatusBarNotification(sbn.getPackageName(), 1789 sbn.getOpPkg(), 1790 sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(), 1791 newNotification, sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime()); 1792 boolean updated = false; 1793 try { 1794 updateNotification(newSbn, null); 1795 updated = true; 1796 } catch (InflationException e) { 1797 deferRemoval = false; 1798 } 1799 if (updated) { 1800 mKeysKeptForRemoteInput.add(entry.key); 1801 return; 1802 } 1803 } 1804 if (deferRemoval) { 1805 mLatestRankingMap = ranking; 1806 mHeadsUpEntriesToRemoveOnSwitch.add(mHeadsUpManager.getEntry(key)); 1807 return; 1808 } 1809 Entry entry = mNotificationData.get(key); 1810 1811 if (entry != null && mRemoteInputController.isRemoteInputActive(entry) 1812 && (entry.row != null && !entry.row.isDismissed())) { 1813 mLatestRankingMap = ranking; 1814 mRemoteInputEntriesToRemoveOnCollapse.add(entry); 1815 return; 1816 } 1817 if (entry != null && mNotificationGutsExposed != null 1818 && mNotificationGutsExposed == entry.row.getGuts() && entry.row.getGuts() != null 1819 && !entry.row.getGuts().isLeavebehind()) { 1820 Log.w(TAG, "Keeping notification because it's showing guts. " + key); 1821 mLatestRankingMap = ranking; 1822 mKeyToRemoveOnGutsClosed = key; 1823 return; 1824 } 1825 1826 if (entry != null) { 1827 mForegroundServiceController.removeNotification(entry.notification); 1828 } 1829 1830 if (entry != null && entry.row != null) { 1831 entry.row.setRemoved(); 1832 mStackScroller.cleanUpViewState(entry.row); 1833 } 1834 // Let's remove the children if this was a summary 1835 handleGroupSummaryRemoved(key, ranking); 1836 StatusBarNotification old = removeNotificationViews(key, ranking); 1837 if (SPEW) Log.d(TAG, "removeNotification key=" + key + " old=" + old); 1838 1839 if (old != null) { 1840 if (CLOSE_PANEL_WHEN_EMPTIED && !hasActiveNotifications() 1841 && !mNotificationPanel.isTracking() && !mNotificationPanel.isQsExpanded()) { 1842 if (mState == StatusBarState.SHADE) { 1843 animateCollapsePanels(); 1844 } else if (mState == StatusBarState.SHADE_LOCKED && !isCollapsing()) { 1845 goToKeyguard(); 1846 } 1847 } 1848 } 1849 setAreThereNotifications(); 1850 } 1851 1852 /** 1853 * Ensures that the group children are cancelled immediately when the group summary is cancelled 1854 * instead of waiting for the notification manager to send all cancels. Otherwise this could 1855 * lead to flickers. 1856 * 1857 * This also ensures that the animation looks nice and only consists of a single disappear 1858 * animation instead of multiple. 1859 * 1860 * @param key the key of the notification was removed 1861 * @param ranking the current ranking 1862 */ 1863 private void handleGroupSummaryRemoved(String key, 1864 RankingMap ranking) { 1865 Entry entry = mNotificationData.get(key); 1866 if (entry != null && entry.row != null 1867 && entry.row.isSummaryWithChildren()) { 1868 if (entry.notification.getOverrideGroupKey() != null && !entry.row.isDismissed()) { 1869 // We don't want to remove children for autobundled notifications as they are not 1870 // always cancelled. We only remove them if they were dismissed by the user. 1871 return; 1872 } 1873 List<ExpandableNotificationRow> notificationChildren = 1874 entry.row.getNotificationChildren(); 1875 ArrayList<ExpandableNotificationRow> toRemove = new ArrayList<>(); 1876 for (int i = 0; i < notificationChildren.size(); i++) { 1877 ExpandableNotificationRow row = notificationChildren.get(i); 1878 if ((row.getStatusBarNotification().getNotification().flags 1879 & Notification.FLAG_FOREGROUND_SERVICE) != 0) { 1880 // the child is a forground service notification which we can't remove! 1881 continue; 1882 } 1883 toRemove.add(row); 1884 row.setKeepInParent(true); 1885 // we need to set this state earlier as otherwise we might generate some weird 1886 // animations 1887 row.setRemoved(); 1888 } 1889 } 1890 } 1891 1892 protected void performRemoveNotification(StatusBarNotification n) { 1893 Entry entry = mNotificationData.get(n.getKey()); 1894 if (mRemoteInputController.isRemoteInputActive(entry)) { 1895 mRemoteInputController.removeRemoteInput(entry, null); 1896 } 1897 // start old BaseStatusBar.performRemoveNotification. 1898 final String pkg = n.getPackageName(); 1899 final String tag = n.getTag(); 1900 final int id = n.getId(); 1901 final int userId = n.getUserId(); 1902 try { 1903 mBarService.onNotificationClear(pkg, tag, id, userId); 1904 if (FORCE_REMOTE_INPUT_HISTORY 1905 && mKeysKeptForRemoteInput.contains(n.getKey())) { 1906 mKeysKeptForRemoteInput.remove(n.getKey()); 1907 } 1908 removeNotification(n.getKey(), null); 1909 1910 } catch (RemoteException ex) { 1911 // system process is dead if we're here. 1912 } 1913 if (mStackScroller.hasPulsingNotifications() && mHeadsUpManager.getAllEntries().isEmpty()) { 1914 // We were showing a pulse for a notification, but no notifications are pulsing anymore. 1915 // Finish the pulse. 1916 mDozeScrimController.pulseOutNow(); 1917 } 1918 // end old BaseStatusBar.performRemoveNotification. 1919 } 1920 1921 private void updateNotificationShade() { 1922 if (mStackScroller == null) return; 1923 1924 // Do not modify the notifications during collapse. 1925 if (isCollapsing()) { 1926 addPostCollapseAction(new Runnable() { 1927 @Override 1928 public void run() { 1929 updateNotificationShade(); 1930 } 1931 }); 1932 return; 1933 } 1934 1935 ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications(); 1936 ArrayList<ExpandableNotificationRow> toShow = new ArrayList<>(activeNotifications.size()); 1937 final int N = activeNotifications.size(); 1938 for (int i=0; i<N; i++) { 1939 Entry ent = activeNotifications.get(i); 1940 if (ent.row.isDismissed() || ent.row.isRemoved()) { 1941 // we don't want to update removed notifications because they could 1942 // temporarily become children if they were isolated before. 1943 continue; 1944 } 1945 int userId = ent.notification.getUserId(); 1946 1947 // Display public version of the notification if we need to redact. 1948 boolean devicePublic = isLockscreenPublicMode(mCurrentUserId); 1949 boolean userPublic = devicePublic || isLockscreenPublicMode(userId); 1950 boolean needsRedaction = needsRedaction(ent); 1951 boolean sensitive = userPublic && needsRedaction; 1952 boolean deviceSensitive = devicePublic 1953 && !userAllowsPrivateNotificationsInPublic(mCurrentUserId); 1954 ent.row.setSensitive(sensitive, deviceSensitive); 1955 ent.row.setNeedsRedaction(needsRedaction); 1956 if (mGroupManager.isChildInGroupWithSummary(ent.row.getStatusBarNotification())) { 1957 ExpandableNotificationRow summary = mGroupManager.getGroupSummary( 1958 ent.row.getStatusBarNotification()); 1959 List<ExpandableNotificationRow> orderedChildren = 1960 mTmpChildOrderMap.get(summary); 1961 if (orderedChildren == null) { 1962 orderedChildren = new ArrayList<>(); 1963 mTmpChildOrderMap.put(summary, orderedChildren); 1964 } 1965 orderedChildren.add(ent.row); 1966 } else { 1967 toShow.add(ent.row); 1968 } 1969 1970 } 1971 1972 ArrayList<ExpandableNotificationRow> toRemove = new ArrayList<>(); 1973 for (int i=0; i< mStackScroller.getChildCount(); i++) { 1974 View child = mStackScroller.getChildAt(i); 1975 if (!toShow.contains(child) && child instanceof ExpandableNotificationRow) { 1976 toRemove.add((ExpandableNotificationRow) child); 1977 } 1978 } 1979 1980 for (ExpandableNotificationRow remove : toRemove) { 1981 if (mGroupManager.isChildInGroupWithSummary(remove.getStatusBarNotification())) { 1982 // we are only transfering this notification to its parent, don't generate an animation 1983 mStackScroller.setChildTransferInProgress(true); 1984 } 1985 if (remove.isSummaryWithChildren()) { 1986 remove.removeAllChildren(); 1987 } 1988 mStackScroller.removeView(remove); 1989 mStackScroller.setChildTransferInProgress(false); 1990 } 1991 1992 removeNotificationChildren(); 1993 1994 for (int i=0; i<toShow.size(); i++) { 1995 View v = toShow.get(i); 1996 if (v.getParent() == null) { 1997 mVisualStabilityManager.notifyViewAddition(v); 1998 mStackScroller.addView(v); 1999 } 2000 } 2001 2002 addNotificationChildrenAndSort(); 2003 2004 // So after all this work notifications still aren't sorted correctly. 2005 // Let's do that now by advancing through toShow and mStackScroller in 2006 // lock-step, making sure mStackScroller matches what we see in toShow. 2007 int j = 0; 2008 for (int i = 0; i < mStackScroller.getChildCount(); i++) { 2009 View child = mStackScroller.getChildAt(i); 2010 if (!(child instanceof ExpandableNotificationRow)) { 2011 // We don't care about non-notification views. 2012 continue; 2013 } 2014 2015 ExpandableNotificationRow targetChild = toShow.get(j); 2016 if (child != targetChild) { 2017 // Oops, wrong notification at this position. Put the right one 2018 // here and advance both lists. 2019 if (mVisualStabilityManager.canReorderNotification(targetChild)) { 2020 mStackScroller.changeViewPosition(targetChild, i); 2021 } else { 2022 mVisualStabilityManager.addReorderingAllowedCallback(this); 2023 } 2024 } 2025 j++; 2026 2027 } 2028 2029 mVisualStabilityManager.onReorderingFinished(); 2030 // clear the map again for the next usage 2031 mTmpChildOrderMap.clear(); 2032 2033 updateRowStates(); 2034 updateSpeedBumpIndex(); 2035 updateClearAll(); 2036 updateEmptyShadeView(); 2037 2038 updateQsExpansionEnabled(); 2039 2040 // Let's also update the icons 2041 mNotificationIconAreaController.updateNotificationIcons(mNotificationData); 2042 } 2043 2044 /** @return true if the entry needs redaction when on the lockscreen. */ 2045 private boolean needsRedaction(Entry ent) { 2046 int userId = ent.notification.getUserId(); 2047 2048 boolean currentUserWantsRedaction = !userAllowsPrivateNotificationsInPublic(mCurrentUserId); 2049 boolean notiUserWantsRedaction = !userAllowsPrivateNotificationsInPublic(userId); 2050 boolean redactedLockscreen = currentUserWantsRedaction || notiUserWantsRedaction; 2051 2052 boolean notificationRequestsRedaction = 2053 ent.notification.getNotification().visibility == Notification.VISIBILITY_PRIVATE; 2054 boolean userForcesRedaction = packageHasVisibilityOverride(ent.notification.getKey()); 2055 2056 return userForcesRedaction || notificationRequestsRedaction && redactedLockscreen; 2057 } 2058 2059 /** 2060 * Disable QS if device not provisioned. 2061 * If the user switcher is simple then disable QS during setup because 2062 * the user intends to use the lock screen user switcher, QS in not needed. 2063 */ 2064 private void updateQsExpansionEnabled() { 2065 mNotificationPanel.setQsExpansionEnabled(isDeviceProvisioned() 2066 && (mUserSetup || mUserSwitcherController == null 2067 || !mUserSwitcherController.isSimpleUserSwitcher()) 2068 && ((mDisabled2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) == 0) 2069 && !mDozing 2070 && !ONLY_CORE_APPS); 2071 } 2072 2073 private void addNotificationChildrenAndSort() { 2074 // Let's now add all notification children which are missing 2075 boolean orderChanged = false; 2076 for (int i = 0; i < mStackScroller.getChildCount(); i++) { 2077 View view = mStackScroller.getChildAt(i); 2078 if (!(view instanceof ExpandableNotificationRow)) { 2079 // We don't care about non-notification views. 2080 continue; 2081 } 2082 2083 ExpandableNotificationRow parent = (ExpandableNotificationRow) view; 2084 List<ExpandableNotificationRow> children = parent.getNotificationChildren(); 2085 List<ExpandableNotificationRow> orderedChildren = mTmpChildOrderMap.get(parent); 2086 2087 for (int childIndex = 0; orderedChildren != null && childIndex < orderedChildren.size(); 2088 childIndex++) { 2089 ExpandableNotificationRow childView = orderedChildren.get(childIndex); 2090 if (children == null || !children.contains(childView)) { 2091 if (childView.getParent() != null) { 2092 Log.wtf(TAG, "trying to add a notification child that already has " + 2093 "a parent. class:" + childView.getParent().getClass() + 2094 "\n child: " + childView); 2095 // This shouldn't happen. We can recover by removing it though. 2096 ((ViewGroup) childView.getParent()).removeView(childView); 2097 } 2098 mVisualStabilityManager.notifyViewAddition(childView); 2099 parent.addChildNotification(childView, childIndex); 2100 mStackScroller.notifyGroupChildAdded(childView); 2101 } 2102 } 2103 2104 // Finally after removing and adding has been beformed we can apply the order. 2105 orderChanged |= parent.applyChildOrder(orderedChildren, mVisualStabilityManager, this); 2106 } 2107 if (orderChanged) { 2108 mStackScroller.generateChildOrderChangedEvent(); 2109 } 2110 } 2111 2112 private void removeNotificationChildren() { 2113 // First let's remove all children which don't belong in the parents 2114 ArrayList<ExpandableNotificationRow> toRemove = new ArrayList<>(); 2115 for (int i = 0; i < mStackScroller.getChildCount(); i++) { 2116 View view = mStackScroller.getChildAt(i); 2117 if (!(view instanceof ExpandableNotificationRow)) { 2118 // We don't care about non-notification views. 2119 continue; 2120 } 2121 2122 ExpandableNotificationRow parent = (ExpandableNotificationRow) view; 2123 List<ExpandableNotificationRow> children = parent.getNotificationChildren(); 2124 List<ExpandableNotificationRow> orderedChildren = mTmpChildOrderMap.get(parent); 2125 2126 if (children != null) { 2127 toRemove.clear(); 2128 for (ExpandableNotificationRow childRow : children) { 2129 if ((orderedChildren == null 2130 || !orderedChildren.contains(childRow)) 2131 && !childRow.keepInParent()) { 2132 toRemove.add(childRow); 2133 } 2134 } 2135 for (ExpandableNotificationRow remove : toRemove) { 2136 parent.removeChildNotification(remove); 2137 if (mNotificationData.get(remove.getStatusBarNotification().getKey()) == null) { 2138 // We only want to add an animation if the view is completely removed 2139 // otherwise it's just a transfer 2140 mStackScroller.notifyGroupChildRemoved(remove, 2141 parent.getChildrenContainer()); 2142 } 2143 } 2144 } 2145 } 2146 } 2147 2148 public void addQsTile(ComponentName tile) { 2149 mQSPanel.getHost().addTile(tile); 2150 } 2151 2152 public void remQsTile(ComponentName tile) { 2153 mQSPanel.getHost().removeTile(tile); 2154 } 2155 2156 public void clickTile(ComponentName tile) { 2157 mQSPanel.clickTile(tile); 2158 } 2159 2160 private boolean packageHasVisibilityOverride(String key) { 2161 return mNotificationData.getVisibilityOverride(key) == Notification.VISIBILITY_PRIVATE; 2162 } 2163 2164 private void updateClearAll() { 2165 if (!mClearAllEnabled) { 2166 return; 2167 } 2168 boolean showDismissView = mState != StatusBarState.KEYGUARD 2169 && hasActiveClearableNotifications(); 2170 mStackScroller.updateDismissView(showDismissView); 2171 } 2172 2173 /** 2174 * Return whether there are any clearable notifications 2175 */ 2176 private boolean hasActiveClearableNotifications() { 2177 int childCount = mStackScroller.getChildCount(); 2178 for (int i = 0; i < childCount; i++) { 2179 View child = mStackScroller.getChildAt(i); 2180 if (!(child instanceof ExpandableNotificationRow)) { 2181 continue; 2182 } 2183 if (((ExpandableNotificationRow) child).canViewBeDismissed()) { 2184 return true; 2185 } 2186 } 2187 return false; 2188 } 2189 2190 private void updateEmptyShadeView() { 2191 boolean showEmptyShadeView = 2192 mState != StatusBarState.KEYGUARD && 2193 mNotificationData.getActiveNotifications().size() == 0; 2194 mNotificationPanel.showEmptyShadeView(showEmptyShadeView); 2195 } 2196 2197 private void updateSpeedBumpIndex() { 2198 int speedBumpIndex = 0; 2199 int currentIndex = 0; 2200 final int N = mStackScroller.getChildCount(); 2201 for (int i = 0; i < N; i++) { 2202 View view = mStackScroller.getChildAt(i); 2203 if (view.getVisibility() == View.GONE || !(view instanceof ExpandableNotificationRow)) { 2204 continue; 2205 } 2206 ExpandableNotificationRow row = (ExpandableNotificationRow) view; 2207 currentIndex++; 2208 if (!mNotificationData.isAmbient(row.getStatusBarNotification().getKey())) { 2209 speedBumpIndex = currentIndex; 2210 } 2211 } 2212 boolean noAmbient = speedBumpIndex == N; 2213 mStackScroller.updateSpeedBumpIndex(speedBumpIndex, noAmbient); 2214 } 2215 2216 public static boolean isTopLevelChild(Entry entry) { 2217 return entry.row.getParent() instanceof NotificationStackScrollLayout; 2218 } 2219 2220 protected void updateNotifications() { 2221 mNotificationData.filterAndSort(); 2222 2223 updateNotificationShade(); 2224 } 2225 2226 public void requestNotificationUpdate() { 2227 updateNotifications(); 2228 } 2229 2230 protected void setAreThereNotifications() { 2231 2232 if (SPEW) { 2233 final boolean clearable = hasActiveNotifications() && 2234 hasActiveClearableNotifications(); 2235 Log.d(TAG, "setAreThereNotifications: N=" + 2236 mNotificationData.getActiveNotifications().size() + " any=" + 2237 hasActiveNotifications() + " clearable=" + clearable); 2238 } 2239 2240 if (mStatusBarView != null) { 2241 final View nlo = mStatusBarView.findViewById(R.id.notification_lights_out); 2242 final boolean showDot = hasActiveNotifications() && !areLightsOn(); 2243 if (showDot != (nlo.getAlpha() == 1.0f)) { 2244 if (showDot) { 2245 nlo.setAlpha(0f); 2246 nlo.setVisibility(View.VISIBLE); 2247 } 2248 nlo.animate() 2249 .alpha(showDot ? 1 : 0) 2250 .setDuration(showDot ? 750 : 250) 2251 .setInterpolator(new AccelerateInterpolator(2.0f)) 2252 .setListener(showDot ? null : new AnimatorListenerAdapter() { 2253 @Override 2254 public void onAnimationEnd(Animator _a) { 2255 nlo.setVisibility(View.GONE); 2256 } 2257 }) 2258 .start(); 2259 } 2260 } 2261 2262 findAndUpdateMediaNotifications(); 2263 } 2264 2265 public void findAndUpdateMediaNotifications() { 2266 boolean metaDataChanged = false; 2267 2268 synchronized (mNotificationData) { 2269 ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications(); 2270 final int N = activeNotifications.size(); 2271 2272 // Promote the media notification with a controller in 'playing' state, if any. 2273 Entry mediaNotification = null; 2274 MediaController controller = null; 2275 for (int i = 0; i < N; i++) { 2276 final Entry entry = activeNotifications.get(i); 2277 if (isMediaNotification(entry)) { 2278 final MediaSession.Token token = 2279 entry.notification.getNotification().extras 2280 .getParcelable(Notification.EXTRA_MEDIA_SESSION); 2281 if (token != null) { 2282 MediaController aController = new MediaController(mContext, token); 2283 if (PlaybackState.STATE_PLAYING == 2284 getMediaControllerPlaybackState(aController)) { 2285 if (DEBUG_MEDIA) { 2286 Log.v(TAG, "DEBUG_MEDIA: found mediastyle controller matching " 2287 + entry.notification.getKey()); 2288 } 2289 mediaNotification = entry; 2290 controller = aController; 2291 break; 2292 } 2293 } 2294 } 2295 } 2296 if (mediaNotification == null) { 2297 // Still nothing? OK, let's just look for live media sessions and see if they match 2298 // one of our notifications. This will catch apps that aren't (yet!) using media 2299 // notifications. 2300 2301 if (mMediaSessionManager != null) { 2302 final List<MediaController> sessions 2303 = mMediaSessionManager.getActiveSessionsForUser( 2304 null, 2305 UserHandle.USER_ALL); 2306 2307 for (MediaController aController : sessions) { 2308 if (PlaybackState.STATE_PLAYING == 2309 getMediaControllerPlaybackState(aController)) { 2310 // now to see if we have one like this 2311 final String pkg = aController.getPackageName(); 2312 2313 for (int i = 0; i < N; i++) { 2314 final Entry entry = activeNotifications.get(i); 2315 if (entry.notification.getPackageName().equals(pkg)) { 2316 if (DEBUG_MEDIA) { 2317 Log.v(TAG, "DEBUG_MEDIA: found controller matching " 2318 + entry.notification.getKey()); 2319 } 2320 controller = aController; 2321 mediaNotification = entry; 2322 break; 2323 } 2324 } 2325 } 2326 } 2327 } 2328 } 2329 2330 if (controller != null && !sameSessions(mMediaController, controller)) { 2331 // We have a new media session 2332 clearCurrentMediaNotification(); 2333 mMediaController = controller; 2334 mMediaController.registerCallback(mMediaListener); 2335 mMediaMetadata = mMediaController.getMetadata(); 2336 if (DEBUG_MEDIA) { 2337 Log.v(TAG, "DEBUG_MEDIA: insert listener, receive metadata: " 2338 + mMediaMetadata); 2339 } 2340 2341 if (mediaNotification != null) { 2342 mMediaNotificationKey = mediaNotification.notification.getKey(); 2343 if (DEBUG_MEDIA) { 2344 Log.v(TAG, "DEBUG_MEDIA: Found new media notification: key=" 2345 + mMediaNotificationKey + " controller=" + mMediaController); 2346 } 2347 } 2348 metaDataChanged = true; 2349 } 2350 } 2351 2352 if (metaDataChanged) { 2353 updateNotifications(); 2354 } 2355 updateMediaMetaData(metaDataChanged, true); 2356 } 2357 2358 private int getMediaControllerPlaybackState(MediaController controller) { 2359 if (controller != null) { 2360 final PlaybackState playbackState = controller.getPlaybackState(); 2361 if (playbackState != null) { 2362 return playbackState.getState(); 2363 } 2364 } 2365 return PlaybackState.STATE_NONE; 2366 } 2367 2368 private boolean isPlaybackActive(int state) { 2369 if (state != PlaybackState.STATE_STOPPED 2370 && state != PlaybackState.STATE_ERROR 2371 && state != PlaybackState.STATE_NONE) { 2372 return true; 2373 } 2374 return false; 2375 } 2376 2377 private void clearCurrentMediaNotification() { 2378 mMediaNotificationKey = null; 2379 mMediaMetadata = null; 2380 if (mMediaController != null) { 2381 if (DEBUG_MEDIA) { 2382 Log.v(TAG, "DEBUG_MEDIA: Disconnecting from old controller: " 2383 + mMediaController.getPackageName()); 2384 } 2385 mMediaController.unregisterCallback(mMediaListener); 2386 } 2387 mMediaController = null; 2388 } 2389 2390 private boolean sameSessions(MediaController a, MediaController b) { 2391 if (a == b) return true; 2392 if (a == null) return false; 2393 return a.controlsSameSession(b); 2394 } 2395 2396 /** 2397 * Hide the album artwork that is fading out and release its bitmap. 2398 */ 2399 protected Runnable mHideBackdropFront = new Runnable() { 2400 @Override 2401 public void run() { 2402 if (DEBUG_MEDIA) { 2403 Log.v(TAG, "DEBUG_MEDIA: removing fade layer"); 2404 } 2405 mBackdropFront.setVisibility(View.INVISIBLE); 2406 mBackdropFront.animate().cancel(); 2407 mBackdropFront.setImageDrawable(null); 2408 } 2409 }; 2410 2411 /** 2412 * Refresh or remove lockscreen artwork from media metadata or the lockscreen wallpaper. 2413 */ 2414 public void updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation) { 2415 Trace.beginSection("StatusBar#updateMediaMetaData"); 2416 if (!SHOW_LOCKSCREEN_MEDIA_ARTWORK) { 2417 Trace.endSection(); 2418 return; 2419 } 2420 2421 if (mBackdrop == null) { 2422 Trace.endSection(); 2423 return; // called too early 2424 } 2425 2426 if (mLaunchTransitionFadingAway) { 2427 mBackdrop.setVisibility(View.INVISIBLE); 2428 Trace.endSection(); 2429 return; 2430 } 2431 2432 if (DEBUG_MEDIA) { 2433 Log.v(TAG, "DEBUG_MEDIA: updating album art for notification " + mMediaNotificationKey 2434 + " metadata=" + mMediaMetadata 2435 + " metaDataChanged=" + metaDataChanged 2436 + " state=" + mState); 2437 } 2438 2439 Drawable artworkDrawable = null; 2440 if (mMediaMetadata != null) { 2441 Bitmap artworkBitmap = null; 2442 artworkBitmap = mMediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ART); 2443 if (artworkBitmap == null) { 2444 artworkBitmap = mMediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART); 2445 // might still be null 2446 } 2447 if (artworkBitmap != null) { 2448 artworkDrawable = new BitmapDrawable(mBackdropBack.getResources(), artworkBitmap); 2449 } 2450 } 2451 boolean allowWhenShade = false; 2452 if (ENABLE_LOCKSCREEN_WALLPAPER && artworkDrawable == null) { 2453 Bitmap lockWallpaper = mLockscreenWallpaper.getBitmap(); 2454 if (lockWallpaper != null) { 2455 artworkDrawable = new LockscreenWallpaper.WallpaperDrawable( 2456 mBackdropBack.getResources(), lockWallpaper); 2457 // We're in the SHADE mode on the SIM screen - yet we still need to show 2458 // the lockscreen wallpaper in that mode. 2459 allowWhenShade = mStatusBarKeyguardViewManager != null 2460 && mStatusBarKeyguardViewManager.isShowing(); 2461 } 2462 } 2463 2464 boolean hideBecauseOccluded = mStatusBarKeyguardViewManager != null 2465 && mStatusBarKeyguardViewManager.isOccluded(); 2466 2467 final boolean hasArtwork = artworkDrawable != null; 2468 2469 if ((hasArtwork || DEBUG_MEDIA_FAKE_ARTWORK) 2470 && (mState != StatusBarState.SHADE || allowWhenShade) 2471 && mFingerprintUnlockController.getMode() 2472 != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING 2473 && !hideBecauseOccluded) { 2474 // time to show some art! 2475 if (mBackdrop.getVisibility() != View.VISIBLE) { 2476 mBackdrop.setVisibility(View.VISIBLE); 2477 if (allowEnterAnimation) { 2478 mBackdrop.setAlpha(SRC_MIN_ALPHA); 2479 mBackdrop.animate().alpha(1f); 2480 } else { 2481 mBackdrop.animate().cancel(); 2482 mBackdrop.setAlpha(1f); 2483 } 2484 mStatusBarWindowManager.setBackdropShowing(true); 2485 metaDataChanged = true; 2486 if (DEBUG_MEDIA) { 2487 Log.v(TAG, "DEBUG_MEDIA: Fading in album artwork"); 2488 } 2489 } 2490 if (metaDataChanged) { 2491 if (mBackdropBack.getDrawable() != null) { 2492 Drawable drawable = 2493 mBackdropBack.getDrawable().getConstantState() 2494 .newDrawable(mBackdropFront.getResources()).mutate(); 2495 mBackdropFront.setImageDrawable(drawable); 2496 if (mScrimSrcModeEnabled) { 2497 mBackdropFront.getDrawable().mutate().setXfermode(mSrcOverXferMode); 2498 } 2499 mBackdropFront.setAlpha(1f); 2500 mBackdropFront.setVisibility(View.VISIBLE); 2501 } else { 2502 mBackdropFront.setVisibility(View.INVISIBLE); 2503 } 2504 2505 if (DEBUG_MEDIA_FAKE_ARTWORK) { 2506 final int c = 0xFF000000 | (int)(Math.random() * 0xFFFFFF); 2507 Log.v(TAG, String.format("DEBUG_MEDIA: setting new color: 0x%08x", c)); 2508 mBackdropBack.setBackgroundColor(0xFFFFFFFF); 2509 mBackdropBack.setImageDrawable(new ColorDrawable(c)); 2510 } else { 2511 mBackdropBack.setImageDrawable(artworkDrawable); 2512 } 2513 if (mScrimSrcModeEnabled) { 2514 mBackdropBack.getDrawable().mutate().setXfermode(mSrcXferMode); 2515 } 2516 2517 if (mBackdropFront.getVisibility() == View.VISIBLE) { 2518 if (DEBUG_MEDIA) { 2519 Log.v(TAG, "DEBUG_MEDIA: Crossfading album artwork from " 2520 + mBackdropFront.getDrawable() 2521 + " to " 2522 + mBackdropBack.getDrawable()); 2523 } 2524 mBackdropFront.animate() 2525 .setDuration(250) 2526 .alpha(0f).withEndAction(mHideBackdropFront); 2527 } 2528 } 2529 } else { 2530 // need to hide the album art, either because we are unlocked or because 2531 // the metadata isn't there to support it 2532 if (mBackdrop.getVisibility() != View.GONE) { 2533 if (DEBUG_MEDIA) { 2534 Log.v(TAG, "DEBUG_MEDIA: Fading out album artwork"); 2535 } 2536 if (mFingerprintUnlockController.getMode() 2537 == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING 2538 || hideBecauseOccluded) { 2539 2540 // We are unlocking directly - no animation! 2541 mBackdrop.setVisibility(View.GONE); 2542 mBackdropBack.setImageDrawable(null); 2543 mStatusBarWindowManager.setBackdropShowing(false); 2544 } else { 2545 mStatusBarWindowManager.setBackdropShowing(false); 2546 mBackdrop.animate() 2547 .alpha(SRC_MIN_ALPHA) 2548 .setInterpolator(Interpolators.ACCELERATE_DECELERATE) 2549 .setDuration(300) 2550 .setStartDelay(0) 2551 .withEndAction(new Runnable() { 2552 @Override 2553 public void run() { 2554 mBackdrop.setVisibility(View.GONE); 2555 mBackdropFront.animate().cancel(); 2556 mBackdropBack.setImageDrawable(null); 2557 mHandler.post(mHideBackdropFront); 2558 } 2559 }); 2560 if (mKeyguardFadingAway) { 2561 mBackdrop.animate() 2562 // Make it disappear faster, as the focus should be on the activity 2563 // behind. 2564 .setDuration(mKeyguardFadingAwayDuration / 2) 2565 .setStartDelay(mKeyguardFadingAwayDelay) 2566 .setInterpolator(Interpolators.LINEAR) 2567 .start(); 2568 } 2569 } 2570 } 2571 } 2572 Trace.endSection(); 2573 } 2574 2575 private void updateReportRejectedTouchVisibility() { 2576 if (mReportRejectedTouch == null) { 2577 return; 2578 } 2579 mReportRejectedTouch.setVisibility(mState == StatusBarState.KEYGUARD 2580 && mFalsingManager.isReportingEnabled() ? View.VISIBLE : View.INVISIBLE); 2581 } 2582 2583 /** 2584 * State is one or more of the DISABLE constants from StatusBarManager. 2585 */ 2586 @Override 2587 public void disable(int state1, int state2, boolean animate) { 2588 animate &= mStatusBarWindowState != WINDOW_STATE_HIDDEN; 2589 mDisabledUnmodified1 = state1; 2590 mDisabledUnmodified2 = state2; 2591 final int old1 = mDisabled1; 2592 final int diff1 = state1 ^ old1; 2593 mDisabled1 = state1; 2594 2595 final int old2 = mDisabled2; 2596 final int diff2 = state2 ^ old2; 2597 mDisabled2 = state2; 2598 2599 if (DEBUG) { 2600 Log.d(TAG, String.format("disable1: 0x%08x -> 0x%08x (diff1: 0x%08x)", 2601 old1, state1, diff1)); 2602 Log.d(TAG, String.format("disable2: 0x%08x -> 0x%08x (diff2: 0x%08x)", 2603 old2, state2, diff2)); 2604 } 2605 2606 StringBuilder flagdbg = new StringBuilder(); 2607 flagdbg.append("disable<"); 2608 flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_EXPAND)) ? 'E' : 'e'); 2609 flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_EXPAND)) ? '!' : ' '); 2610 flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS)) ? 'I' : 'i'); 2611 flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS)) ? '!' : ' '); 2612 flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS)) ? 'A' : 'a'); 2613 flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS)) ? '!' : ' '); 2614 flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_SYSTEM_INFO)) ? 'S' : 's'); 2615 flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_SYSTEM_INFO)) ? '!' : ' '); 2616 flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_BACK)) ? 'B' : 'b'); 2617 flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_BACK)) ? '!' : ' '); 2618 flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_HOME)) ? 'H' : 'h'); 2619 flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_HOME)) ? '!' : ' '); 2620 flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_RECENT)) ? 'R' : 'r'); 2621 flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_RECENT)) ? '!' : ' '); 2622 flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_CLOCK)) ? 'C' : 'c'); 2623 flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_CLOCK)) ? '!' : ' '); 2624 flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_SEARCH)) ? 'S' : 's'); 2625 flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_SEARCH)) ? '!' : ' '); 2626 flagdbg.append(0 != ((state2 & StatusBarManager.DISABLE2_QUICK_SETTINGS)) ? 'Q' : 'q'); 2627 flagdbg.append(0 != ((diff2 & StatusBarManager.DISABLE2_QUICK_SETTINGS)) ? '!' : ' '); 2628 flagdbg.append('>'); 2629 Log.d(TAG, flagdbg.toString()); 2630 2631 if ((diff1 & StatusBarManager.DISABLE_EXPAND) != 0) { 2632 if ((state1 & StatusBarManager.DISABLE_EXPAND) != 0) { 2633 animateCollapsePanels(); 2634 } 2635 } 2636 2637 if ((diff1 & StatusBarManager.DISABLE_RECENT) != 0) { 2638 if ((state1 & StatusBarManager.DISABLE_RECENT) != 0) { 2639 // close recents if it's visible 2640 mHandler.removeMessages(MSG_HIDE_RECENT_APPS); 2641 mHandler.sendEmptyMessage(MSG_HIDE_RECENT_APPS); 2642 } 2643 } 2644 2645 if ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) { 2646 mDisableNotificationAlerts = 2647 (state1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0; 2648 mHeadsUpObserver.onChange(true); 2649 } 2650 2651 if ((diff2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) { 2652 updateQsExpansionEnabled(); 2653 } 2654 } 2655 2656 /** 2657 * Reapplies the disable flags as last requested by StatusBarManager. 2658 * 2659 * This needs to be called if state used by {@link #adjustDisableFlags} changes. 2660 */ 2661 public void recomputeDisableFlags(boolean animate) { 2662 mCommandQueue.recomputeDisableFlags(animate); 2663 } 2664 2665 protected H createHandler() { 2666 return new StatusBar.H(); 2667 } 2668 2669 @Override 2670 public void startActivity(Intent intent, boolean dismissShade) { 2671 startActivityDismissingKeyguard(intent, false, dismissShade); 2672 } 2673 2674 @Override 2675 public void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade) { 2676 startActivityDismissingKeyguard(intent, onlyProvisioned, dismissShade); 2677 } 2678 2679 @Override 2680 public void startActivity(Intent intent, boolean dismissShade, Callback callback) { 2681 startActivityDismissingKeyguard(intent, false, dismissShade, 2682 false /* disallowEnterPictureInPictureWhileLaunching */, callback); 2683 } 2684 2685 public void setQsExpanded(boolean expanded) { 2686 mStatusBarWindowManager.setQsExpanded(expanded); 2687 mNotificationPanel.setStatusAccessibilityImportance(expanded 2688 ? View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 2689 : View.IMPORTANT_FOR_ACCESSIBILITY_AUTO); 2690 } 2691 2692 public boolean isGoingToNotificationShade() { 2693 return mLeaveOpenOnKeyguardHide; 2694 } 2695 2696 public boolean isWakeUpComingFromTouch() { 2697 return mWakeUpComingFromTouch; 2698 } 2699 2700 public boolean isFalsingThresholdNeeded() { 2701 return getBarState() == StatusBarState.KEYGUARD; 2702 } 2703 2704 public boolean isDozing() { 2705 return mDozing; 2706 } 2707 2708 @Override // NotificationData.Environment 2709 public String getCurrentMediaNotificationKey() { 2710 return mMediaNotificationKey; 2711 } 2712 2713 public boolean isScrimSrcModeEnabled() { 2714 return mScrimSrcModeEnabled; 2715 } 2716 2717 /** 2718 * To be called when there's a state change in StatusBarKeyguardViewManager. 2719 */ 2720 public void onKeyguardViewManagerStatesUpdated() { 2721 logStateToEventlog(); 2722 } 2723 2724 @Override // UnlockMethodCache.OnUnlockMethodChangedListener 2725 public void onUnlockMethodStateChanged() { 2726 logStateToEventlog(); 2727 } 2728 2729 @Override 2730 public void onHeadsUpPinnedModeChanged(boolean inPinnedMode) { 2731 if (inPinnedMode) { 2732 mStatusBarWindowManager.setHeadsUpShowing(true); 2733 mStatusBarWindowManager.setForceStatusBarVisible(true); 2734 if (mNotificationPanel.isFullyCollapsed()) { 2735 // We need to ensure that the touchable region is updated before the window will be 2736 // resized, in order to not catch any touches. A layout will ensure that 2737 // onComputeInternalInsets will be called and after that we can resize the layout. Let's 2738 // make sure that the window stays small for one frame until the touchableRegion is set. 2739 mNotificationPanel.requestLayout(); 2740 mStatusBarWindowManager.setForceWindowCollapsed(true); 2741 mNotificationPanel.post(new Runnable() { 2742 @Override 2743 public void run() { 2744 mStatusBarWindowManager.setForceWindowCollapsed(false); 2745 } 2746 }); 2747 } 2748 } else { 2749 if (!mNotificationPanel.isFullyCollapsed() || mNotificationPanel.isTracking()) { 2750 // We are currently tracking or is open and the shade doesn't need to be kept 2751 // open artificially. 2752 mStatusBarWindowManager.setHeadsUpShowing(false); 2753 } else { 2754 // we need to keep the panel open artificially, let's wait until the animation 2755 // is finished. 2756 mHeadsUpManager.setHeadsUpGoingAway(true); 2757 mStackScroller.runAfterAnimationFinished(new Runnable() { 2758 @Override 2759 public void run() { 2760 if (!mHeadsUpManager.hasPinnedHeadsUp()) { 2761 mStatusBarWindowManager.setHeadsUpShowing(false); 2762 mHeadsUpManager.setHeadsUpGoingAway(false); 2763 } 2764 removeRemoteInputEntriesKeptUntilCollapsed(); 2765 } 2766 }); 2767 } 2768 } 2769 } 2770 2771 @Override 2772 public void onHeadsUpPinned(ExpandableNotificationRow headsUp) { 2773 dismissVolumeDialog(); 2774 } 2775 2776 @Override 2777 public void onHeadsUpUnPinned(ExpandableNotificationRow headsUp) { 2778 } 2779 2780 @Override 2781 public void onHeadsUpStateChanged(Entry entry, boolean isHeadsUp) { 2782 if (!isHeadsUp && mHeadsUpEntriesToRemoveOnSwitch.contains(entry)) { 2783 removeNotification(entry.key, mLatestRankingMap); 2784 mHeadsUpEntriesToRemoveOnSwitch.remove(entry); 2785 if (mHeadsUpEntriesToRemoveOnSwitch.isEmpty()) { 2786 mLatestRankingMap = null; 2787 } 2788 } else { 2789 updateNotificationRanking(null); 2790 if (isHeadsUp) { 2791 mDozeServiceHost.fireNotificationHeadsUp(); 2792 } 2793 } 2794 2795 } 2796 2797 protected void updateHeadsUp(String key, Entry entry, boolean shouldPeek, 2798 boolean alertAgain) { 2799 final boolean wasHeadsUp = isHeadsUp(key); 2800 if (wasHeadsUp) { 2801 if (!shouldPeek) { 2802 // We don't want this to be interrupting anymore, lets remove it 2803 mHeadsUpManager.removeNotification(key, false /* ignoreEarliestRemovalTime */); 2804 } else { 2805 mHeadsUpManager.updateNotification(entry, alertAgain); 2806 } 2807 } else if (shouldPeek && alertAgain) { 2808 // This notification was updated to be a heads-up, show it! 2809 mHeadsUpManager.showNotification(entry); 2810 } 2811 } 2812 2813 protected void setHeadsUpUser(int newUserId) { 2814 if (mHeadsUpManager != null) { 2815 mHeadsUpManager.setUser(newUserId); 2816 } 2817 } 2818 2819 public boolean isHeadsUp(String key) { 2820 return mHeadsUpManager.isHeadsUp(key); 2821 } 2822 2823 protected boolean isSnoozedPackage(StatusBarNotification sbn) { 2824 return mHeadsUpManager.isSnoozed(sbn.getPackageName()); 2825 } 2826 2827 public boolean isKeyguardCurrentlySecure() { 2828 return !mUnlockMethodCache.canSkipBouncer(); 2829 } 2830 2831 public void setPanelExpanded(boolean isExpanded) { 2832 mPanelExpanded = isExpanded; 2833 updateHideIconsForBouncer(false /* animate */); 2834 mStatusBarWindowManager.setPanelExpanded(isExpanded); 2835 mVisualStabilityManager.setPanelExpanded(isExpanded); 2836 if (isExpanded && getBarState() != StatusBarState.KEYGUARD) { 2837 if (DEBUG) { 2838 Log.v(TAG, "clearing notification effects from setPanelExpanded"); 2839 } 2840 clearNotificationEffects(); 2841 } 2842 2843 if (!isExpanded) { 2844 removeRemoteInputEntriesKeptUntilCollapsed(); 2845 } 2846 } 2847 2848 private void removeRemoteInputEntriesKeptUntilCollapsed() { 2849 for (int i = 0; i < mRemoteInputEntriesToRemoveOnCollapse.size(); i++) { 2850 Entry entry = mRemoteInputEntriesToRemoveOnCollapse.valueAt(i); 2851 mRemoteInputController.removeRemoteInput(entry, null); 2852 removeNotification(entry.key, mLatestRankingMap); 2853 } 2854 mRemoteInputEntriesToRemoveOnCollapse.clear(); 2855 } 2856 2857 public NotificationStackScrollLayout getNotificationScrollLayout() { 2858 return mStackScroller; 2859 } 2860 2861 public boolean isPulsing() { 2862 return mDozeScrimController.isPulsing(); 2863 } 2864 2865 @Override 2866 public void onReorderingAllowed() { 2867 updateNotifications(); 2868 } 2869 2870 public boolean isLaunchTransitionFadingAway() { 2871 return mLaunchTransitionFadingAway; 2872 } 2873 2874 public boolean hideStatusBarIconsWhenExpanded() { 2875 return mNotificationPanel.hideStatusBarIconsWhenExpanded(); 2876 } 2877 2878 @Override 2879 public void onColorsChanged(ColorExtractor extractor, int which) { 2880 updateTheme(); 2881 } 2882 2883 public boolean isUsingDarkTheme() { 2884 OverlayInfo themeInfo = null; 2885 try { 2886 themeInfo = mOverlayManager.getOverlayInfo("com.android.systemui.theme.dark", 2887 mCurrentUserId); 2888 } catch (RemoteException e) { 2889 e.printStackTrace(); 2890 } 2891 return themeInfo != null && themeInfo.isEnabled(); 2892 } 2893 2894 @Nullable 2895 public View getAmbientIndicationContainer() { 2896 return mAmbientIndicationContainer; 2897 } 2898 2899 public void setOccluded(boolean occluded) { 2900 mIsOccluded = occluded; 2901 updateHideIconsForBouncer(false /* animate */); 2902 } 2903 2904 public boolean hideStatusBarIconsForBouncer() { 2905 return mHideIconsForBouncer || mWereIconsJustHidden; 2906 } 2907 2908 /** 2909 * @param animate should the change of the icons be animated. 2910 */ 2911 private void updateHideIconsForBouncer(boolean animate) { 2912 boolean shouldHideIconsForBouncer = !mPanelExpanded && mTopHidesStatusBar && mIsOccluded 2913 && (mBouncerShowing || mStatusBarWindowHidden); 2914 if (mHideIconsForBouncer != shouldHideIconsForBouncer) { 2915 mHideIconsForBouncer = shouldHideIconsForBouncer; 2916 if (!shouldHideIconsForBouncer && mBouncerWasShowingWhenHidden) { 2917 // We're delaying the showing, since most of the time the fullscreen app will 2918 // hide the icons again and we don't want them to fade in and out immediately again. 2919 mWereIconsJustHidden = true; 2920 mHandler.postDelayed(() -> { 2921 mWereIconsJustHidden = false; 2922 recomputeDisableFlags(true); 2923 }, 500); 2924 } else { 2925 recomputeDisableFlags(animate); 2926 } 2927 } 2928 if (shouldHideIconsForBouncer) { 2929 mBouncerWasShowingWhenHidden = mBouncerShowing; 2930 } 2931 } 2932 2933 /** 2934 * All changes to the status bar and notifications funnel through here and are batched. 2935 */ 2936 protected class H extends Handler { 2937 @Override 2938 public void handleMessage(Message m) { 2939 switch (m.what) { 2940 case MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU: 2941 toggleKeyboardShortcuts(m.arg1); 2942 break; 2943 case MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU: 2944 dismissKeyboardShortcuts(); 2945 break; 2946 // End old BaseStatusBar.H handling. 2947 case MSG_OPEN_NOTIFICATION_PANEL: 2948 animateExpandNotificationsPanel(); 2949 break; 2950 case MSG_OPEN_SETTINGS_PANEL: 2951 animateExpandSettingsPanel((String) m.obj); 2952 break; 2953 case MSG_CLOSE_PANELS: 2954 animateCollapsePanels(); 2955 break; 2956 case MSG_LAUNCH_TRANSITION_TIMEOUT: 2957 onLaunchTransitionTimeout(); 2958 break; 2959 } 2960 } 2961 } 2962 2963 public void maybeEscalateHeadsUp() { 2964 Collection<HeadsUpManager.HeadsUpEntry> entries = mHeadsUpManager.getAllEntries(); 2965 for (HeadsUpManager.HeadsUpEntry entry : entries) { 2966 final StatusBarNotification sbn = entry.entry.notification; 2967 final Notification notification = sbn.getNotification(); 2968 if (notification.fullScreenIntent != null) { 2969 if (DEBUG) { 2970 Log.d(TAG, "converting a heads up to fullScreen"); 2971 } 2972 try { 2973 EventLog.writeEvent(EventLogTags.SYSUI_HEADS_UP_ESCALATION, 2974 sbn.getKey()); 2975 notification.fullScreenIntent.send(); 2976 entry.entry.notifyFullScreenIntentLaunched(); 2977 } catch (PendingIntent.CanceledException e) { 2978 } 2979 } 2980 } 2981 mHeadsUpManager.releaseAllImmediately(); 2982 } 2983 2984 /** 2985 * Called for system navigation gestures. First action opens the panel, second opens 2986 * settings. Down action closes the entire panel. 2987 */ 2988 @Override 2989 public void handleSystemKey(int key) { 2990 if (SPEW) Log.d(TAG, "handleNavigationKey: " + key); 2991 if (!panelsEnabled() || !mKeyguardMonitor.isDeviceInteractive() 2992 || mKeyguardMonitor.isShowing() && !mKeyguardMonitor.isOccluded()) { 2993 return; 2994 } 2995 2996 // Panels are not available in setup 2997 if (!mUserSetup) return; 2998 2999 if (KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP == key) { 3000 mMetricsLogger.action(MetricsEvent.ACTION_SYSTEM_NAVIGATION_KEY_UP); 3001 mNotificationPanel.collapse(false /* delayed */, 1.0f /* speedUpFactor */); 3002 } else if (KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN == key) { 3003 mMetricsLogger.action(MetricsEvent.ACTION_SYSTEM_NAVIGATION_KEY_DOWN); 3004 if (mNotificationPanel.isFullyCollapsed()) { 3005 mNotificationPanel.expand(true /* animate */); 3006 mMetricsLogger.count(NotificationPanelView.COUNTER_PANEL_OPEN, 1); 3007 } else if (!mNotificationPanel.isInSettings() && !mNotificationPanel.isExpanding()){ 3008 mNotificationPanel.flingSettings(0 /* velocity */, true /* expand */); 3009 mMetricsLogger.count(NotificationPanelView.COUNTER_PANEL_OPEN_QS, 1); 3010 } 3011 } 3012 3013 } 3014 3015 boolean panelsEnabled() { 3016 return (mDisabled1 & StatusBarManager.DISABLE_EXPAND) == 0 && !ONLY_CORE_APPS; 3017 } 3018 3019 void makeExpandedVisible(boolean force) { 3020 if (SPEW) Log.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible); 3021 if (!force && (mExpandedVisible || !panelsEnabled())) { 3022 return; 3023 } 3024 3025 mExpandedVisible = true; 3026 3027 // Expand the window to encompass the full screen in anticipation of the drag. 3028 // This is only possible to do atomically because the status bar is at the top of the screen! 3029 mStatusBarWindowManager.setPanelVisible(true); 3030 3031 visibilityChanged(true); 3032 mWaitingForKeyguardExit = false; 3033 recomputeDisableFlags(!force /* animate */); 3034 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true); 3035 } 3036 3037 public void animateCollapsePanels() { 3038 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE); 3039 } 3040 3041 private final Runnable mAnimateCollapsePanels = new Runnable() { 3042 @Override 3043 public void run() { 3044 animateCollapsePanels(); 3045 } 3046 }; 3047 3048 public void postAnimateCollapsePanels() { 3049 mHandler.post(mAnimateCollapsePanels); 3050 } 3051 3052 public void postAnimateForceCollapsePanels() { 3053 mHandler.post(new Runnable() { 3054 @Override 3055 public void run() { 3056 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */); 3057 } 3058 }); 3059 } 3060 3061 public void postAnimateOpenPanels() { 3062 mHandler.sendEmptyMessage(MSG_OPEN_SETTINGS_PANEL); 3063 } 3064 3065 @Override 3066 public void togglePanel() { 3067 if (mPanelExpanded) { 3068 animateCollapsePanels(); 3069 } else { 3070 animateExpandNotificationsPanel(); 3071 } 3072 } 3073 3074 @Override 3075 public void animateCollapsePanels(int flags) { 3076 animateCollapsePanels(flags, false /* force */, false /* delayed */, 3077 1.0f /* speedUpFactor */); 3078 } 3079 3080 public void animateCollapsePanels(int flags, boolean force) { 3081 animateCollapsePanels(flags, force, false /* delayed */, 1.0f /* speedUpFactor */); 3082 } 3083 3084 public void animateCollapsePanels(int flags, boolean force, boolean delayed) { 3085 animateCollapsePanels(flags, force, delayed, 1.0f /* speedUpFactor */); 3086 } 3087 3088 public void animateCollapsePanels(int flags, boolean force, boolean delayed, 3089 float speedUpFactor) { 3090 if (!force && mState != StatusBarState.SHADE) { 3091 runPostCollapseRunnables(); 3092 return; 3093 } 3094 if (SPEW) { 3095 Log.d(TAG, "animateCollapse():" 3096 + " mExpandedVisible=" + mExpandedVisible 3097 + " flags=" + flags); 3098 } 3099 3100 if ((flags & CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL) == 0) { 3101 if (!mHandler.hasMessages(MSG_HIDE_RECENT_APPS)) { 3102 mHandler.removeMessages(MSG_HIDE_RECENT_APPS); 3103 mHandler.sendEmptyMessage(MSG_HIDE_RECENT_APPS); 3104 } 3105 } 3106 3107 if (mStatusBarWindow != null && mNotificationPanel.canPanelBeCollapsed()) { 3108 // release focus immediately to kick off focus change transition 3109 mStatusBarWindowManager.setStatusBarFocusable(false); 3110 3111 mStatusBarWindow.cancelExpandHelper(); 3112 mStatusBarView.collapsePanel(true /* animate */, delayed, speedUpFactor); 3113 } 3114 } 3115 3116 private void runPostCollapseRunnables() { 3117 ArrayList<Runnable> clonedList = new ArrayList<>(mPostCollapseRunnables); 3118 mPostCollapseRunnables.clear(); 3119 int size = clonedList.size(); 3120 for (int i = 0; i < size; i++) { 3121 clonedList.get(i).run(); 3122 } 3123 mStatusBarKeyguardViewManager.readyForKeyguardDone(); 3124 } 3125 3126 @Override 3127 public void animateExpandNotificationsPanel() { 3128 if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible); 3129 if (!panelsEnabled()) { 3130 return ; 3131 } 3132 3133 mNotificationPanel.expand(true /* animate */); 3134 3135 if (false) postStartTracing(); 3136 } 3137 3138 @Override 3139 public void animateExpandSettingsPanel(String subPanel) { 3140 if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible); 3141 if (!panelsEnabled()) { 3142 return; 3143 } 3144 3145 // Settings are not available in setup 3146 if (!mUserSetup) return; 3147 3148 3149 if (subPanel != null) { 3150 mQSPanel.openDetails(subPanel); 3151 } 3152 mNotificationPanel.expandWithQs(); 3153 3154 if (false) postStartTracing(); 3155 } 3156 3157 public void animateCollapseQuickSettings() { 3158 if (mState == StatusBarState.SHADE) { 3159 mStatusBarView.collapsePanel(true, false /* delayed */, 1.0f /* speedUpFactor */); 3160 } 3161 } 3162 3163 void makeExpandedInvisible() { 3164 if (SPEW) Log.d(TAG, "makeExpandedInvisible: mExpandedVisible=" + mExpandedVisible 3165 + " mExpandedVisible=" + mExpandedVisible); 3166 3167 if (!mExpandedVisible || mStatusBarWindow == null) { 3168 return; 3169 } 3170 3171 // Ensure the panel is fully collapsed (just in case; bug 6765842, 7260868) 3172 mStatusBarView.collapsePanel(/*animate=*/ false, false /* delayed*/, 3173 1.0f /* speedUpFactor */); 3174 3175 mNotificationPanel.closeQs(); 3176 3177 mExpandedVisible = false; 3178 visibilityChanged(false); 3179 3180 // Shrink the window to the size of the status bar only 3181 mStatusBarWindowManager.setPanelVisible(false); 3182 mStatusBarWindowManager.setForceStatusBarVisible(false); 3183 3184 // Close any guts that might be visible 3185 closeAndSaveGuts(true /* removeLeavebehind */, true /* force */, true /* removeControls */, 3186 -1 /* x */, -1 /* y */, true /* resetMenu */); 3187 3188 runPostCollapseRunnables(); 3189 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false); 3190 showBouncerIfKeyguard(); 3191 recomputeDisableFlags(mNotificationPanel.hideStatusBarIconsWhenExpanded() /* animate */); 3192 3193 // Trimming will happen later if Keyguard is showing - doing it here might cause a jank in 3194 // the bouncer appear animation. 3195 if (!mStatusBarKeyguardViewManager.isShowing()) { 3196 WindowManagerGlobal.getInstance().trimMemory(ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN); 3197 } 3198 } 3199 3200 public boolean interceptTouchEvent(MotionEvent event) { 3201 if (DEBUG_GESTURES) { 3202 if (event.getActionMasked() != MotionEvent.ACTION_MOVE) { 3203 EventLog.writeEvent(EventLogTags.SYSUI_STATUSBAR_TOUCH, 3204 event.getActionMasked(), (int) event.getX(), (int) event.getY(), 3205 mDisabled1, mDisabled2); 3206 } 3207 3208 } 3209 3210 if (SPEW) { 3211 Log.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled1=" 3212 + mDisabled1 + " mDisabled2=" + mDisabled2 + " mTracking=" + mTracking); 3213 } else if (CHATTY) { 3214 if (event.getAction() != MotionEvent.ACTION_MOVE) { 3215 Log.d(TAG, String.format( 3216 "panel: %s at (%f, %f) mDisabled1=0x%08x mDisabled2=0x%08x", 3217 MotionEvent.actionToString(event.getAction()), 3218 event.getRawX(), event.getRawY(), mDisabled1, mDisabled2)); 3219 } 3220 } 3221 3222 if (DEBUG_GESTURES) { 3223 mGestureRec.add(event); 3224 } 3225 3226 if (mStatusBarWindowState == WINDOW_STATE_SHOWING) { 3227 final boolean upOrCancel = 3228 event.getAction() == MotionEvent.ACTION_UP || 3229 event.getAction() == MotionEvent.ACTION_CANCEL; 3230 if (upOrCancel && !mExpandedVisible) { 3231 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false); 3232 } else { 3233 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true); 3234 } 3235 } 3236 return false; 3237 } 3238 3239 public GestureRecorder getGestureRecorder() { 3240 return mGestureRec; 3241 } 3242 3243 public FingerprintUnlockController getFingerprintUnlockController() { 3244 return mFingerprintUnlockController; 3245 } 3246 3247 @Override // CommandQueue 3248 public void setWindowState(int window, int state) { 3249 boolean showing = state == WINDOW_STATE_SHOWING; 3250 if (mStatusBarWindow != null 3251 && window == StatusBarManager.WINDOW_STATUS_BAR 3252 && mStatusBarWindowState != state) { 3253 mStatusBarWindowState = state; 3254 if (DEBUG_WINDOW_STATE) Log.d(TAG, "Status bar " + windowStateToString(state)); 3255 if (!showing && mState == StatusBarState.SHADE) { 3256 mStatusBarView.collapsePanel(false /* animate */, false /* delayed */, 3257 1.0f /* speedUpFactor */); 3258 } 3259 if (mStatusBarView != null) { 3260 mStatusBarWindowHidden = state == WINDOW_STATE_HIDDEN; 3261 updateHideIconsForBouncer(false /* animate */); 3262 } 3263 } 3264 } 3265 3266 @Override // CommandQueue 3267 public void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis, 3268 int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) { 3269 final int oldVal = mSystemUiVisibility; 3270 final int newVal = (oldVal&~mask) | (vis&mask); 3271 final int diff = newVal ^ oldVal; 3272 if (DEBUG) Log.d(TAG, String.format( 3273 "setSystemUiVisibility vis=%s mask=%s oldVal=%s newVal=%s diff=%s", 3274 Integer.toHexString(vis), Integer.toHexString(mask), 3275 Integer.toHexString(oldVal), Integer.toHexString(newVal), 3276 Integer.toHexString(diff))); 3277 boolean sbModeChanged = false; 3278 if (diff != 0) { 3279 mSystemUiVisibility = newVal; 3280 3281 // update low profile 3282 if ((diff & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0) { 3283 setAreThereNotifications(); 3284 } 3285 3286 // ready to unhide 3287 if ((vis & View.STATUS_BAR_UNHIDE) != 0) { 3288 mSystemUiVisibility &= ~View.STATUS_BAR_UNHIDE; 3289 mNoAnimationOnNextBarModeChange = true; 3290 } 3291 3292 // update status bar mode 3293 final int sbMode = computeStatusBarMode(oldVal, newVal); 3294 3295 sbModeChanged = sbMode != -1; 3296 if (sbModeChanged && sbMode != mStatusBarMode) { 3297 if (sbMode != mStatusBarMode) { 3298 mStatusBarMode = sbMode; 3299 checkBarModes(); 3300 } 3301 touchAutoHide(); 3302 } 3303 3304 if ((vis & View.NAVIGATION_BAR_UNHIDE) != 0) { 3305 mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE; 3306 } 3307 3308 // send updated sysui visibility to window manager 3309 notifyUiVisibilityChanged(mSystemUiVisibility); 3310 } 3311 3312 mLightBarController.onSystemUiVisibilityChanged(fullscreenStackVis, dockedStackVis, 3313 mask, fullscreenStackBounds, dockedStackBounds, sbModeChanged, mStatusBarMode); 3314 } 3315 3316 void touchAutoHide() { 3317 // update transient bar autohide 3318 if (mStatusBarMode == MODE_SEMI_TRANSPARENT || (mNavigationBar != null 3319 && mNavigationBar.isSemiTransparent())) { 3320 scheduleAutohide(); 3321 } else { 3322 cancelAutohide(); 3323 } 3324 } 3325 3326 protected int computeStatusBarMode(int oldVal, int newVal) { 3327 return computeBarMode(oldVal, newVal, View.STATUS_BAR_TRANSIENT, 3328 View.STATUS_BAR_TRANSLUCENT, View.STATUS_BAR_TRANSPARENT); 3329 } 3330 3331 protected BarTransitions getStatusBarTransitions() { 3332 return mStatusBarView.getBarTransitions(); 3333 } 3334 3335 protected int computeBarMode(int oldVis, int newVis, 3336 int transientFlag, int translucentFlag, int transparentFlag) { 3337 final int oldMode = barMode(oldVis, transientFlag, translucentFlag, transparentFlag); 3338 final int newMode = barMode(newVis, transientFlag, translucentFlag, transparentFlag); 3339 if (oldMode == newMode) { 3340 return -1; // no mode change 3341 } 3342 return newMode; 3343 } 3344 3345 private int barMode(int vis, int transientFlag, int translucentFlag, int transparentFlag) { 3346 int lightsOutTransparent = View.SYSTEM_UI_FLAG_LOW_PROFILE | transparentFlag; 3347 return (vis & transientFlag) != 0 ? MODE_SEMI_TRANSPARENT 3348 : (vis & translucentFlag) != 0 ? MODE_TRANSLUCENT 3349 : (vis & lightsOutTransparent) == lightsOutTransparent ? MODE_LIGHTS_OUT_TRANSPARENT 3350 : (vis & transparentFlag) != 0 ? MODE_TRANSPARENT 3351 : (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0 ? MODE_LIGHTS_OUT 3352 : MODE_OPAQUE; 3353 } 3354 3355 void checkBarModes() { 3356 if (mDemoMode) return; 3357 if (mStatusBarView != null) checkBarMode(mStatusBarMode, mStatusBarWindowState, 3358 getStatusBarTransitions()); 3359 if (mNavigationBar != null) mNavigationBar.checkNavBarModes(); 3360 mNoAnimationOnNextBarModeChange = false; 3361 } 3362 3363 // Called by NavigationBarFragment 3364 void setQsScrimEnabled(boolean scrimEnabled) { 3365 mNotificationPanel.setQsScrimEnabled(scrimEnabled); 3366 } 3367 3368 void checkBarMode(int mode, int windowState, BarTransitions transitions) { 3369 final boolean powerSave = mBatteryController.isPowerSave(); 3370 final boolean anim = !mNoAnimationOnNextBarModeChange && mDeviceInteractive 3371 && windowState != WINDOW_STATE_HIDDEN && !powerSave; 3372 if (powerSave && getBarState() == StatusBarState.SHADE) { 3373 mode = MODE_WARNING; 3374 } 3375 transitions.transitionTo(mode, anim); 3376 } 3377 3378 private void finishBarAnimations() { 3379 if (mStatusBarView != null) { 3380 mStatusBarView.getBarTransitions().finishAnimations(); 3381 } 3382 if (mNavigationBar != null) { 3383 mNavigationBar.finishBarAnimations(); 3384 } 3385 } 3386 3387 private final Runnable mCheckBarModes = new Runnable() { 3388 @Override 3389 public void run() { 3390 checkBarModes(); 3391 } 3392 }; 3393 3394 public void setInteracting(int barWindow, boolean interacting) { 3395 final boolean changing = ((mInteractingWindows & barWindow) != 0) != interacting; 3396 mInteractingWindows = interacting 3397 ? (mInteractingWindows | barWindow) 3398 : (mInteractingWindows & ~barWindow); 3399 if (mInteractingWindows != 0) { 3400 suspendAutohide(); 3401 } else { 3402 resumeSuspendedAutohide(); 3403 } 3404 // manually dismiss the volume panel when interacting with the nav bar 3405 if (changing && interacting && barWindow == StatusBarManager.WINDOW_NAVIGATION_BAR) { 3406 touchAutoDim(); 3407 dismissVolumeDialog(); 3408 } 3409 checkBarModes(); 3410 } 3411 3412 private void dismissVolumeDialog() { 3413 if (mVolumeComponent != null) { 3414 mVolumeComponent.dismissNow(); 3415 } 3416 } 3417 3418 private void resumeSuspendedAutohide() { 3419 if (mAutohideSuspended) { 3420 scheduleAutohide(); 3421 mHandler.postDelayed(mCheckBarModes, 500); // longer than home -> launcher 3422 } 3423 } 3424 3425 private void suspendAutohide() { 3426 mHandler.removeCallbacks(mAutohide); 3427 mHandler.removeCallbacks(mCheckBarModes); 3428 mAutohideSuspended = (mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0; 3429 } 3430 3431 private void cancelAutohide() { 3432 mAutohideSuspended = false; 3433 mHandler.removeCallbacks(mAutohide); 3434 } 3435 3436 private void scheduleAutohide() { 3437 cancelAutohide(); 3438 mHandler.postDelayed(mAutohide, AUTOHIDE_TIMEOUT_MS); 3439 } 3440 3441 public void touchAutoDim() { 3442 if (mNavigationBar != null) { 3443 mNavigationBar.getBarTransitions().setAutoDim(false); 3444 } 3445 mHandler.removeCallbacks(mAutoDim); 3446 if (mState != StatusBarState.KEYGUARD && mState != StatusBarState.SHADE_LOCKED) { 3447 mHandler.postDelayed(mAutoDim, AUTOHIDE_TIMEOUT_MS); 3448 } 3449 } 3450 3451 void checkUserAutohide(View v, MotionEvent event) { 3452 if ((mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0 // a transient bar is revealed 3453 && event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar 3454 && event.getX() == 0 && event.getY() == 0 // a touch outside both bars 3455 && !mRemoteInputController.isRemoteInputActive()) { // not due to typing in IME 3456 userAutohide(); 3457 } 3458 } 3459 3460 private void checkRemoteInputOutside(MotionEvent event) { 3461 if (event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar 3462 && event.getX() == 0 && event.getY() == 0 // a touch outside both bars 3463 && mRemoteInputController.isRemoteInputActive()) { 3464 mRemoteInputController.closeRemoteInputs(); 3465 } 3466 } 3467 3468 private void userAutohide() { 3469 cancelAutohide(); 3470 mHandler.postDelayed(mAutohide, 350); // longer than app gesture -> flag clear 3471 } 3472 3473 private boolean areLightsOn() { 3474 return 0 == (mSystemUiVisibility & View.SYSTEM_UI_FLAG_LOW_PROFILE); 3475 } 3476 3477 public void setLightsOn(boolean on) { 3478 Log.v(TAG, "setLightsOn(" + on + ")"); 3479 if (on) { 3480 setSystemUiVisibility(0, 0, 0, View.SYSTEM_UI_FLAG_LOW_PROFILE, 3481 mLastFullscreenStackBounds, mLastDockedStackBounds); 3482 } else { 3483 setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE, 0, 0, 3484 View.SYSTEM_UI_FLAG_LOW_PROFILE, mLastFullscreenStackBounds, 3485 mLastDockedStackBounds); 3486 } 3487 } 3488 3489 private void notifyUiVisibilityChanged(int vis) { 3490 try { 3491 if (mLastDispatchedSystemUiVisibility != vis) { 3492 mWindowManagerService.statusBarVisibilityChanged(vis); 3493 mLastDispatchedSystemUiVisibility = vis; 3494 } 3495 } catch (RemoteException ex) { 3496 } 3497 } 3498 3499 @Override 3500 public void topAppWindowChanged(boolean showMenu) { 3501 if (SPEW) { 3502 Log.d(TAG, (showMenu?"showing":"hiding") + " the MENU button"); 3503 } 3504 3505 // See above re: lights-out policy for legacy apps. 3506 if (showMenu) setLightsOn(true); 3507 } 3508 3509 public static String viewInfo(View v) { 3510 return "[(" + v.getLeft() + "," + v.getTop() + ")(" + v.getRight() + "," + v.getBottom() 3511 + ") " + v.getWidth() + "x" + v.getHeight() + "]"; 3512 } 3513 3514 @Override 3515 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 3516 synchronized (mQueueLock) { 3517 pw.println("Current Status Bar state:"); 3518 pw.println(" mExpandedVisible=" + mExpandedVisible 3519 + ", mTrackingPosition=" + mTrackingPosition); 3520 pw.println(" mTracking=" + mTracking); 3521 pw.println(" mDisplayMetrics=" + mDisplayMetrics); 3522 pw.println(" mStackScroller: " + viewInfo(mStackScroller)); 3523 pw.println(" mStackScroller: " + viewInfo(mStackScroller) 3524 + " scroll " + mStackScroller.getScrollX() 3525 + "," + mStackScroller.getScrollY()); 3526 } 3527 pw.print(" mPendingNotifications="); 3528 if (mPendingNotifications.size() == 0) { 3529 pw.println("null"); 3530 } else { 3531 for (Entry entry : mPendingNotifications.values()) { 3532 pw.println(entry.notification); 3533 } 3534 } 3535 3536 pw.print(" mInteractingWindows="); pw.println(mInteractingWindows); 3537 pw.print(" mStatusBarWindowState="); 3538 pw.println(windowStateToString(mStatusBarWindowState)); 3539 pw.print(" mStatusBarMode="); 3540 pw.println(BarTransitions.modeToString(mStatusBarMode)); 3541 pw.print(" mDozing="); pw.println(mDozing); 3542 pw.print(" mZenMode="); 3543 pw.println(Settings.Global.zenModeToString(mZenMode)); 3544 pw.print(" mUseHeadsUp="); 3545 pw.println(mUseHeadsUp); 3546 pw.print(" mKeyToRemoveOnGutsClosed="); 3547 pw.println(mKeyToRemoveOnGutsClosed); 3548 if (mStatusBarView != null) { 3549 dumpBarTransitions(pw, "mStatusBarView", mStatusBarView.getBarTransitions()); 3550 } 3551 3552 pw.print(" mMediaSessionManager="); 3553 pw.println(mMediaSessionManager); 3554 pw.print(" mMediaNotificationKey="); 3555 pw.println(mMediaNotificationKey); 3556 pw.print(" mMediaController="); 3557 pw.print(mMediaController); 3558 if (mMediaController != null) { 3559 pw.print(" state=" + mMediaController.getPlaybackState()); 3560 } 3561 pw.println(); 3562 pw.print(" mMediaMetadata="); 3563 pw.print(mMediaMetadata); 3564 if (mMediaMetadata != null) { 3565 pw.print(" title=" + mMediaMetadata.getText(MediaMetadata.METADATA_KEY_TITLE)); 3566 } 3567 pw.println(); 3568 3569 pw.println(" Panels: "); 3570 if (mNotificationPanel != null) { 3571 pw.println(" mNotificationPanel=" + 3572 mNotificationPanel + " params=" + mNotificationPanel.getLayoutParams().debug("")); 3573 pw.print (" "); 3574 mNotificationPanel.dump(fd, pw, args); 3575 } 3576 pw.println(" mStackScroller: "); 3577 if (mStackScroller != null) { 3578 pw.print (" "); 3579 mStackScroller.dump(fd, pw, args); 3580 } 3581 pw.println(" Theme:"); 3582 if (mOverlayManager == null) { 3583 pw.println(" overlay manager not initialized!"); 3584 } else { 3585 pw.println(" dark overlay on: " + isUsingDarkTheme()); 3586 } 3587 final boolean lightWpTheme = mContext.getThemeResId() == R.style.Theme_SystemUI_Light; 3588 pw.println(" light wallpaper theme: " + lightWpTheme); 3589 3590 DozeLog.dump(pw); 3591 3592 if (mFingerprintUnlockController != null) { 3593 mFingerprintUnlockController.dump(pw); 3594 } 3595 3596 if (mScrimController != null) { 3597 mScrimController.dump(pw); 3598 } 3599 3600 if (DUMPTRUCK) { 3601 synchronized (mNotificationData) { 3602 mNotificationData.dump(pw, " "); 3603 } 3604 3605 if (false) { 3606 pw.println("see the logcat for a dump of the views we have created."); 3607 // must happen on ui thread 3608 mHandler.post(new Runnable() { 3609 @Override 3610 public void run() { 3611 mStatusBarView.getLocationOnScreen(mAbsPos); 3612 Log.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1] 3613 + ") " + mStatusBarView.getWidth() + "x" 3614 + getStatusBarHeight()); 3615 mStatusBarView.debug(); 3616 } 3617 }); 3618 } 3619 } 3620 3621 if (DEBUG_GESTURES) { 3622 pw.print(" status bar gestures: "); 3623 mGestureRec.dump(fd, pw, args); 3624 } 3625 3626 if (mHeadsUpManager != null) { 3627 mHeadsUpManager.dump(fd, pw, args); 3628 } else { 3629 pw.println(" mHeadsUpManager: null"); 3630 } 3631 if (mGroupManager != null) { 3632 mGroupManager.dump(fd, pw, args); 3633 } else { 3634 pw.println(" mGroupManager: null"); 3635 } 3636 3637 if (mLightBarController != null) { 3638 mLightBarController.dump(fd, pw, args); 3639 } 3640 3641 if (KeyguardUpdateMonitor.getInstance(mContext) != null) { 3642 KeyguardUpdateMonitor.getInstance(mContext).dump(fd, pw, args); 3643 } 3644 3645 FalsingManager.getInstance(mContext).dump(pw); 3646 FalsingLog.dump(pw); 3647 3648 pw.println("SharedPreferences:"); 3649 for (Map.Entry<String, ?> entry : Prefs.getAll(mContext).entrySet()) { 3650 pw.print(" "); pw.print(entry.getKey()); pw.print("="); pw.println(entry.getValue()); 3651 } 3652 } 3653 3654 static void dumpBarTransitions(PrintWriter pw, String var, BarTransitions transitions) { 3655 pw.print(" "); pw.print(var); pw.print(".BarTransitions.mMode="); 3656 pw.println(BarTransitions.modeToString(transitions.getMode())); 3657 } 3658 3659 public void createAndAddWindows() { 3660 addStatusBarWindow(); 3661 } 3662 3663 private void addStatusBarWindow() { 3664 makeStatusBarView(); 3665 mStatusBarWindowManager = Dependency.get(StatusBarWindowManager.class); 3666 mRemoteInputController = new RemoteInputController(mHeadsUpManager); 3667 mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight()); 3668 } 3669 3670 // called by makeStatusbar and also by PhoneStatusBarView 3671 void updateDisplaySize() { 3672 mDisplay.getMetrics(mDisplayMetrics); 3673 mDisplay.getSize(mCurrentDisplaySize); 3674 if (DEBUG_GESTURES) { 3675 mGestureRec.tag("display", 3676 String.format("%dx%d", mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels)); 3677 } 3678 } 3679 3680 float getDisplayDensity() { 3681 return mDisplayMetrics.density; 3682 } 3683 3684 public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned, 3685 boolean dismissShade) { 3686 startActivityDismissingKeyguard(intent, onlyProvisioned, dismissShade, 3687 false /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */); 3688 } 3689 3690 public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned, 3691 final boolean dismissShade, final boolean disallowEnterPictureInPictureWhileLaunching, 3692 final Callback callback) { 3693 if (onlyProvisioned && !isDeviceProvisioned()) return; 3694 3695 final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity( 3696 mContext, intent, mCurrentUserId); 3697 Runnable runnable = new Runnable() { 3698 @Override 3699 public void run() { 3700 mAssistManager.hideAssist(); 3701 intent.setFlags( 3702 Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); 3703 int result = ActivityManager.START_CANCELED; 3704 ActivityOptions options = new ActivityOptions(getActivityOptions()); 3705 options.setDisallowEnterPictureInPictureWhileLaunching( 3706 disallowEnterPictureInPictureWhileLaunching); 3707 if (intent == KeyguardBottomAreaView.INSECURE_CAMERA_INTENT) { 3708 // Normally an activity will set it's requested rotation 3709 // animation on its window. However when launching an activity 3710 // causes the orientation to change this is too late. In these cases 3711 // the default animation is used. This doesn't look good for 3712 // the camera (as it rotates the camera contents out of sync 3713 // with physical reality). So, we ask the WindowManager to 3714 // force the crossfade animation if an orientation change 3715 // happens to occur during the launch. 3716 options.setRotationAnimationHint( 3717 WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS); 3718 } 3719 try { 3720 result = ActivityManager.getService().startActivityAsUser( 3721 null, mContext.getBasePackageName(), 3722 intent, 3723 intent.resolveTypeIfNeeded(mContext.getContentResolver()), 3724 null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, 3725 options.toBundle(), UserHandle.CURRENT.getIdentifier()); 3726 } catch (RemoteException e) { 3727 Log.w(TAG, "Unable to start activity", e); 3728 } 3729 if (callback != null) { 3730 callback.onActivityStarted(result); 3731 } 3732 } 3733 }; 3734 Runnable cancelRunnable = new Runnable() { 3735 @Override 3736 public void run() { 3737 if (callback != null) { 3738 callback.onActivityStarted(ActivityManager.START_CANCELED); 3739 } 3740 } 3741 }; 3742 executeRunnableDismissingKeyguard(runnable, cancelRunnable, dismissShade, 3743 afterKeyguardGone, true /* deferred */); 3744 } 3745 3746 public void readyForKeyguardDone() { 3747 mStatusBarKeyguardViewManager.readyForKeyguardDone(); 3748 } 3749 3750 public void executeRunnableDismissingKeyguard(final Runnable runnable, 3751 final Runnable cancelAction, 3752 final boolean dismissShade, 3753 final boolean afterKeyguardGone, 3754 final boolean deferred) { 3755 dismissKeyguardThenExecute(() -> { 3756 if (runnable != null) { 3757 if (mStatusBarKeyguardViewManager.isShowing() 3758 && mStatusBarKeyguardViewManager.isOccluded()) { 3759 mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(runnable); 3760 } else { 3761 AsyncTask.execute(runnable); 3762 } 3763 } 3764 if (dismissShade) { 3765 if (mExpandedVisible) { 3766 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */, 3767 true /* delayed*/); 3768 } else { 3769 3770 // Do it after DismissAction has been processed to conserve the needed ordering. 3771 mHandler.post(this::runPostCollapseRunnables); 3772 } 3773 } else if (isInLaunchTransition() && mNotificationPanel.isLaunchTransitionFinished()) { 3774 3775 // We are not dismissing the shade, but the launch transition is already finished, 3776 // so nobody will call readyForKeyguardDone anymore. Post it such that 3777 // keyguardDonePending gets called first. 3778 mHandler.post(mStatusBarKeyguardViewManager::readyForKeyguardDone); 3779 } 3780 return deferred; 3781 }, cancelAction, afterKeyguardGone); 3782 } 3783 3784 private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 3785 @Override 3786 public void onReceive(Context context, Intent intent) { 3787 if (DEBUG) Log.v(TAG, "onReceive: " + intent); 3788 String action = intent.getAction(); 3789 if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) { 3790 KeyboardShortcuts.dismiss(); 3791 if (mRemoteInputController != null) { 3792 mRemoteInputController.closeRemoteInputs(); 3793 } 3794 if (isCurrentProfile(getSendingUserId())) { 3795 int flags = CommandQueue.FLAG_EXCLUDE_NONE; 3796 String reason = intent.getStringExtra("reason"); 3797 if (reason != null && reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) { 3798 flags |= CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL; 3799 } 3800 animateCollapsePanels(flags); 3801 } 3802 } 3803 else if (Intent.ACTION_SCREEN_OFF.equals(action)) { 3804 finishBarAnimations(); 3805 resetUserExpandedStates(); 3806 } 3807 else if (DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG.equals(action)) { 3808 mQSPanel.showDeviceMonitoringDialog(); 3809 } 3810 } 3811 }; 3812 3813 private BroadcastReceiver mDemoReceiver = new BroadcastReceiver() { 3814 @Override 3815 public void onReceive(Context context, Intent intent) { 3816 if (DEBUG) Log.v(TAG, "onReceive: " + intent); 3817 String action = intent.getAction(); 3818 if (ACTION_DEMO.equals(action)) { 3819 Bundle bundle = intent.getExtras(); 3820 if (bundle != null) { 3821 String command = bundle.getString("command", "").trim().toLowerCase(); 3822 if (command.length() > 0) { 3823 try { 3824 dispatchDemoCommand(command, bundle); 3825 } catch (Throwable t) { 3826 Log.w(TAG, "Error running demo command, intent=" + intent, t); 3827 } 3828 } 3829 } 3830 } else if (ACTION_FAKE_ARTWORK.equals(action)) { 3831 if (DEBUG_MEDIA_FAKE_ARTWORK) { 3832 updateMediaMetaData(true, true); 3833 } 3834 } 3835 } 3836 }; 3837 3838 public void resetUserExpandedStates() { 3839 ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications(); 3840 final int notificationCount = activeNotifications.size(); 3841 for (int i = 0; i < notificationCount; i++) { 3842 NotificationData.Entry entry = activeNotifications.get(i); 3843 if (entry.row != null) { 3844 entry.row.resetUserExpansion(); 3845 } 3846 } 3847 } 3848 3849 protected void dismissKeyguardThenExecute(OnDismissAction action, boolean afterKeyguardGone) { 3850 dismissKeyguardThenExecute(action, null /* cancelRunnable */, afterKeyguardGone); 3851 } 3852 3853 private void dismissKeyguardThenExecute(OnDismissAction action, Runnable cancelAction, 3854 boolean afterKeyguardGone) { 3855 if (mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_ASLEEP 3856 && mUnlockMethodCache.canSkipBouncer() 3857 && !mLeaveOpenOnKeyguardHide 3858 && isPulsing()) { 3859 // Reuse the fingerprint wake-and-unlock transition if we dismiss keyguard from a pulse. 3860 // TODO: Factor this transition out of FingerprintUnlockController. 3861 mFingerprintUnlockController.startWakeAndUnlock( 3862 FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING); 3863 } 3864 if (mStatusBarKeyguardViewManager.isShowing()) { 3865 mStatusBarKeyguardViewManager.dismissWithAction(action, cancelAction, 3866 afterKeyguardGone); 3867 } else { 3868 action.onDismiss(); 3869 } 3870 } 3871 3872 // SystemUIService notifies SystemBars of configuration changes, which then calls down here 3873 @Override 3874 public void onConfigChanged(Configuration newConfig) { 3875 updateResources(); 3876 updateDisplaySize(); // populates mDisplayMetrics 3877 3878 if (DEBUG) { 3879 Log.v(TAG, "configuration changed: " + mContext.getResources().getConfiguration()); 3880 } 3881 3882 updateRowStates(); 3883 mScreenPinningRequest.onConfigurationChanged(); 3884 } 3885 3886 public void userSwitched(int newUserId) { 3887 // Begin old BaseStatusBar.userSwitched 3888 setHeadsUpUser(newUserId); 3889 // End old BaseStatusBar.userSwitched 3890 if (MULTIUSER_DEBUG) mNotificationPanelDebugText.setText("USER " + newUserId); 3891 animateCollapsePanels(); 3892 updatePublicMode(); 3893 mNotificationData.filterAndSort(); 3894 if (mReinflateNotificationsOnUserSwitched) { 3895 updateNotificationsOnDensityOrFontScaleChanged(); 3896 mReinflateNotificationsOnUserSwitched = false; 3897 } 3898 updateNotificationShade(); 3899 clearCurrentMediaNotification(); 3900 setLockscreenUser(newUserId); 3901 } 3902 3903 protected void setLockscreenUser(int newUserId) { 3904 mLockscreenWallpaper.setCurrentUser(newUserId); 3905 mScrimController.setCurrentUser(newUserId); 3906 updateMediaMetaData(true, false); 3907 } 3908 3909 /** 3910 * Reload some of our resources when the configuration changes. 3911 * 3912 * We don't reload everything when the configuration changes -- we probably 3913 * should, but getting that smooth is tough. Someday we'll fix that. In the 3914 * meantime, just update the things that we know change. 3915 */ 3916 void updateResources() { 3917 // Update the quick setting tiles 3918 if (mQSPanel != null) { 3919 mQSPanel.updateResources(); 3920 } 3921 3922 loadDimens(); 3923 3924 if (mNotificationPanel != null) { 3925 mNotificationPanel.updateResources(); 3926 } 3927 if (mBrightnessMirrorController != null) { 3928 mBrightnessMirrorController.updateResources(); 3929 } 3930 } 3931 3932 protected void loadDimens() { 3933 final Resources res = mContext.getResources(); 3934 3935 int oldBarHeight = mNaturalBarHeight; 3936 mNaturalBarHeight = res.getDimensionPixelSize( 3937 com.android.internal.R.dimen.status_bar_height); 3938 if (mStatusBarWindowManager != null && mNaturalBarHeight != oldBarHeight) { 3939 mStatusBarWindowManager.setBarHeight(mNaturalBarHeight); 3940 } 3941 mMaxAllowedKeyguardNotifications = res.getInteger( 3942 R.integer.keyguard_max_notification_count); 3943 3944 if (DEBUG) Log.v(TAG, "defineSlots"); 3945 } 3946 3947 // Visibility reporting 3948 3949 protected void handleVisibleToUserChanged(boolean visibleToUser) { 3950 if (visibleToUser) { 3951 handleVisibleToUserChangedImpl(visibleToUser); 3952 startNotificationLogging(); 3953 } else { 3954 stopNotificationLogging(); 3955 handleVisibleToUserChangedImpl(visibleToUser); 3956 } 3957 } 3958 3959 void handlePeekToExpandTransistion() { 3960 try { 3961 // consider the transition from peek to expanded to be a panel open, 3962 // but not one that clears notification effects. 3963 int notificationLoad = mNotificationData.getActiveNotifications().size(); 3964 mBarService.onPanelRevealed(false, notificationLoad); 3965 } catch (RemoteException ex) { 3966 // Won't fail unless the world has ended. 3967 } 3968 } 3969 3970 /** 3971 * The LEDs are turned off when the notification panel is shown, even just a little bit. 3972 * See also StatusBar.setPanelExpanded for another place where we attempt to do this. 3973 */ 3974 // Old BaseStatusBar.handleVisibileToUserChanged 3975 private void handleVisibleToUserChangedImpl(boolean visibleToUser) { 3976 try { 3977 if (visibleToUser) { 3978 boolean pinnedHeadsUp = mHeadsUpManager.hasPinnedHeadsUp(); 3979 boolean clearNotificationEffects = 3980 !isPanelFullyCollapsed() && 3981 (mState == StatusBarState.SHADE || mState == StatusBarState.SHADE_LOCKED); 3982 int notificationLoad = mNotificationData.getActiveNotifications().size(); 3983 if (pinnedHeadsUp && isPanelFullyCollapsed()) { 3984 notificationLoad = 1; 3985 } 3986 mBarService.onPanelRevealed(clearNotificationEffects, notificationLoad); 3987 } else { 3988 mBarService.onPanelHidden(); 3989 } 3990 } catch (RemoteException ex) { 3991 // Won't fail unless the world has ended. 3992 } 3993 } 3994 3995 private void stopNotificationLogging() { 3996 // Report all notifications as invisible and turn down the 3997 // reporter. 3998 if (!mCurrentlyVisibleNotifications.isEmpty()) { 3999 logNotificationVisibilityChanges(Collections.<NotificationVisibility>emptyList(), 4000 mCurrentlyVisibleNotifications); 4001 recycleAllVisibilityObjects(mCurrentlyVisibleNotifications); 4002 } 4003 mHandler.removeCallbacks(mVisibilityReporter); 4004 mStackScroller.setChildLocationsChangedListener(null); 4005 } 4006 4007 private void startNotificationLogging() { 4008 mStackScroller.setChildLocationsChangedListener(mNotificationLocationsChangedListener); 4009 // Some transitions like mVisibleToUser=false -> mVisibleToUser=true don't 4010 // cause the scroller to emit child location events. Hence generate 4011 // one ourselves to guarantee that we're reporting visible 4012 // notifications. 4013 // (Note that in cases where the scroller does emit events, this 4014 // additional event doesn't break anything.) 4015 mNotificationLocationsChangedListener.onChildLocationsChanged(mStackScroller); 4016 } 4017 4018 private void logNotificationVisibilityChanges( 4019 Collection<NotificationVisibility> newlyVisible, 4020 Collection<NotificationVisibility> noLongerVisible) { 4021 if (newlyVisible.isEmpty() && noLongerVisible.isEmpty()) { 4022 return; 4023 } 4024 NotificationVisibility[] newlyVisibleAr = 4025 newlyVisible.toArray(new NotificationVisibility[newlyVisible.size()]); 4026 NotificationVisibility[] noLongerVisibleAr = 4027 noLongerVisible.toArray(new NotificationVisibility[noLongerVisible.size()]); 4028 try { 4029 mBarService.onNotificationVisibilityChanged(newlyVisibleAr, noLongerVisibleAr); 4030 } catch (RemoteException e) { 4031 // Ignore. 4032 } 4033 4034 final int N = newlyVisible.size(); 4035 if (N > 0) { 4036 String[] newlyVisibleKeyAr = new String[N]; 4037 for (int i = 0; i < N; i++) { 4038 newlyVisibleKeyAr[i] = newlyVisibleAr[i].key; 4039 } 4040 4041 setNotificationsShown(newlyVisibleKeyAr); 4042 } 4043 } 4044 4045 // State logging 4046 4047 private void logStateToEventlog() { 4048 boolean isShowing = mStatusBarKeyguardViewManager.isShowing(); 4049 boolean isOccluded = mStatusBarKeyguardViewManager.isOccluded(); 4050 boolean isBouncerShowing = mStatusBarKeyguardViewManager.isBouncerShowing(); 4051 boolean isSecure = mUnlockMethodCache.isMethodSecure(); 4052 boolean canSkipBouncer = mUnlockMethodCache.canSkipBouncer(); 4053 int stateFingerprint = getLoggingFingerprint(mState, 4054 isShowing, 4055 isOccluded, 4056 isBouncerShowing, 4057 isSecure, 4058 canSkipBouncer); 4059 if (stateFingerprint != mLastLoggedStateFingerprint) { 4060 if (mStatusBarStateLog == null) { 4061 mStatusBarStateLog = new LogMaker(MetricsEvent.VIEW_UNKNOWN); 4062 } 4063 mMetricsLogger.write(mStatusBarStateLog 4064 .setCategory(isBouncerShowing ? MetricsEvent.BOUNCER : MetricsEvent.LOCKSCREEN) 4065 .setType(isShowing ? MetricsEvent.TYPE_OPEN : MetricsEvent.TYPE_CLOSE) 4066 .setSubtype(isSecure ? 1 : 0)); 4067 EventLogTags.writeSysuiStatusBarState(mState, 4068 isShowing ? 1 : 0, 4069 isOccluded ? 1 : 0, 4070 isBouncerShowing ? 1 : 0, 4071 isSecure ? 1 : 0, 4072 canSkipBouncer ? 1 : 0); 4073 mLastLoggedStateFingerprint = stateFingerprint; 4074 } 4075 } 4076 4077 /** 4078 * Returns a fingerprint of fields logged to eventlog 4079 */ 4080 private static int getLoggingFingerprint(int statusBarState, boolean keyguardShowing, 4081 boolean keyguardOccluded, boolean bouncerShowing, boolean secure, 4082 boolean currentlyInsecure) { 4083 // Reserve 8 bits for statusBarState. We'll never go higher than 4084 // that, right? Riiiight. 4085 return (statusBarState & 0xFF) 4086 | ((keyguardShowing ? 1 : 0) << 8) 4087 | ((keyguardOccluded ? 1 : 0) << 9) 4088 | ((bouncerShowing ? 1 : 0) << 10) 4089 | ((secure ? 1 : 0) << 11) 4090 | ((currentlyInsecure ? 1 : 0) << 12); 4091 } 4092 4093 // 4094 // tracing 4095 // 4096 4097 void postStartTracing() { 4098 mHandler.postDelayed(mStartTracing, 3000); 4099 } 4100 4101 void vibrate() { 4102 android.os.Vibrator vib = (android.os.Vibrator)mContext.getSystemService( 4103 Context.VIBRATOR_SERVICE); 4104 vib.vibrate(250, VIBRATION_ATTRIBUTES); 4105 } 4106 4107 Runnable mStartTracing = new Runnable() { 4108 @Override 4109 public void run() { 4110 vibrate(); 4111 SystemClock.sleep(250); 4112 Log.d(TAG, "startTracing"); 4113 android.os.Debug.startMethodTracing("/data/statusbar-traces/trace"); 4114 mHandler.postDelayed(mStopTracing, 10000); 4115 } 4116 }; 4117 4118 Runnable mStopTracing = new Runnable() { 4119 @Override 4120 public void run() { 4121 android.os.Debug.stopMethodTracing(); 4122 Log.d(TAG, "stopTracing"); 4123 vibrate(); 4124 } 4125 }; 4126 4127 @Override 4128 public void postQSRunnableDismissingKeyguard(final Runnable runnable) { 4129 mHandler.post(() -> { 4130 mLeaveOpenOnKeyguardHide = true; 4131 executeRunnableDismissingKeyguard(() -> mHandler.post(runnable), null, false, false, 4132 false); 4133 }); 4134 } 4135 4136 @Override 4137 public void postStartActivityDismissingKeyguard(final PendingIntent intent) { 4138 mHandler.post(() -> startPendingIntentDismissingKeyguard(intent)); 4139 } 4140 4141 @Override 4142 public void postStartActivityDismissingKeyguard(final Intent intent, int delay) { 4143 mHandler.postDelayed(() -> 4144 handleStartActivityDismissingKeyguard(intent, true /*onlyProvisioned*/), delay); 4145 } 4146 4147 private void handleStartActivityDismissingKeyguard(Intent intent, boolean onlyProvisioned) { 4148 startActivityDismissingKeyguard(intent, onlyProvisioned, true /* dismissShade */); 4149 } 4150 4151 private static class FastColorDrawable extends Drawable { 4152 private final int mColor; 4153 4154 public FastColorDrawable(int color) { 4155 mColor = 0xff000000 | color; 4156 } 4157 4158 @Override 4159 public void draw(Canvas canvas) { 4160 canvas.drawColor(mColor, PorterDuff.Mode.SRC); 4161 } 4162 4163 @Override 4164 public void setAlpha(int alpha) { 4165 } 4166 4167 @Override 4168 public void setColorFilter(ColorFilter colorFilter) { 4169 } 4170 4171 @Override 4172 public int getOpacity() { 4173 return PixelFormat.OPAQUE; 4174 } 4175 4176 @Override 4177 public void setBounds(int left, int top, int right, int bottom) { 4178 } 4179 4180 @Override 4181 public void setBounds(Rect bounds) { 4182 } 4183 } 4184 4185 public void destroy() { 4186 // Begin old BaseStatusBar.destroy(). 4187 mContext.unregisterReceiver(mBaseBroadcastReceiver); 4188 try { 4189 mNotificationListener.unregisterAsSystemService(); 4190 } catch (RemoteException e) { 4191 // Ignore. 4192 } 4193 mDeviceProvisionedController.removeCallback(mDeviceProvisionedListener); 4194 // End old BaseStatusBar.destroy(). 4195 if (mStatusBarWindow != null) { 4196 mWindowManager.removeViewImmediate(mStatusBarWindow); 4197 mStatusBarWindow = null; 4198 } 4199 if (mNavigationBarView != null) { 4200 mWindowManager.removeViewImmediate(mNavigationBarView); 4201 mNavigationBarView = null; 4202 } 4203 mContext.unregisterReceiver(mBroadcastReceiver); 4204 mContext.unregisterReceiver(mDemoReceiver); 4205 mAssistManager.destroy(); 4206 4207 if (mQSPanel != null && mQSPanel.getHost() != null) { 4208 mQSPanel.getHost().destroy(); 4209 } 4210 Dependency.get(ActivityStarterDelegate.class).setActivityStarterImpl(null); 4211 mDeviceProvisionedController.removeCallback(mUserSetupObserver); 4212 Dependency.get(ConfigurationController.class).removeCallback(this); 4213 } 4214 4215 private boolean mDemoModeAllowed; 4216 private boolean mDemoMode; 4217 4218 @Override 4219 public void dispatchDemoCommand(String command, Bundle args) { 4220 if (!mDemoModeAllowed) { 4221 mDemoModeAllowed = Settings.Global.getInt(mContext.getContentResolver(), 4222 DEMO_MODE_ALLOWED, 0) != 0; 4223 } 4224 if (!mDemoModeAllowed) return; 4225 if (command.equals(COMMAND_ENTER)) { 4226 mDemoMode = true; 4227 } else if (command.equals(COMMAND_EXIT)) { 4228 mDemoMode = false; 4229 checkBarModes(); 4230 } else if (!mDemoMode) { 4231 // automatically enter demo mode on first demo command 4232 dispatchDemoCommand(COMMAND_ENTER, new Bundle()); 4233 } 4234 boolean modeChange = command.equals(COMMAND_ENTER) || command.equals(COMMAND_EXIT); 4235 if ((modeChange || command.equals(COMMAND_VOLUME)) && mVolumeComponent != null) { 4236 mVolumeComponent.dispatchDemoCommand(command, args); 4237 } 4238 if (modeChange || command.equals(COMMAND_CLOCK)) { 4239 dispatchDemoCommandToView(command, args, R.id.clock); 4240 } 4241 if (modeChange || command.equals(COMMAND_BATTERY)) { 4242 mBatteryController.dispatchDemoCommand(command, args); 4243 } 4244 if (modeChange || command.equals(COMMAND_STATUS)) { 4245 ((StatusBarIconControllerImpl) mIconController).dispatchDemoCommand(command, args); 4246 } 4247 if (mNetworkController != null && (modeChange || command.equals(COMMAND_NETWORK))) { 4248 mNetworkController.dispatchDemoCommand(command, args); 4249 } 4250 if (modeChange || command.equals(COMMAND_NOTIFICATIONS)) { 4251 View notifications = mStatusBarView == null ? null 4252 : mStatusBarView.findViewById(R.id.notification_icon_area); 4253 if (notifications != null) { 4254 String visible = args.getString("visible"); 4255 int vis = mDemoMode && "false".equals(visible) ? View.INVISIBLE : View.VISIBLE; 4256 notifications.setVisibility(vis); 4257 } 4258 } 4259 if (command.equals(COMMAND_BARS)) { 4260 String mode = args.getString("mode"); 4261 int barMode = "opaque".equals(mode) ? MODE_OPAQUE : 4262 "translucent".equals(mode) ? MODE_TRANSLUCENT : 4263 "semi-transparent".equals(mode) ? MODE_SEMI_TRANSPARENT : 4264 "transparent".equals(mode) ? MODE_TRANSPARENT : 4265 "warning".equals(mode) ? MODE_WARNING : 4266 -1; 4267 if (barMode != -1) { 4268 boolean animate = true; 4269 if (mStatusBarView != null) { 4270 mStatusBarView.getBarTransitions().transitionTo(barMode, animate); 4271 } 4272 if (mNavigationBar != null) { 4273 mNavigationBar.getBarTransitions().transitionTo(barMode, animate); 4274 } 4275 } 4276 } 4277 } 4278 4279 private void dispatchDemoCommandToView(String command, Bundle args, int id) { 4280 if (mStatusBarView == null) return; 4281 View v = mStatusBarView.findViewById(id); 4282 if (v instanceof DemoMode) { 4283 ((DemoMode)v).dispatchDemoCommand(command, args); 4284 } 4285 } 4286 4287 /** 4288 * @return The {@link StatusBarState} the status bar is in. 4289 */ 4290 public int getBarState() { 4291 return mState; 4292 } 4293 4294 public boolean isPanelFullyCollapsed() { 4295 return mNotificationPanel.isFullyCollapsed(); 4296 } 4297 4298 public void showKeyguard() { 4299 mKeyguardRequested = true; 4300 mLeaveOpenOnKeyguardHide = false; 4301 mPendingRemoteInputView = null; 4302 updateIsKeyguard(); 4303 mAssistManager.onLockscreenShown(); 4304 } 4305 4306 public boolean hideKeyguard() { 4307 mKeyguardRequested = false; 4308 return updateIsKeyguard(); 4309 } 4310 4311 private boolean updateIsKeyguard() { 4312 boolean wakeAndUnlocking = mFingerprintUnlockController.getMode() 4313 == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK; 4314 4315 // For dozing, keyguard needs to be shown whenever the device is non-interactive. Otherwise 4316 // there's no surface we can show to the user. Note that the device goes fully interactive 4317 // late in the transition, so we also allow the device to start dozing once the screen has 4318 // turned off fully. 4319 boolean keyguardForDozing = mDozingRequested && 4320 (!mDeviceInteractive || isGoingToSleep() && (isScreenFullyOff() || mIsKeyguard)); 4321 boolean shouldBeKeyguard = (mKeyguardRequested || keyguardForDozing) && !wakeAndUnlocking; 4322 if (keyguardForDozing) { 4323 updatePanelExpansionForKeyguard(); 4324 } 4325 if (shouldBeKeyguard) { 4326 if (isGoingToSleep() 4327 && mScreenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_TURNING_OFF) { 4328 // Delay showing the keyguard until screen turned off. 4329 } else { 4330 showKeyguardImpl(); 4331 } 4332 } else { 4333 return hideKeyguardImpl(); 4334 } 4335 return false; 4336 } 4337 4338 public void showKeyguardImpl() { 4339 mIsKeyguard = true; 4340 if (mLaunchTransitionFadingAway) { 4341 mNotificationPanel.animate().cancel(); 4342 onLaunchTransitionFadingEnded(); 4343 } 4344 mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT); 4345 if (mUserSwitcherController != null && mUserSwitcherController.useFullscreenUserSwitcher()) { 4346 setBarState(StatusBarState.FULLSCREEN_USER_SWITCHER); 4347 } else { 4348 setBarState(StatusBarState.KEYGUARD); 4349 } 4350 updateKeyguardState(false /* goingToFullShade */, false /* fromShadeLocked */); 4351 updatePanelExpansionForKeyguard(); 4352 if (mDraggedDownRow != null) { 4353 mDraggedDownRow.setUserLocked(false); 4354 mDraggedDownRow.notifyHeightChanged(false /* needsAnimation */); 4355 mDraggedDownRow = null; 4356 } 4357 } 4358 4359 private void updatePanelExpansionForKeyguard() { 4360 if (mState == StatusBarState.KEYGUARD && mFingerprintUnlockController.getMode() 4361 != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK) { 4362 instantExpandNotificationsPanel(); 4363 } else if (mState == StatusBarState.FULLSCREEN_USER_SWITCHER) { 4364 instantCollapseNotificationPanel(); 4365 } 4366 } 4367 4368 private void onLaunchTransitionFadingEnded() { 4369 mNotificationPanel.setAlpha(1.0f); 4370 mNotificationPanel.onAffordanceLaunchEnded(); 4371 releaseGestureWakeLock(); 4372 runLaunchTransitionEndRunnable(); 4373 mLaunchTransitionFadingAway = false; 4374 mScrimController.forceHideScrims(false /* hide */, false /* animated */); 4375 updateMediaMetaData(true /* metaDataChanged */, true); 4376 } 4377 4378 public boolean isCollapsing() { 4379 return mNotificationPanel.isCollapsing(); 4380 } 4381 4382 public void addPostCollapseAction(Runnable r) { 4383 mPostCollapseRunnables.add(r); 4384 } 4385 4386 public boolean isInLaunchTransition() { 4387 return mNotificationPanel.isLaunchTransitionRunning() 4388 || mNotificationPanel.isLaunchTransitionFinished(); 4389 } 4390 4391 /** 4392 * Fades the content of the keyguard away after the launch transition is done. 4393 * 4394 * @param beforeFading the runnable to be run when the circle is fully expanded and the fading 4395 * starts 4396 * @param endRunnable the runnable to be run when the transition is done 4397 */ 4398 public void fadeKeyguardAfterLaunchTransition(final Runnable beforeFading, 4399 Runnable endRunnable) { 4400 mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT); 4401 mLaunchTransitionEndRunnable = endRunnable; 4402 Runnable hideRunnable = new Runnable() { 4403 @Override 4404 public void run() { 4405 mLaunchTransitionFadingAway = true; 4406 if (beforeFading != null) { 4407 beforeFading.run(); 4408 } 4409 mScrimController.forceHideScrims(true /* hide */, false /* animated */); 4410 updateMediaMetaData(false, true); 4411 mNotificationPanel.setAlpha(1); 4412 mStackScroller.setParentNotFullyVisible(true); 4413 mNotificationPanel.animate() 4414 .alpha(0) 4415 .setStartDelay(FADE_KEYGUARD_START_DELAY) 4416 .setDuration(FADE_KEYGUARD_DURATION) 4417 .withLayer() 4418 .withEndAction(new Runnable() { 4419 @Override 4420 public void run() { 4421 onLaunchTransitionFadingEnded(); 4422 } 4423 }); 4424 mCommandQueue.appTransitionStarting(SystemClock.uptimeMillis(), 4425 LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true); 4426 } 4427 }; 4428 if (mNotificationPanel.isLaunchTransitionRunning()) { 4429 mNotificationPanel.setLaunchTransitionEndRunnable(hideRunnable); 4430 } else { 4431 hideRunnable.run(); 4432 } 4433 } 4434 4435 /** 4436 * Fades the content of the Keyguard while we are dozing and makes it invisible when finished 4437 * fading. 4438 */ 4439 public void fadeKeyguardWhilePulsing() { 4440 mNotificationPanel.notifyStartFading(); 4441 mNotificationPanel.animate() 4442 .alpha(0f) 4443 .setStartDelay(0) 4444 .setDuration(FADE_KEYGUARD_DURATION_PULSING) 4445 .setInterpolator(ScrimController.KEYGUARD_FADE_OUT_INTERPOLATOR) 4446 .start(); 4447 } 4448 4449 /** 4450 * Plays the animation when an activity that was occluding Keyguard goes away. 4451 */ 4452 public void animateKeyguardUnoccluding() { 4453 mScrimController.animateKeyguardUnoccluding(500); 4454 mNotificationPanel.setExpandedFraction(0f); 4455 animateExpandNotificationsPanel(); 4456 } 4457 4458 /** 4459 * Starts the timeout when we try to start the affordances on Keyguard. We usually rely that 4460 * Keyguard goes away via fadeKeyguardAfterLaunchTransition, however, that might not happen 4461 * because the launched app crashed or something else went wrong. 4462 */ 4463 public void startLaunchTransitionTimeout() { 4464 mHandler.sendEmptyMessageDelayed(MSG_LAUNCH_TRANSITION_TIMEOUT, 4465 LAUNCH_TRANSITION_TIMEOUT_MS); 4466 } 4467 4468 private void onLaunchTransitionTimeout() { 4469 Log.w(TAG, "Launch transition: Timeout!"); 4470 mNotificationPanel.onAffordanceLaunchEnded(); 4471 releaseGestureWakeLock(); 4472 mNotificationPanel.resetViews(); 4473 } 4474 4475 private void runLaunchTransitionEndRunnable() { 4476 if (mLaunchTransitionEndRunnable != null) { 4477 Runnable r = mLaunchTransitionEndRunnable; 4478 4479 // mLaunchTransitionEndRunnable might call showKeyguard, which would execute it again, 4480 // which would lead to infinite recursion. Protect against it. 4481 mLaunchTransitionEndRunnable = null; 4482 r.run(); 4483 } 4484 } 4485 4486 /** 4487 * @return true if we would like to stay in the shade, false if it should go away entirely 4488 */ 4489 public boolean hideKeyguardImpl() { 4490 mIsKeyguard = false; 4491 Trace.beginSection("StatusBar#hideKeyguard"); 4492 boolean staying = mLeaveOpenOnKeyguardHide; 4493 setBarState(StatusBarState.SHADE); 4494 View viewToClick = null; 4495 if (mLeaveOpenOnKeyguardHide) { 4496 if (!mKeyguardRequested) { 4497 mLeaveOpenOnKeyguardHide = false; 4498 } 4499 long delay = calculateGoingToFullShadeDelay(); 4500 mNotificationPanel.animateToFullShade(delay); 4501 if (mDraggedDownRow != null) { 4502 mDraggedDownRow.setUserLocked(false); 4503 mDraggedDownRow = null; 4504 } 4505 if (!mKeyguardRequested) { 4506 viewToClick = mPendingRemoteInputView; 4507 mPendingRemoteInputView = null; 4508 } 4509 4510 // Disable layout transitions in navbar for this transition because the load is just 4511 // too heavy for the CPU and GPU on any device. 4512 if (mNavigationBar != null) { 4513 mNavigationBar.disableAnimationsDuringHide(delay); 4514 } 4515 } else if (!mNotificationPanel.isCollapsing()) { 4516 instantCollapseNotificationPanel(); 4517 } 4518 updateKeyguardState(staying, false /* fromShadeLocked */); 4519 4520 if (viewToClick != null && viewToClick.isAttachedToWindow()) { 4521 viewToClick.callOnClick(); 4522 } 4523 4524 // Keyguard state has changed, but QS is not listening anymore. Make sure to update the tile 4525 // visibilities so next time we open the panel we know the correct height already. 4526 if (mQSPanel != null) { 4527 mQSPanel.refreshAllTiles(); 4528 } 4529 mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT); 4530 releaseGestureWakeLock(); 4531 mNotificationPanel.onAffordanceLaunchEnded(); 4532 mNotificationPanel.animate().cancel(); 4533 mNotificationPanel.setAlpha(1f); 4534 Trace.endSection(); 4535 return staying; 4536 } 4537 4538 private void releaseGestureWakeLock() { 4539 if (mGestureWakeLock.isHeld()) { 4540 mGestureWakeLock.release(); 4541 } 4542 } 4543 4544 public long calculateGoingToFullShadeDelay() { 4545 return mKeyguardFadingAwayDelay + mKeyguardFadingAwayDuration; 4546 } 4547 4548 /** 4549 * Notifies the status bar that Keyguard is going away very soon. 4550 */ 4551 public void keyguardGoingAway() { 4552 4553 // Treat Keyguard exit animation as an app transition to achieve nice transition for status 4554 // bar. 4555 mKeyguardGoingAway = true; 4556 mKeyguardMonitor.notifyKeyguardGoingAway(true); 4557 mCommandQueue.appTransitionPending(true); 4558 } 4559 4560 /** 4561 * Notifies the status bar the Keyguard is fading away with the specified timings. 4562 * 4563 * @param startTime the start time of the animations in uptime millis 4564 * @param delay the precalculated animation delay in miliseconds 4565 * @param fadeoutDuration the duration of the exit animation, in milliseconds 4566 */ 4567 public void setKeyguardFadingAway(long startTime, long delay, long fadeoutDuration) { 4568 mKeyguardFadingAway = true; 4569 mKeyguardFadingAwayDelay = delay; 4570 mKeyguardFadingAwayDuration = fadeoutDuration; 4571 mWaitingForKeyguardExit = false; 4572 mCommandQueue.appTransitionStarting(startTime + fadeoutDuration 4573 - LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, 4574 LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true); 4575 recomputeDisableFlags(fadeoutDuration > 0 /* animate */); 4576 mCommandQueue.appTransitionStarting( 4577 startTime - LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, 4578 LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true); 4579 mKeyguardMonitor.notifyKeyguardFadingAway(delay, fadeoutDuration); 4580 } 4581 4582 public boolean isKeyguardFadingAway() { 4583 return mKeyguardFadingAway; 4584 } 4585 4586 /** 4587 * Notifies that the Keyguard fading away animation is done. 4588 */ 4589 public void finishKeyguardFadingAway() { 4590 mKeyguardFadingAway = false; 4591 mKeyguardGoingAway = false; 4592 mKeyguardMonitor.notifyKeyguardDoneFading(); 4593 } 4594 4595 public void stopWaitingForKeyguardExit() { 4596 mWaitingForKeyguardExit = false; 4597 } 4598 4599 private void updatePublicMode() { 4600 final boolean showingKeyguard = mStatusBarKeyguardViewManager.isShowing(); 4601 final boolean devicePublic = showingKeyguard 4602 && mStatusBarKeyguardViewManager.isSecure(mCurrentUserId); 4603 4604 // Look for public mode users. Users are considered public in either case of: 4605 // - device keyguard is shown in secure mode; 4606 // - profile is locked with a work challenge. 4607 for (int i = mCurrentProfiles.size() - 1; i >= 0; i--) { 4608 final int userId = mCurrentProfiles.valueAt(i).id; 4609 boolean isProfilePublic = devicePublic; 4610 if (!devicePublic && userId != mCurrentUserId) { 4611 // We can't rely on KeyguardManager#isDeviceLocked() for unified profile challenge 4612 // due to a race condition where this code could be called before 4613 // TrustManagerService updates its internal records, resulting in an incorrect 4614 // state being cached in mLockscreenPublicMode. (b/35951989) 4615 if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId) 4616 && mStatusBarKeyguardViewManager.isSecure(userId)) { 4617 isProfilePublic = mKeyguardManager.isDeviceLocked(userId); 4618 } 4619 } 4620 setLockscreenPublicMode(isProfilePublic, userId); 4621 } 4622 } 4623 4624 protected void updateKeyguardState(boolean goingToFullShade, boolean fromShadeLocked) { 4625 Trace.beginSection("StatusBar#updateKeyguardState"); 4626 if (mState == StatusBarState.KEYGUARD) { 4627 mKeyguardIndicationController.setVisible(true); 4628 mNotificationPanel.resetViews(); 4629 if (mKeyguardUserSwitcher != null) { 4630 mKeyguardUserSwitcher.setKeyguard(true, fromShadeLocked); 4631 } 4632 if (mStatusBarView != null) mStatusBarView.removePendingHideExpandedRunnables(); 4633 if (mAmbientIndicationContainer != null) { 4634 mAmbientIndicationContainer.setVisibility(View.VISIBLE); 4635 } 4636 } else { 4637 mKeyguardIndicationController.setVisible(false); 4638 if (mKeyguardUserSwitcher != null) { 4639 mKeyguardUserSwitcher.setKeyguard(false, 4640 goingToFullShade || 4641 mState == StatusBarState.SHADE_LOCKED || 4642 fromShadeLocked); 4643 } 4644 if (mAmbientIndicationContainer != null) { 4645 mAmbientIndicationContainer.setVisibility(View.INVISIBLE); 4646 } 4647 } 4648 if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) { 4649 mScrimController.setKeyguardShowing(true); 4650 } else { 4651 mScrimController.setKeyguardShowing(false); 4652 } 4653 mNotificationPanel.setBarState(mState, mKeyguardFadingAway, goingToFullShade); 4654 updateTheme(); 4655 updateDozingState(); 4656 updatePublicMode(); 4657 updateStackScrollerState(goingToFullShade, fromShadeLocked); 4658 updateNotifications(); 4659 checkBarModes(); 4660 updateMediaMetaData(false, mState != StatusBarState.KEYGUARD); 4661 mKeyguardMonitor.notifyKeyguardState(mStatusBarKeyguardViewManager.isShowing(), 4662 mUnlockMethodCache.isMethodSecure(), 4663 mStatusBarKeyguardViewManager.isOccluded()); 4664 Trace.endSection(); 4665 } 4666 4667 /** 4668 * Switches theme from light to dark and vice-versa. 4669 */ 4670 protected void updateTheme() { 4671 final boolean inflated = mStackScroller != null; 4672 4673 // The system wallpaper defines if QS should be light or dark. 4674 WallpaperColors systemColors = mColorExtractor 4675 .getWallpaperColors(WallpaperManager.FLAG_SYSTEM); 4676 final boolean useDarkTheme = systemColors != null 4677 && (systemColors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_THEME) != 0; 4678 if (isUsingDarkTheme() != useDarkTheme) { 4679 try { 4680 mOverlayManager.setEnabled("com.android.systemui.theme.dark", 4681 useDarkTheme, mCurrentUserId); 4682 } catch (RemoteException e) { 4683 Log.w(TAG, "Can't change theme", e); 4684 } 4685 } 4686 4687 // Lock wallpaper defines the color of the majority of the views, hence we'll use it 4688 // to set our default theme. 4689 final boolean lockDarkText = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK, true 4690 /* ignoreVisibility */).supportsDarkText(); 4691 final int themeResId = lockDarkText ? R.style.Theme_SystemUI_Light : R.style.Theme_SystemUI; 4692 if (mContext.getThemeResId() != themeResId) { 4693 mContext.setTheme(themeResId); 4694 if (inflated) { 4695 reinflateViews(); 4696 } 4697 } 4698 4699 if (inflated) { 4700 int which; 4701 if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) { 4702 which = WallpaperManager.FLAG_LOCK; 4703 } else { 4704 which = WallpaperManager.FLAG_SYSTEM; 4705 } 4706 final boolean useDarkText = mColorExtractor.getColors(which, 4707 true /* ignoreVisibility */).supportsDarkText(); 4708 mStackScroller.updateDecorViews(useDarkText); 4709 4710 // Make sure we have the correct navbar/statusbar colors. 4711 mStatusBarWindowManager.setKeyguardDark(useDarkText); 4712 } 4713 } 4714 4715 private void updateDozingState() { 4716 Trace.traceCounter(Trace.TRACE_TAG_APP, "dozing", mDozing ? 1 : 0); 4717 Trace.beginSection("StatusBar#updateDozingState"); 4718 boolean animate = !mDozing && mDozeServiceHost.shouldAnimateWakeup(); 4719 mNotificationPanel.setDozing(mDozing, animate); 4720 mStackScroller.setDark(mDozing, animate, mWakeUpTouchLocation); 4721 mScrimController.setDozing(mDozing); 4722 mKeyguardIndicationController.setDozing(mDozing); 4723 mNotificationPanel.setDark(mDozing, animate); 4724 updateQsExpansionEnabled(); 4725 mDozeScrimController.setDozing(mDozing, animate); 4726 updateRowStates(); 4727 Trace.endSection(); 4728 } 4729 4730 public void updateStackScrollerState(boolean goingToFullShade, boolean fromShadeLocked) { 4731 if (mStackScroller == null) return; 4732 boolean onKeyguard = mState == StatusBarState.KEYGUARD; 4733 boolean publicMode = isAnyProfilePublicMode(); 4734 mStackScroller.setHideSensitive(publicMode, goingToFullShade); 4735 mStackScroller.setDimmed(onKeyguard, fromShadeLocked /* animate */); 4736 mStackScroller.setExpandingEnabled(!onKeyguard); 4737 ActivatableNotificationView activatedChild = mStackScroller.getActivatedChild(); 4738 mStackScroller.setActivatedChild(null); 4739 if (activatedChild != null) { 4740 activatedChild.makeInactive(false /* animate */); 4741 } 4742 } 4743 4744 public void userActivity() { 4745 if (mState == StatusBarState.KEYGUARD) { 4746 mKeyguardViewMediatorCallback.userActivity(); 4747 } 4748 } 4749 4750 public boolean interceptMediaKey(KeyEvent event) { 4751 return mState == StatusBarState.KEYGUARD 4752 && mStatusBarKeyguardViewManager.interceptMediaKey(event); 4753 } 4754 4755 protected boolean shouldUnlockOnMenuPressed() { 4756 return mDeviceInteractive && mState != StatusBarState.SHADE 4757 && mStatusBarKeyguardViewManager.shouldDismissOnMenuPressed(); 4758 } 4759 4760 public boolean onMenuPressed() { 4761 if (shouldUnlockOnMenuPressed()) { 4762 animateCollapsePanels( 4763 CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL /* flags */, true /* force */); 4764 return true; 4765 } 4766 return false; 4767 } 4768 4769 public void endAffordanceLaunch() { 4770 releaseGestureWakeLock(); 4771 mNotificationPanel.onAffordanceLaunchEnded(); 4772 } 4773 4774 public boolean onBackPressed() { 4775 if (mStatusBarKeyguardViewManager.onBackPressed()) { 4776 return true; 4777 } 4778 if (mNotificationPanel.isQsExpanded()) { 4779 if (mNotificationPanel.isQsDetailShowing()) { 4780 mNotificationPanel.closeQsDetail(); 4781 } else { 4782 mNotificationPanel.animateCloseQs(); 4783 } 4784 return true; 4785 } 4786 if (mState != StatusBarState.KEYGUARD && mState != StatusBarState.SHADE_LOCKED) { 4787 animateCollapsePanels(); 4788 return true; 4789 } 4790 if (mKeyguardUserSwitcher != null && mKeyguardUserSwitcher.hideIfNotSimple(true)) { 4791 return true; 4792 } 4793 return false; 4794 } 4795 4796 public boolean onSpacePressed() { 4797 if (mDeviceInteractive && mState != StatusBarState.SHADE) { 4798 animateCollapsePanels( 4799 CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL /* flags */, true /* force */); 4800 return true; 4801 } 4802 return false; 4803 } 4804 4805 private void showBouncerIfKeyguard() { 4806 if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) { 4807 showBouncer(); 4808 } 4809 } 4810 4811 protected void showBouncer() { 4812 mWaitingForKeyguardExit = mStatusBarKeyguardViewManager.isShowing(); 4813 mStatusBarKeyguardViewManager.dismiss(); 4814 } 4815 4816 private void instantExpandNotificationsPanel() { 4817 // Make our window larger and the panel expanded. 4818 makeExpandedVisible(true); 4819 mNotificationPanel.expand(false /* animate */); 4820 recomputeDisableFlags(false /* animate */); 4821 } 4822 4823 private void instantCollapseNotificationPanel() { 4824 mNotificationPanel.instantCollapse(); 4825 } 4826 4827 @Override 4828 public void onActivated(ActivatableNotificationView view) { 4829 onActivated((View)view); 4830 mStackScroller.setActivatedChild(view); 4831 } 4832 4833 public void onActivated(View view) { 4834 mLockscreenGestureLogger.write( 4835 MetricsEvent.ACTION_LS_NOTE, 4836 0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */); 4837 mKeyguardIndicationController.showTransientIndication(R.string.notification_tap_again); 4838 ActivatableNotificationView previousView = mStackScroller.getActivatedChild(); 4839 if (previousView != null) { 4840 previousView.makeInactive(true /* animate */); 4841 } 4842 } 4843 4844 /** 4845 * @param state The {@link StatusBarState} to set. 4846 */ 4847 public void setBarState(int state) { 4848 // If we're visible and switched to SHADE_LOCKED (the user dragged 4849 // down on the lockscreen), clear notification LED, vibration, 4850 // ringing. 4851 // Other transitions are covered in handleVisibleToUserChanged(). 4852 if (state != mState && mVisible && (state == StatusBarState.SHADE_LOCKED 4853 || (state == StatusBarState.SHADE && isGoingToNotificationShade()))) { 4854 clearNotificationEffects(); 4855 } 4856 if (state == StatusBarState.KEYGUARD) { 4857 removeRemoteInputEntriesKeptUntilCollapsed(); 4858 maybeEscalateHeadsUp(); 4859 } 4860 mState = state; 4861 mGroupManager.setStatusBarState(state); 4862 mHeadsUpManager.setStatusBarState(state); 4863 mFalsingManager.setStatusBarState(state); 4864 mStatusBarWindowManager.setStatusBarState(state); 4865 mStackScroller.setStatusBarState(state); 4866 updateReportRejectedTouchVisibility(); 4867 updateDozing(); 4868 updateTheme(); 4869 touchAutoDim(); 4870 mNotificationShelf.setStatusBarState(state); 4871 } 4872 4873 @Override 4874 public void onActivationReset(ActivatableNotificationView view) { 4875 if (view == mStackScroller.getActivatedChild()) { 4876 mStackScroller.setActivatedChild(null); 4877 onActivationReset((View)view); 4878 } 4879 } 4880 4881 public void onActivationReset(View view) { 4882 mKeyguardIndicationController.hideTransientIndication(); 4883 } 4884 4885 public void onTrackingStarted() { 4886 runPostCollapseRunnables(); 4887 } 4888 4889 public void onClosingFinished() { 4890 runPostCollapseRunnables(); 4891 if (!isPanelFullyCollapsed()) { 4892 // if we set it not to be focusable when collapsing, we have to undo it when we aborted 4893 // the closing 4894 mStatusBarWindowManager.setStatusBarFocusable(true); 4895 } 4896 } 4897 4898 public void onUnlockHintStarted() { 4899 mFalsingManager.onUnlockHintStarted(); 4900 mKeyguardIndicationController.showTransientIndication(R.string.keyguard_unlock); 4901 } 4902 4903 public void onHintFinished() { 4904 // Delay the reset a bit so the user can read the text. 4905 mKeyguardIndicationController.hideTransientIndicationDelayed(HINT_RESET_DELAY_MS); 4906 } 4907 4908 public void onCameraHintStarted() { 4909 mFalsingManager.onCameraHintStarted(); 4910 mKeyguardIndicationController.showTransientIndication(R.string.camera_hint); 4911 } 4912 4913 public void onVoiceAssistHintStarted() { 4914 mFalsingManager.onLeftAffordanceHintStarted(); 4915 mKeyguardIndicationController.showTransientIndication(R.string.voice_hint); 4916 } 4917 4918 public void onPhoneHintStarted() { 4919 mFalsingManager.onLeftAffordanceHintStarted(); 4920 mKeyguardIndicationController.showTransientIndication(R.string.phone_hint); 4921 } 4922 4923 public void onTrackingStopped(boolean expand) { 4924 if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) { 4925 if (!expand && !mUnlockMethodCache.canSkipBouncer()) { 4926 showBouncerIfKeyguard(); 4927 } 4928 } 4929 } 4930 4931 protected int getMaxKeyguardNotifications(boolean recompute) { 4932 if (recompute) { 4933 mMaxKeyguardNotifications = Math.max(1, 4934 mNotificationPanel.computeMaxKeyguardNotifications( 4935 mMaxAllowedKeyguardNotifications)); 4936 return mMaxKeyguardNotifications; 4937 } 4938 return mMaxKeyguardNotifications; 4939 } 4940 4941 public int getMaxKeyguardNotifications() { 4942 return getMaxKeyguardNotifications(false /* recompute */); 4943 } 4944 4945 // TODO: Figure out way to remove these. 4946 public NavigationBarView getNavigationBarView() { 4947 return (mNavigationBar != null ? (NavigationBarView) mNavigationBar.getView() : null); 4948 } 4949 4950 public View getNavigationBarWindow() { 4951 return mNavigationBarView; 4952 } 4953 4954 /** 4955 * TODO: Remove this method. Views should not be passed forward. Will cause theme issues. 4956 * @return bottom area view 4957 */ 4958 public KeyguardBottomAreaView getKeyguardBottomAreaView() { 4959 return mNotificationPanel.getKeyguardBottomAreaView(); 4960 } 4961 4962 // ---------------------- DragDownHelper.OnDragDownListener ------------------------------------ 4963 4964 4965 /* Only ever called as a consequence of a lockscreen expansion gesture. */ 4966 @Override 4967 public boolean onDraggedDown(View startingChild, int dragLengthY) { 4968 if (mState == StatusBarState.KEYGUARD 4969 && hasActiveNotifications() && (!isDozing() || isPulsing())) { 4970 mLockscreenGestureLogger.write( 4971 MetricsEvent.ACTION_LS_SHADE, 4972 (int) (dragLengthY / mDisplayMetrics.density), 4973 0 /* velocityDp - N/A */); 4974 4975 // We have notifications, go to locked shade. 4976 goToLockedShade(startingChild); 4977 if (startingChild instanceof ExpandableNotificationRow) { 4978 ExpandableNotificationRow row = (ExpandableNotificationRow) startingChild; 4979 row.onExpandedByGesture(true /* drag down is always an open */); 4980 } 4981 return true; 4982 } else { 4983 // abort gesture. 4984 return false; 4985 } 4986 } 4987 4988 @Override 4989 public void onDragDownReset() { 4990 mStackScroller.setDimmed(true /* dimmed */, true /* animated */); 4991 mStackScroller.resetScrollPosition(); 4992 mStackScroller.resetCheckSnoozeLeavebehind(); 4993 } 4994 4995 @Override 4996 public void onCrossedThreshold(boolean above) { 4997 mStackScroller.setDimmed(!above /* dimmed */, true /* animate */); 4998 } 4999 5000 @Override 5001 public void onTouchSlopExceeded() { 5002 mStackScroller.removeLongPressCallback(); 5003 mStackScroller.checkSnoozeLeavebehind(); 5004 } 5005 5006 @Override 5007 public void setEmptyDragAmount(float amount) { 5008 mNotificationPanel.setEmptyDragAmount(amount); 5009 } 5010 5011 @Override 5012 public boolean isFalsingCheckNeeded() { 5013 return mState == StatusBarState.KEYGUARD; 5014 } 5015 5016 /** 5017 * If secure with redaction: Show bouncer, go to unlocked shade. 5018 * 5019 * <p>If secure without redaction or no security: Go to {@link StatusBarState#SHADE_LOCKED}.</p> 5020 * 5021 * @param expandView The view to expand after going to the shade. 5022 */ 5023 public void goToLockedShade(View expandView) { 5024 int userId = mCurrentUserId; 5025 ExpandableNotificationRow row = null; 5026 if (expandView instanceof ExpandableNotificationRow) { 5027 row = (ExpandableNotificationRow) expandView; 5028 row.setUserExpanded(true /* userExpanded */, true /* allowChildExpansion */); 5029 // Indicate that the group expansion is changing at this time -- this way the group 5030 // and children backgrounds / divider animations will look correct. 5031 row.setGroupExpansionChanging(true); 5032 if (row.getStatusBarNotification() != null) { 5033 userId = row.getStatusBarNotification().getUserId(); 5034 } 5035 } 5036 boolean fullShadeNeedsBouncer = !userAllowsPrivateNotificationsInPublic(mCurrentUserId) 5037 || !mShowLockscreenNotifications || mFalsingManager.shouldEnforceBouncer(); 5038 if (isLockscreenPublicMode(userId) && fullShadeNeedsBouncer) { 5039 mLeaveOpenOnKeyguardHide = true; 5040 showBouncerIfKeyguard(); 5041 mDraggedDownRow = row; 5042 mPendingRemoteInputView = null; 5043 } else { 5044 mNotificationPanel.animateToFullShade(0 /* delay */); 5045 setBarState(StatusBarState.SHADE_LOCKED); 5046 updateKeyguardState(false /* goingToFullShade */, false /* fromShadeLocked */); 5047 } 5048 } 5049 5050 public void onLockedNotificationImportanceChange(OnDismissAction dismissAction) { 5051 mLeaveOpenOnKeyguardHide = true; 5052 dismissKeyguardThenExecute(dismissAction, true /* afterKeyguardGone */); 5053 } 5054 5055 protected void onLockedRemoteInput(ExpandableNotificationRow row, View clicked) { 5056 mLeaveOpenOnKeyguardHide = true; 5057 showBouncer(); 5058 mPendingRemoteInputView = clicked; 5059 } 5060 5061 protected void onMakeExpandedVisibleForRemoteInput(ExpandableNotificationRow row, 5062 View clickedView) { 5063 if (isKeyguardShowing()) { 5064 onLockedRemoteInput(row, clickedView); 5065 } else { 5066 row.setUserExpanded(true); 5067 row.getPrivateLayout().setOnExpandedVisibleListener(clickedView::performClick); 5068 } 5069 } 5070 5071 protected boolean startWorkChallengeIfNecessary(int userId, IntentSender intendSender, 5072 String notificationKey) { 5073 // Clear pending remote view, as we do not want to trigger pending remote input view when 5074 // it's called by other code 5075 mPendingWorkRemoteInputView = null; 5076 // Begin old BaseStatusBar.startWorkChallengeIfNecessary. 5077 final Intent newIntent = mKeyguardManager.createConfirmDeviceCredentialIntent(null, 5078 null, userId); 5079 if (newIntent == null) { 5080 return false; 5081 } 5082 final Intent callBackIntent = new Intent(NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION); 5083 callBackIntent.putExtra(Intent.EXTRA_INTENT, intendSender); 5084 callBackIntent.putExtra(Intent.EXTRA_INDEX, notificationKey); 5085 callBackIntent.setPackage(mContext.getPackageName()); 5086 5087 PendingIntent callBackPendingIntent = PendingIntent.getBroadcast( 5088 mContext, 5089 0, 5090 callBackIntent, 5091 PendingIntent.FLAG_CANCEL_CURRENT | 5092 PendingIntent.FLAG_ONE_SHOT | 5093 PendingIntent.FLAG_IMMUTABLE); 5094 newIntent.putExtra( 5095 Intent.EXTRA_INTENT, 5096 callBackPendingIntent.getIntentSender()); 5097 try { 5098 ActivityManager.getService().startConfirmDeviceCredentialIntent(newIntent, 5099 null /*options*/); 5100 } catch (RemoteException ex) { 5101 // ignore 5102 } 5103 return true; 5104 // End old BaseStatusBar.startWorkChallengeIfNecessary. 5105 } 5106 5107 protected void onLockedWorkRemoteInput(int userId, ExpandableNotificationRow row, 5108 View clicked) { 5109 // Collapse notification and show work challenge 5110 animateCollapsePanels(); 5111 startWorkChallengeIfNecessary(userId, null, null); 5112 // Add pending remote input view after starting work challenge, as starting work challenge 5113 // will clear all previous pending review view 5114 mPendingWorkRemoteInputView = clicked; 5115 } 5116 5117 private boolean isAnyProfilePublicMode() { 5118 for (int i = mCurrentProfiles.size() - 1; i >= 0; i--) { 5119 if (isLockscreenPublicMode(mCurrentProfiles.valueAt(i).id)) { 5120 return true; 5121 } 5122 } 5123 return false; 5124 } 5125 5126 protected void onWorkChallengeChanged() { 5127 updatePublicMode(); 5128 updateNotifications(); 5129 if (mPendingWorkRemoteInputView != null && !isAnyProfilePublicMode()) { 5130 // Expand notification panel and the notification row, then click on remote input view 5131 final Runnable clickPendingViewRunnable = new Runnable() { 5132 @Override 5133 public void run() { 5134 final View pendingWorkRemoteInputView = mPendingWorkRemoteInputView; 5135 if (pendingWorkRemoteInputView == null) { 5136 return; 5137 } 5138 5139 // Climb up the hierarchy until we get to the container for this row. 5140 ViewParent p = pendingWorkRemoteInputView.getParent(); 5141 while (!(p instanceof ExpandableNotificationRow)) { 5142 if (p == null) { 5143 return; 5144 } 5145 p = p.getParent(); 5146 } 5147 5148 final ExpandableNotificationRow row = (ExpandableNotificationRow) p; 5149 ViewParent viewParent = row.getParent(); 5150 if (viewParent instanceof NotificationStackScrollLayout) { 5151 final NotificationStackScrollLayout scrollLayout = 5152 (NotificationStackScrollLayout) viewParent; 5153 row.makeActionsVisibile(); 5154 row.post(new Runnable() { 5155 @Override 5156 public void run() { 5157 final Runnable finishScrollingCallback = new Runnable() { 5158 @Override 5159 public void run() { 5160 mPendingWorkRemoteInputView.callOnClick(); 5161 mPendingWorkRemoteInputView = null; 5162 scrollLayout.setFinishScrollingCallback(null); 5163 } 5164 }; 5165 if (scrollLayout.scrollTo(row)) { 5166 // It scrolls! So call it when it's finished. 5167 scrollLayout.setFinishScrollingCallback( 5168 finishScrollingCallback); 5169 } else { 5170 // It does not scroll, so call it now! 5171 finishScrollingCallback.run(); 5172 } 5173 } 5174 }); 5175 } 5176 } 5177 }; 5178 mNotificationPanel.getViewTreeObserver().addOnGlobalLayoutListener( 5179 new ViewTreeObserver.OnGlobalLayoutListener() { 5180 @Override 5181 public void onGlobalLayout() { 5182 if (mNotificationPanel.mStatusBar.getStatusBarWindow() 5183 .getHeight() != mNotificationPanel.mStatusBar 5184 .getStatusBarHeight()) { 5185 mNotificationPanel.getViewTreeObserver() 5186 .removeOnGlobalLayoutListener(this); 5187 mNotificationPanel.post(clickPendingViewRunnable); 5188 } 5189 } 5190 }); 5191 instantExpandNotificationsPanel(); 5192 } 5193 } 5194 5195 @Override 5196 public void onExpandClicked(Entry clickedEntry, boolean nowExpanded) { 5197 mHeadsUpManager.setExpanded(clickedEntry, nowExpanded); 5198 if (mState == StatusBarState.KEYGUARD && nowExpanded) { 5199 goToLockedShade(clickedEntry.row); 5200 } 5201 } 5202 5203 /** 5204 * Goes back to the keyguard after hanging around in {@link StatusBarState#SHADE_LOCKED}. 5205 */ 5206 public void goToKeyguard() { 5207 if (mState == StatusBarState.SHADE_LOCKED) { 5208 mStackScroller.onGoToKeyguard(); 5209 setBarState(StatusBarState.KEYGUARD); 5210 updateKeyguardState(false /* goingToFullShade */, true /* fromShadeLocked*/); 5211 } 5212 } 5213 5214 public long getKeyguardFadingAwayDelay() { 5215 return mKeyguardFadingAwayDelay; 5216 } 5217 5218 public long getKeyguardFadingAwayDuration() { 5219 return mKeyguardFadingAwayDuration; 5220 } 5221 5222 public void setBouncerShowing(boolean bouncerShowing) { 5223 mBouncerShowing = bouncerShowing; 5224 if (mStatusBarView != null) mStatusBarView.setBouncerShowing(bouncerShowing); 5225 updateHideIconsForBouncer(true /* animate */); 5226 recomputeDisableFlags(true /* animate */); 5227 } 5228 5229 public void cancelCurrentTouch() { 5230 if (mNotificationPanel.isTracking()) { 5231 mStatusBarWindow.cancelCurrentTouch(); 5232 if (mState == StatusBarState.SHADE) { 5233 animateCollapsePanels(); 5234 } 5235 } 5236 } 5237 5238 WakefulnessLifecycle.Observer mWakefulnessObserver = new WakefulnessLifecycle.Observer() { 5239 @Override 5240 public void onFinishedGoingToSleep() { 5241 mNotificationPanel.onAffordanceLaunchEnded(); 5242 releaseGestureWakeLock(); 5243 mLaunchCameraOnScreenTurningOn = false; 5244 mDeviceInteractive = false; 5245 mWakeUpComingFromTouch = false; 5246 mWakeUpTouchLocation = null; 5247 mStackScroller.setAnimationsEnabled(false); 5248 mVisualStabilityManager.setScreenOn(false); 5249 updateVisibleToUser(); 5250 5251 // We need to disable touch events because these might 5252 // collapse the panel after we expanded it, and thus we would end up with a blank 5253 // Keyguard. 5254 mNotificationPanel.setTouchDisabled(true); 5255 mStatusBarWindow.cancelCurrentTouch(); 5256 if (mLaunchCameraOnFinishedGoingToSleep) { 5257 mLaunchCameraOnFinishedGoingToSleep = false; 5258 5259 // This gets executed before we will show Keyguard, so post it in order that the state 5260 // is correct. 5261 mHandler.post(new Runnable() { 5262 @Override 5263 public void run() { 5264 onCameraLaunchGestureDetected(mLastCameraLaunchSource); 5265 } 5266 }); 5267 } 5268 updateIsKeyguard(); 5269 } 5270 5271 @Override 5272 public void onStartedGoingToSleep() { 5273 notifyHeadsUpGoingToSleep(); 5274 dismissVolumeDialog(); 5275 } 5276 5277 @Override 5278 public void onStartedWakingUp() { 5279 mDeviceInteractive = true; 5280 mStackScroller.setAnimationsEnabled(true); 5281 mVisualStabilityManager.setScreenOn(true); 5282 mNotificationPanel.setTouchDisabled(false); 5283 5284 maybePrepareWakeUpFromAod(); 5285 5286 mDozeServiceHost.stopDozing(); 5287 updateVisibleToUser(); 5288 updateIsKeyguard(); 5289 } 5290 }; 5291 5292 ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() { 5293 @Override 5294 public void onScreenTurningOn() { 5295 mFalsingManager.onScreenTurningOn(); 5296 mNotificationPanel.onScreenTurningOn(); 5297 5298 maybePrepareWakeUpFromAod(); 5299 5300 if (mLaunchCameraOnScreenTurningOn) { 5301 mNotificationPanel.launchCamera(false, mLastCameraLaunchSource); 5302 mLaunchCameraOnScreenTurningOn = false; 5303 } 5304 } 5305 5306 @Override 5307 public void onScreenTurnedOn() { 5308 mScrimController.wakeUpFromAod(); 5309 mDozeScrimController.onScreenTurnedOn(); 5310 } 5311 5312 @Override 5313 public void onScreenTurnedOff() { 5314 mFalsingManager.onScreenOff(); 5315 // If we pulse in from AOD, we turn the screen off first. However, updatingIsKeyguard 5316 // in that case destroys the HeadsUpManager state, so don't do it in that case. 5317 if (!isPulsing()) { 5318 updateIsKeyguard(); 5319 } 5320 } 5321 }; 5322 5323 public int getWakefulnessState() { 5324 return mWakefulnessLifecycle.getWakefulness(); 5325 } 5326 5327 private void maybePrepareWakeUpFromAod() { 5328 int wakefulness = mWakefulnessLifecycle.getWakefulness(); 5329 if (mDozing && wakefulness == WAKEFULNESS_WAKING && !isPulsing()) { 5330 mScrimController.prepareWakeUpFromAod(); 5331 } 5332 } 5333 5334 private void vibrateForCameraGesture() { 5335 // Make sure to pass -1 for repeat so VibratorService doesn't stop us when going to sleep. 5336 mVibrator.vibrate(mCameraLaunchGestureVibePattern, -1 /* repeat */); 5337 } 5338 5339 /** 5340 * @return true if the screen is currently fully off, i.e. has finished turning off and has 5341 * since not started turning on. 5342 */ 5343 public boolean isScreenFullyOff() { 5344 return mScreenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_OFF; 5345 } 5346 5347 @Override 5348 public void showScreenPinningRequest(int taskId) { 5349 if (mKeyguardMonitor.isShowing()) { 5350 // Don't allow apps to trigger this from keyguard. 5351 return; 5352 } 5353 // Show screen pinning request, since this comes from an app, show 'no thanks', button. 5354 showScreenPinningRequest(taskId, true); 5355 } 5356 5357 public void showScreenPinningRequest(int taskId, boolean allowCancel) { 5358 mScreenPinningRequest.showPrompt(taskId, allowCancel); 5359 } 5360 5361 public boolean hasActiveNotifications() { 5362 return !mNotificationData.getActiveNotifications().isEmpty(); 5363 } 5364 5365 public void wakeUpIfDozing(long time, View where) { 5366 if (mDozing) { 5367 PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 5368 pm.wakeUp(time, "com.android.systemui:NODOZE"); 5369 mWakeUpComingFromTouch = true; 5370 where.getLocationInWindow(mTmpInt2); 5371 mWakeUpTouchLocation = new PointF(mTmpInt2[0] + where.getWidth() / 2, 5372 mTmpInt2[1] + where.getHeight() / 2); 5373 mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested(); 5374 mFalsingManager.onScreenOnFromTouch(); 5375 } 5376 } 5377 5378 @Override 5379 public void appTransitionCancelled() { 5380 EventBus.getDefault().send(new AppTransitionFinishedEvent()); 5381 } 5382 5383 @Override 5384 public void appTransitionFinished() { 5385 EventBus.getDefault().send(new AppTransitionFinishedEvent()); 5386 } 5387 5388 @Override 5389 public void onCameraLaunchGestureDetected(int source) { 5390 mLastCameraLaunchSource = source; 5391 if (isGoingToSleep()) { 5392 if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Finish going to sleep before launching camera"); 5393 mLaunchCameraOnFinishedGoingToSleep = true; 5394 return; 5395 } 5396 if (!mNotificationPanel.canCameraGestureBeLaunched( 5397 mStatusBarKeyguardViewManager.isShowing() && mExpandedVisible)) { 5398 if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Can't launch camera right now, mExpandedVisible: " + 5399 mExpandedVisible); 5400 return; 5401 } 5402 if (!mDeviceInteractive) { 5403 PowerManager pm = mContext.getSystemService(PowerManager.class); 5404 pm.wakeUp(SystemClock.uptimeMillis(), "com.android.systemui:CAMERA_GESTURE"); 5405 mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested(); 5406 } 5407 vibrateForCameraGesture(); 5408 if (!mStatusBarKeyguardViewManager.isShowing()) { 5409 startActivityDismissingKeyguard(KeyguardBottomAreaView.INSECURE_CAMERA_INTENT, 5410 false /* onlyProvisioned */, true /* dismissShade */, 5411 true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */); 5412 } else { 5413 if (!mDeviceInteractive) { 5414 // Avoid flickering of the scrim when we instant launch the camera and the bouncer 5415 // comes on. 5416 mScrimController.dontAnimateBouncerChangesUntilNextFrame(); 5417 mGestureWakeLock.acquire(LAUNCH_TRANSITION_TIMEOUT_MS + 1000L); 5418 } 5419 if (isScreenTurningOnOrOn()) { 5420 if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Launching camera"); 5421 mNotificationPanel.launchCamera(mDeviceInteractive /* animate */, source); 5422 } else { 5423 // We need to defer the camera launch until the screen comes on, since otherwise 5424 // we will dismiss us too early since we are waiting on an activity to be drawn and 5425 // incorrectly get notified because of the screen on event (which resumes and pauses 5426 // some activities) 5427 if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Deferring until screen turns on"); 5428 mLaunchCameraOnScreenTurningOn = true; 5429 } 5430 } 5431 } 5432 5433 boolean isCameraAllowedByAdmin() { 5434 if (mDevicePolicyManager.getCameraDisabled(null, mCurrentUserId)) { 5435 return false; 5436 } else if (isKeyguardShowing() && isKeyguardSecure()) { 5437 // Check if the admin has disabled the camera specifically for the keyguard 5438 return (mDevicePolicyManager.getKeyguardDisabledFeatures(null, mCurrentUserId) 5439 & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) == 0; 5440 } 5441 5442 return true; 5443 } 5444 5445 private boolean isGoingToSleep() { 5446 return mWakefulnessLifecycle.getWakefulness() 5447 == WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP; 5448 } 5449 5450 private boolean isScreenTurningOnOrOn() { 5451 return mScreenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_TURNING_ON 5452 || mScreenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_ON; 5453 } 5454 5455 public void notifyFpAuthModeChanged() { 5456 updateDozing(); 5457 } 5458 5459 private void updateDozing() { 5460 Trace.beginSection("StatusBar#updateDozing"); 5461 // When in wake-and-unlock while pulsing, keep dozing state until fully unlocked. 5462 mDozing = mDozingRequested && mState == StatusBarState.KEYGUARD 5463 || mFingerprintUnlockController.getMode() 5464 == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING; 5465 // When in wake-and-unlock we may not have received a change to mState 5466 // but we still should not be dozing, manually set to false. 5467 if (mFingerprintUnlockController.getMode() == 5468 FingerprintUnlockController.MODE_WAKE_AND_UNLOCK) { 5469 mDozing = false; 5470 } 5471 mStatusBarWindowManager.setDozing(mDozing); 5472 mStatusBarKeyguardViewManager.setDozing(mDozing); 5473 if (mAmbientIndicationContainer instanceof DozeReceiver) { 5474 ((DozeReceiver) mAmbientIndicationContainer).setDozing(mDozing); 5475 } 5476 updateDozingState(); 5477 Trace.endSection(); 5478 } 5479 5480 public boolean isKeyguardShowing() { 5481 if (mStatusBarKeyguardViewManager == null) { 5482 Slog.i(TAG, "isKeyguardShowing() called before startKeyguard(), returning true"); 5483 return true; 5484 } 5485 return mStatusBarKeyguardViewManager.isShowing(); 5486 } 5487 5488 private final class DozeServiceHost implements DozeHost { 5489 private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>(); 5490 private boolean mAnimateWakeup; 5491 private boolean mIgnoreTouchWhilePulsing; 5492 5493 @Override 5494 public String toString() { 5495 return "PSB.DozeServiceHost[mCallbacks=" + mCallbacks.size() + "]"; 5496 } 5497 5498 public void firePowerSaveChanged(boolean active) { 5499 for (Callback callback : mCallbacks) { 5500 callback.onPowerSaveChanged(active); 5501 } 5502 } 5503 5504 public void fireNotificationHeadsUp() { 5505 for (Callback callback : mCallbacks) { 5506 callback.onNotificationHeadsUp(); 5507 } 5508 } 5509 5510 @Override 5511 public void addCallback(@NonNull Callback callback) { 5512 mCallbacks.add(callback); 5513 } 5514 5515 @Override 5516 public void removeCallback(@NonNull Callback callback) { 5517 mCallbacks.remove(callback); 5518 } 5519 5520 @Override 5521 public void startDozing() { 5522 if (!mDozingRequested) { 5523 mDozingRequested = true; 5524 DozeLog.traceDozing(mContext, mDozing); 5525 updateDozing(); 5526 updateIsKeyguard(); 5527 } 5528 } 5529 5530 @Override 5531 public void pulseWhileDozing(@NonNull PulseCallback callback, int reason) { 5532 if (reason == DozeLog.PULSE_REASON_SENSOR_LONG_PRESS) { 5533 mPowerManager.wakeUp(SystemClock.uptimeMillis(), "com.android.systemui:NODOZE"); 5534 startAssist(new Bundle()); 5535 return; 5536 } 5537 5538 mDozeScrimController.pulse(new PulseCallback() { 5539 5540 @Override 5541 public void onPulseStarted() { 5542 callback.onPulseStarted(); 5543 Collection<HeadsUpManager.HeadsUpEntry> pulsingEntries = 5544 mHeadsUpManager.getAllEntries(); 5545 if (!pulsingEntries.isEmpty()) { 5546 // Only pulse the stack scroller if there's actually something to show. 5547 // Otherwise just show the always-on screen. 5548 setPulsing(pulsingEntries); 5549 } 5550 } 5551 5552 @Override 5553 public void onPulseFinished() { 5554 callback.onPulseFinished(); 5555 setPulsing(null); 5556 } 5557 5558 private void setPulsing(Collection<HeadsUpManager.HeadsUpEntry> pulsing) { 5559 mStackScroller.setPulsing(pulsing); 5560 mNotificationPanel.setPulsing(pulsing != null); 5561 mVisualStabilityManager.setPulsing(pulsing != null); 5562 mIgnoreTouchWhilePulsing = false; 5563 } 5564 }, reason); 5565 } 5566 5567 @Override 5568 public void stopDozing() { 5569 if (mDozingRequested) { 5570 mDozingRequested = false; 5571 DozeLog.traceDozing(mContext, mDozing); 5572 updateDozing(); 5573 } 5574 } 5575 5576 @Override 5577 public void onIgnoreTouchWhilePulsing(boolean ignore) { 5578 if (ignore != mIgnoreTouchWhilePulsing) { 5579 DozeLog.tracePulseTouchDisabledByProx(mContext, ignore); 5580 } 5581 mIgnoreTouchWhilePulsing = ignore; 5582 if (isDozing() && ignore) { 5583 mStatusBarWindow.cancelCurrentTouch(); 5584 } 5585 } 5586 5587 @Override 5588 public void dozeTimeTick() { 5589 mNotificationPanel.refreshTime(); 5590 } 5591 5592 @Override 5593 public boolean isPowerSaveActive() { 5594 return mBatteryController.isPowerSave(); 5595 } 5596 5597 @Override 5598 public boolean isPulsingBlocked() { 5599 return mFingerprintUnlockController.getMode() 5600 == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK; 5601 } 5602 5603 @Override 5604 public boolean isProvisioned() { 5605 return mDeviceProvisionedController.isDeviceProvisioned() 5606 && mDeviceProvisionedController.isCurrentUserSetup(); 5607 } 5608 5609 @Override 5610 public boolean isBlockingDoze() { 5611 if (mFingerprintUnlockController.hasPendingAuthentication()) { 5612 Log.i(TAG, "Blocking AOD because fingerprint has authenticated"); 5613 return true; 5614 } 5615 return false; 5616 } 5617 5618 @Override 5619 public void startPendingIntentDismissingKeyguard(PendingIntent intent) { 5620 StatusBar.this.startPendingIntentDismissingKeyguard(intent); 5621 } 5622 5623 @Override 5624 public void abortPulsing() { 5625 mDozeScrimController.abortPulsing(); 5626 } 5627 5628 @Override 5629 public void extendPulse() { 5630 mDozeScrimController.extendPulse(); 5631 } 5632 5633 @Override 5634 public void setAnimateWakeup(boolean animateWakeup) { 5635 if (mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_AWAKE 5636 || mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_WAKING) { 5637 // Too late to change the wakeup animation. 5638 return; 5639 } 5640 mAnimateWakeup = animateWakeup; 5641 } 5642 5643 @Override 5644 public void onDoubleTap(float screenX, float screenY) { 5645 if (screenX > 0 && screenY > 0 && mAmbientIndicationContainer != null 5646 && mAmbientIndicationContainer.getVisibility() == View.VISIBLE) { 5647 mAmbientIndicationContainer.getLocationOnScreen(mTmpInt2); 5648 float viewX = screenX - mTmpInt2[0]; 5649 float viewY = screenY - mTmpInt2[1]; 5650 if (0 <= viewX && viewX <= mAmbientIndicationContainer.getWidth() 5651 && 0 <= viewY && viewY <= mAmbientIndicationContainer.getHeight()) { 5652 dispatchDoubleTap(viewX, viewY); 5653 } 5654 } 5655 } 5656 5657 @Override 5658 public void setDozeScreenBrightness(int value) { 5659 mStatusBarWindowManager.setDozeScreenBrightness(value); 5660 } 5661 5662 @Override 5663 public void setAodDimmingScrim(float scrimOpacity) { 5664 mDozeScrimController.setAodDimmingScrim(scrimOpacity); 5665 } 5666 5667 public void dispatchDoubleTap(float viewX, float viewY) { 5668 dispatchTap(mAmbientIndicationContainer, viewX, viewY); 5669 dispatchTap(mAmbientIndicationContainer, viewX, viewY); 5670 } 5671 5672 private void dispatchTap(View view, float x, float y) { 5673 long now = SystemClock.elapsedRealtime(); 5674 dispatchTouchEvent(view, x, y, now, MotionEvent.ACTION_DOWN); 5675 dispatchTouchEvent(view, x, y, now, MotionEvent.ACTION_UP); 5676 } 5677 5678 private void dispatchTouchEvent(View view, float x, float y, long now, int action) { 5679 MotionEvent ev = MotionEvent.obtain(now, now, action, x, y, 0 /* meta */); 5680 view.dispatchTouchEvent(ev); 5681 ev.recycle(); 5682 } 5683 5684 private boolean shouldAnimateWakeup() { 5685 return mAnimateWakeup; 5686 } 5687 } 5688 5689 public boolean shouldIgnoreTouch() { 5690 return isDozing() && mDozeServiceHost.mIgnoreTouchWhilePulsing; 5691 } 5692 5693 // Begin Extra BaseStatusBar methods. 5694 5695 protected CommandQueue mCommandQueue; 5696 protected IStatusBarService mBarService; 5697 5698 // all notifications 5699 protected NotificationData mNotificationData; 5700 protected NotificationStackScrollLayout mStackScroller; 5701 5702 protected NotificationGroupManager mGroupManager = new NotificationGroupManager(); 5703 5704 protected RemoteInputController mRemoteInputController; 5705 5706 // for heads up notifications 5707 protected HeadsUpManager mHeadsUpManager; 5708 5709 private AboveShelfObserver mAboveShelfObserver; 5710 5711 // handling reordering 5712 protected VisualStabilityManager mVisualStabilityManager = new VisualStabilityManager(); 5713 5714 protected int mCurrentUserId = 0; 5715 final protected SparseArray<UserInfo> mCurrentProfiles = new SparseArray<UserInfo>(); 5716 5717 protected int mLayoutDirection = -1; // invalid 5718 protected AccessibilityManager mAccessibilityManager; 5719 5720 protected boolean mDeviceInteractive; 5721 5722 protected boolean mVisible; 5723 protected ArraySet<Entry> mHeadsUpEntriesToRemoveOnSwitch = new ArraySet<>(); 5724 protected ArraySet<Entry> mRemoteInputEntriesToRemoveOnCollapse = new ArraySet<>(); 5725 5726 /** 5727 * Notifications with keys in this set are not actually around anymore. We kept them around 5728 * when they were canceled in response to a remote input interaction. This allows us to show 5729 * what you replied and allows you to continue typing into it. 5730 */ 5731 protected ArraySet<String> mKeysKeptForRemoteInput = new ArraySet<>(); 5732 5733 // mScreenOnFromKeyguard && mVisible. 5734 private boolean mVisibleToUser; 5735 5736 private Locale mLocale; 5737 5738 protected boolean mUseHeadsUp = false; 5739 protected boolean mHeadsUpTicker = false; 5740 protected boolean mDisableNotificationAlerts = false; 5741 5742 protected DevicePolicyManager mDevicePolicyManager; 5743 protected PowerManager mPowerManager; 5744 protected StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; 5745 5746 // public mode, private notifications, etc 5747 private final SparseBooleanArray mLockscreenPublicMode = new SparseBooleanArray(); 5748 private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray(); 5749 private final SparseBooleanArray mUsersAllowingNotifications = new SparseBooleanArray(); 5750 5751 private UserManager mUserManager; 5752 5753 protected KeyguardManager mKeyguardManager; 5754 private LockPatternUtils mLockPatternUtils; 5755 private DeviceProvisionedController mDeviceProvisionedController 5756 = Dependency.get(DeviceProvisionedController.class); 5757 protected SystemServicesProxy mSystemServicesProxy; 5758 5759 // UI-specific methods 5760 5761 protected WindowManager mWindowManager; 5762 protected IWindowManager mWindowManagerService; 5763 5764 protected Display mDisplay; 5765 5766 protected RecentsComponent mRecents; 5767 5768 protected int mZenMode; 5769 5770 // which notification is currently being longpress-examined by the user 5771 private NotificationGuts mNotificationGutsExposed; 5772 private MenuItem mGutsMenuItem; 5773 5774 private KeyboardShortcuts mKeyboardShortcuts; 5775 5776 protected NotificationShelf mNotificationShelf; 5777 protected DismissView mDismissView; 5778 protected EmptyShadeView mEmptyShadeView; 5779 5780 private NotificationClicker mNotificationClicker = new NotificationClicker(); 5781 5782 protected AssistManager mAssistManager; 5783 5784 protected boolean mVrMode; 5785 5786 private Set<String> mNonBlockablePkgs; 5787 5788 public boolean isDeviceInteractive() { 5789 return mDeviceInteractive; 5790 } 5791 5792 @Override // NotificationData.Environment 5793 public boolean isDeviceProvisioned() { 5794 return mDeviceProvisionedController.isDeviceProvisioned(); 5795 } 5796 5797 private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() { 5798 @Override 5799 public void onVrStateChanged(boolean enabled) { 5800 mVrMode = enabled; 5801 } 5802 }; 5803 5804 public boolean isDeviceInVrMode() { 5805 return mVrMode; 5806 } 5807 5808 private final DeviceProvisionedListener mDeviceProvisionedListener = 5809 new DeviceProvisionedListener() { 5810 @Override 5811 public void onDeviceProvisionedChanged() { 5812 updateNotifications(); 5813 } 5814 }; 5815 5816 protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) { 5817 @Override 5818 public void onChange(boolean selfChange) { 5819 final int mode = Settings.Global.getInt(mContext.getContentResolver(), 5820 Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF); 5821 setZenMode(mode); 5822 5823 updateLockscreenNotificationSetting(); 5824 } 5825 }; 5826 5827 private final ContentObserver mLockscreenSettingsObserver = new ContentObserver(mHandler) { 5828 @Override 5829 public void onChange(boolean selfChange) { 5830 // We don't know which user changed LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS or 5831 // LOCK_SCREEN_SHOW_NOTIFICATIONS, so we just dump our cache ... 5832 mUsersAllowingPrivateNotifications.clear(); 5833 mUsersAllowingNotifications.clear(); 5834 // ... and refresh all the notifications 5835 updateLockscreenNotificationSetting(); 5836 updateNotifications(); 5837 } 5838 }; 5839 5840 private RemoteViews.OnClickHandler mOnClickHandler = new RemoteViews.OnClickHandler() { 5841 5842 @Override 5843 public boolean onClickHandler( 5844 final View view, final PendingIntent pendingIntent, final Intent fillInIntent) { 5845 wakeUpIfDozing(SystemClock.uptimeMillis(), view); 5846 5847 5848 if (handleRemoteInput(view, pendingIntent, fillInIntent)) { 5849 return true; 5850 } 5851 5852 if (DEBUG) { 5853 Log.v(TAG, "Notification click handler invoked for intent: " + pendingIntent); 5854 } 5855 logActionClick(view); 5856 // The intent we are sending is for the application, which 5857 // won't have permission to immediately start an activity after 5858 // the user switches to home. We know it is safe to do at this 5859 // point, so make sure new activity switches are now allowed. 5860 try { 5861 ActivityManager.getService().resumeAppSwitches(); 5862 } catch (RemoteException e) { 5863 } 5864 final boolean isActivity = pendingIntent.isActivity(); 5865 if (isActivity) { 5866 final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing(); 5867 final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity( 5868 mContext, pendingIntent.getIntent(), mCurrentUserId); 5869 dismissKeyguardThenExecute(new OnDismissAction() { 5870 @Override 5871 public boolean onDismiss() { 5872 try { 5873 ActivityManager.getService().resumeAppSwitches(); 5874 } catch (RemoteException e) { 5875 } 5876 5877 boolean handled = superOnClickHandler(view, pendingIntent, fillInIntent); 5878 5879 // close the shade if it was open 5880 if (handled && !mNotificationPanel.isFullyCollapsed()) { 5881 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, 5882 true /* force */); 5883 visibilityChanged(false); 5884 mAssistManager.hideAssist(); 5885 5886 // Wait for activity start. 5887 return true; 5888 } else { 5889 return false; 5890 } 5891 5892 } 5893 }, afterKeyguardGone); 5894 return true; 5895 } else { 5896 return superOnClickHandler(view, pendingIntent, fillInIntent); 5897 } 5898 } 5899 5900 private void logActionClick(View view) { 5901 ViewParent parent = view.getParent(); 5902 String key = getNotificationKeyForParent(parent); 5903 if (key == null) { 5904 Log.w(TAG, "Couldn't determine notification for click."); 5905 return; 5906 } 5907 int index = -1; 5908 // If this is a default template, determine the index of the button. 5909 if (view.getId() == com.android.internal.R.id.action0 && 5910 parent != null && parent instanceof ViewGroup) { 5911 ViewGroup actionGroup = (ViewGroup) parent; 5912 index = actionGroup.indexOfChild(view); 5913 } 5914 try { 5915 mBarService.onNotificationActionClick(key, index); 5916 } catch (RemoteException e) { 5917 // Ignore 5918 } 5919 } 5920 5921 private String getNotificationKeyForParent(ViewParent parent) { 5922 while (parent != null) { 5923 if (parent instanceof ExpandableNotificationRow) { 5924 return ((ExpandableNotificationRow) parent).getStatusBarNotification().getKey(); 5925 } 5926 parent = parent.getParent(); 5927 } 5928 return null; 5929 } 5930 5931 private boolean superOnClickHandler(View view, PendingIntent pendingIntent, 5932 Intent fillInIntent) { 5933 return super.onClickHandler(view, pendingIntent, fillInIntent, 5934 StackId.FULLSCREEN_WORKSPACE_STACK_ID); 5935 } 5936 5937 private boolean handleRemoteInput(View view, PendingIntent pendingIntent, Intent fillInIntent) { 5938 Object tag = view.getTag(com.android.internal.R.id.remote_input_tag); 5939 RemoteInput[] inputs = null; 5940 if (tag instanceof RemoteInput[]) { 5941 inputs = (RemoteInput[]) tag; 5942 } 5943 5944 if (inputs == null) { 5945 return false; 5946 } 5947 5948 RemoteInput input = null; 5949 5950 for (RemoteInput i : inputs) { 5951 if (i.getAllowFreeFormInput()) { 5952 input = i; 5953 } 5954 } 5955 5956 if (input == null) { 5957 return false; 5958 } 5959 5960 ViewParent p = view.getParent(); 5961 RemoteInputView riv = null; 5962 while (p != null) { 5963 if (p instanceof View) { 5964 View pv = (View) p; 5965 if (pv.isRootNamespace()) { 5966 riv = findRemoteInputView(pv); 5967 break; 5968 } 5969 } 5970 p = p.getParent(); 5971 } 5972 ExpandableNotificationRow row = null; 5973 while (p != null) { 5974 if (p instanceof ExpandableNotificationRow) { 5975 row = (ExpandableNotificationRow) p; 5976 break; 5977 } 5978 p = p.getParent(); 5979 } 5980 5981 if (row == null) { 5982 return false; 5983 } 5984 5985 row.setUserExpanded(true); 5986 5987 if (!mAllowLockscreenRemoteInput) { 5988 final int userId = pendingIntent.getCreatorUserHandle().getIdentifier(); 5989 if (isLockscreenPublicMode(userId)) { 5990 onLockedRemoteInput(row, view); 5991 return true; 5992 } 5993 if (mUserManager.getUserInfo(userId).isManagedProfile() 5994 && mKeyguardManager.isDeviceLocked(userId)) { 5995 onLockedWorkRemoteInput(userId, row, view); 5996 return true; 5997 } 5998 } 5999 6000 if (riv == null) { 6001 riv = findRemoteInputView(row.getPrivateLayout().getExpandedChild()); 6002 if (riv == null) { 6003 return false; 6004 } 6005 if (!row.getPrivateLayout().getExpandedChild().isShown()) { 6006 onMakeExpandedVisibleForRemoteInput(row, view); 6007 return true; 6008 } 6009 } 6010 6011 int width = view.getWidth(); 6012 if (view instanceof TextView) { 6013 // Center the reveal on the text which might be off-center from the TextView 6014 TextView tv = (TextView) view; 6015 if (tv.getLayout() != null) { 6016 int innerWidth = (int) tv.getLayout().getLineWidth(0); 6017 innerWidth += tv.getCompoundPaddingLeft() + tv.getCompoundPaddingRight(); 6018 width = Math.min(width, innerWidth); 6019 } 6020 } 6021 int cx = view.getLeft() + width / 2; 6022 int cy = view.getTop() + view.getHeight() / 2; 6023 int w = riv.getWidth(); 6024 int h = riv.getHeight(); 6025 int r = Math.max( 6026 Math.max(cx + cy, cx + (h - cy)), 6027 Math.max((w - cx) + cy, (w - cx) + (h - cy))); 6028 6029 riv.setRevealParameters(cx, cy, r); 6030 riv.setPendingIntent(pendingIntent); 6031 riv.setRemoteInput(inputs, input); 6032 riv.focusAnimated(); 6033 6034 return true; 6035 } 6036 6037 private RemoteInputView findRemoteInputView(View v) { 6038 if (v == null) { 6039 return null; 6040 } 6041 return (RemoteInputView) v.findViewWithTag(RemoteInputView.VIEW_TAG); 6042 } 6043 }; 6044 6045 private final BroadcastReceiver mBaseBroadcastReceiver = new BroadcastReceiver() { 6046 @Override 6047 public void onReceive(Context context, Intent intent) { 6048 String action = intent.getAction(); 6049 if (Intent.ACTION_USER_SWITCHED.equals(action)) { 6050 mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); 6051 updateCurrentProfilesCache(); 6052 if (true) Log.v(TAG, "userId " + mCurrentUserId + " is in the house"); 6053 6054 updateLockscreenNotificationSetting(); 6055 6056 userSwitched(mCurrentUserId); 6057 } else if (Intent.ACTION_USER_ADDED.equals(action)) { 6058 updateCurrentProfilesCache(); 6059 } else if (Intent.ACTION_USER_PRESENT.equals(action)) { 6060 List<ActivityManager.RecentTaskInfo> recentTask = null; 6061 try { 6062 recentTask = ActivityManager.getService().getRecentTasks(1, 6063 ActivityManager.RECENT_WITH_EXCLUDED 6064 | ActivityManager.RECENT_INCLUDE_PROFILES, 6065 mCurrentUserId).getList(); 6066 } catch (RemoteException e) { 6067 // Abandon hope activity manager not running. 6068 } 6069 if (recentTask != null && recentTask.size() > 0) { 6070 UserInfo user = mUserManager.getUserInfo(recentTask.get(0).userId); 6071 if (user != null && user.isManagedProfile()) { 6072 Toast toast = Toast.makeText(mContext, 6073 R.string.managed_profile_foreground_toast, 6074 Toast.LENGTH_SHORT); 6075 TextView text = (TextView) toast.getView().findViewById( 6076 android.R.id.message); 6077 text.setCompoundDrawablesRelativeWithIntrinsicBounds( 6078 R.drawable.stat_sys_managed_profile_status, 0, 0, 0); 6079 int paddingPx = mContext.getResources().getDimensionPixelSize( 6080 R.dimen.managed_profile_toast_padding); 6081 text.setCompoundDrawablePadding(paddingPx); 6082 toast.show(); 6083 } 6084 } 6085 } else if (BANNER_ACTION_CANCEL.equals(action) || BANNER_ACTION_SETUP.equals(action)) { 6086 NotificationManager noMan = (NotificationManager) 6087 mContext.getSystemService(Context.NOTIFICATION_SERVICE); 6088 noMan.cancel(SystemMessage.NOTE_HIDDEN_NOTIFICATIONS); 6089 6090 Settings.Secure.putInt(mContext.getContentResolver(), 6091 Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0); 6092 if (BANNER_ACTION_SETUP.equals(action)) { 6093 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, 6094 true /* force */); 6095 mContext.startActivity(new Intent(Settings.ACTION_APP_NOTIFICATION_REDACTION) 6096 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 6097 6098 ); 6099 } 6100 } else if (NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION.equals(action)) { 6101 final IntentSender intentSender = intent.getParcelableExtra(Intent.EXTRA_INTENT); 6102 final String notificationKey = intent.getStringExtra(Intent.EXTRA_INDEX); 6103 if (intentSender != null) { 6104 try { 6105 mContext.startIntentSender(intentSender, null, 0, 0, 0); 6106 } catch (IntentSender.SendIntentException e) { 6107 /* ignore */ 6108 } 6109 } 6110 if (notificationKey != null) { 6111 try { 6112 mBarService.onNotificationClick(notificationKey); 6113 } catch (RemoteException e) { 6114 /* ignore */ 6115 } 6116 } 6117 } 6118 } 6119 }; 6120 6121 private final BroadcastReceiver mAllUsersReceiver = new BroadcastReceiver() { 6122 @Override 6123 public void onReceive(Context context, Intent intent) { 6124 final String action = intent.getAction(); 6125 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); 6126 6127 if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(action) && 6128 isCurrentProfile(getSendingUserId())) { 6129 mUsersAllowingPrivateNotifications.clear(); 6130 updateLockscreenNotificationSetting(); 6131 updateNotifications(); 6132 } else if (Intent.ACTION_DEVICE_LOCKED_CHANGED.equals(action)) { 6133 if (userId != mCurrentUserId && isCurrentProfile(userId)) { 6134 onWorkChallengeChanged(); 6135 } 6136 } 6137 } 6138 }; 6139 6140 private final NotificationListenerWithPlugins mNotificationListener = 6141 new NotificationListenerWithPlugins() { 6142 @Override 6143 public void onListenerConnected() { 6144 if (DEBUG) Log.d(TAG, "onListenerConnected"); 6145 onPluginConnected(); 6146 final StatusBarNotification[] notifications = getActiveNotifications(); 6147 if (notifications == null) { 6148 Log.w(TAG, "onListenerConnected unable to get active notifications."); 6149 return; 6150 } 6151 final RankingMap currentRanking = getCurrentRanking(); 6152 mHandler.post(new Runnable() { 6153 @Override 6154 public void run() { 6155 for (StatusBarNotification sbn : notifications) { 6156 try { 6157 addNotification(sbn, currentRanking); 6158 } catch (InflationException e) { 6159 handleInflationException(sbn, e); 6160 } 6161 } 6162 } 6163 }); 6164 } 6165 6166 @Override 6167 public void onNotificationPosted(final StatusBarNotification sbn, 6168 final RankingMap rankingMap) { 6169 if (DEBUG) Log.d(TAG, "onNotificationPosted: " + sbn); 6170 if (sbn != null && !onPluginNotificationPosted(sbn, rankingMap)) { 6171 mHandler.post(new Runnable() { 6172 @Override 6173 public void run() { 6174 processForRemoteInput(sbn.getNotification()); 6175 String key = sbn.getKey(); 6176 mKeysKeptForRemoteInput.remove(key); 6177 boolean isUpdate = mNotificationData.get(key) != null; 6178 // In case we don't allow child notifications, we ignore children of 6179 // notifications that have a summary, since we're not going to show them 6180 // anyway. This is true also when the summary is canceled, 6181 // because children are automatically canceled by NoMan in that case. 6182 if (!ENABLE_CHILD_NOTIFICATIONS 6183 && mGroupManager.isChildInGroupWithSummary(sbn)) { 6184 if (DEBUG) { 6185 Log.d(TAG, "Ignoring group child due to existing summary: " + sbn); 6186 } 6187 6188 // Remove existing notification to avoid stale data. 6189 if (isUpdate) { 6190 removeNotification(key, rankingMap); 6191 } else { 6192 mNotificationData.updateRanking(rankingMap); 6193 } 6194 return; 6195 } 6196 try { 6197 if (isUpdate) { 6198 updateNotification(sbn, rankingMap); 6199 } else { 6200 addNotification(sbn, rankingMap); 6201 } 6202 } catch (InflationException e) { 6203 handleInflationException(sbn, e); 6204 } 6205 } 6206 }); 6207 } 6208 } 6209 6210 @Override 6211 public void onNotificationRemoved(StatusBarNotification sbn, 6212 final RankingMap rankingMap) { 6213 if (DEBUG) Log.d(TAG, "onNotificationRemoved: " + sbn); 6214 if (sbn != null && !onPluginNotificationRemoved(sbn, rankingMap)) { 6215 final String key = sbn.getKey(); 6216 mHandler.post(() -> removeNotification(key, rankingMap)); 6217 } 6218 } 6219 6220 @Override 6221 public void onNotificationRankingUpdate(final RankingMap rankingMap) { 6222 if (DEBUG) Log.d(TAG, "onRankingUpdate"); 6223 if (rankingMap != null) { 6224 RankingMap r = onPluginRankingUpdate(rankingMap); 6225 mHandler.post(() -> updateNotificationRanking(r)); 6226 } 6227 } 6228 6229 }; 6230 6231 private void updateCurrentProfilesCache() { 6232 synchronized (mCurrentProfiles) { 6233 mCurrentProfiles.clear(); 6234 if (mUserManager != null) { 6235 for (UserInfo user : mUserManager.getProfiles(mCurrentUserId)) { 6236 mCurrentProfiles.put(user.id, user); 6237 } 6238 } 6239 } 6240 } 6241 6242 protected void notifyUserAboutHiddenNotifications() { 6243 if (0 != Settings.Secure.getInt(mContext.getContentResolver(), 6244 Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 1)) { 6245 Log.d(TAG, "user hasn't seen notification about hidden notifications"); 6246 if (!mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())) { 6247 Log.d(TAG, "insecure lockscreen, skipping notification"); 6248 Settings.Secure.putInt(mContext.getContentResolver(), 6249 Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0); 6250 return; 6251 } 6252 Log.d(TAG, "disabling lockecreen notifications and alerting the user"); 6253 // disable lockscreen notifications until user acts on the banner. 6254 Settings.Secure.putInt(mContext.getContentResolver(), 6255 Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0); 6256 Settings.Secure.putInt(mContext.getContentResolver(), 6257 Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0); 6258 6259 final String packageName = mContext.getPackageName(); 6260 PendingIntent cancelIntent = PendingIntent.getBroadcast(mContext, 0, 6261 new Intent(BANNER_ACTION_CANCEL).setPackage(packageName), 6262 PendingIntent.FLAG_CANCEL_CURRENT); 6263 PendingIntent setupIntent = PendingIntent.getBroadcast(mContext, 0, 6264 new Intent(BANNER_ACTION_SETUP).setPackage(packageName), 6265 PendingIntent.FLAG_CANCEL_CURRENT); 6266 6267 final int colorRes = com.android.internal.R.color.system_notification_accent_color; 6268 Notification.Builder note = 6269 new Notification.Builder(mContext, NotificationChannels.GENERAL) 6270 .setSmallIcon(R.drawable.ic_android) 6271 .setContentTitle(mContext.getString( 6272 R.string.hidden_notifications_title)) 6273 .setContentText(mContext.getString(R.string.hidden_notifications_text)) 6274 .setOngoing(true) 6275 .setColor(mContext.getColor(colorRes)) 6276 .setContentIntent(setupIntent) 6277 .addAction(R.drawable.ic_close, 6278 mContext.getString(R.string.hidden_notifications_cancel), 6279 cancelIntent) 6280 .addAction(R.drawable.ic_settings, 6281 mContext.getString(R.string.hidden_notifications_setup), 6282 setupIntent); 6283 overrideNotificationAppName(mContext, note); 6284 6285 NotificationManager noMan = 6286 (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); 6287 noMan.notify(SystemMessage.NOTE_HIDDEN_NOTIFICATIONS, note.build()); 6288 } 6289 } 6290 6291 @Override // NotificationData.Environment 6292 public boolean isNotificationForCurrentProfiles(StatusBarNotification n) { 6293 final int thisUserId = mCurrentUserId; 6294 final int notificationUserId = n.getUserId(); 6295 if (DEBUG && MULTIUSER_DEBUG) { 6296 Log.v(TAG, String.format("%s: current userid: %d, notification userid: %d", 6297 n, thisUserId, notificationUserId)); 6298 } 6299 return isCurrentProfile(notificationUserId); 6300 } 6301 6302 protected void setNotificationShown(StatusBarNotification n) { 6303 setNotificationsShown(new String[]{n.getKey()}); 6304 } 6305 6306 protected void setNotificationsShown(String[] keys) { 6307 try { 6308 mNotificationListener.setNotificationsShown(keys); 6309 } catch (RuntimeException e) { 6310 Log.d(TAG, "failed setNotificationsShown: ", e); 6311 } 6312 } 6313 6314 protected boolean isCurrentProfile(int userId) { 6315 synchronized (mCurrentProfiles) { 6316 return userId == UserHandle.USER_ALL || mCurrentProfiles.get(userId) != null; 6317 } 6318 } 6319 6320 @Override 6321 public NotificationGroupManager getGroupManager() { 6322 return mGroupManager; 6323 } 6324 6325 public boolean isMediaNotification(NotificationData.Entry entry) { 6326 // TODO: confirm that there's a valid media key 6327 return entry.getExpandedContentView() != null && 6328 entry.getExpandedContentView() 6329 .findViewById(com.android.internal.R.id.media_actions) != null; 6330 } 6331 6332 // The button in the guts that links to the system notification settings for that app 6333 private void startAppNotificationSettingsActivity(String packageName, final int appUid, 6334 final NotificationChannel channel) { 6335 final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS); 6336 intent.putExtra(Settings.EXTRA_APP_PACKAGE, packageName); 6337 intent.putExtra(Settings.EXTRA_APP_UID, appUid); 6338 if (channel != null) { 6339 intent.putExtra(EXTRA_FRAGMENT_ARG_KEY, channel.getId()); 6340 } 6341 startNotificationGutsIntent(intent, appUid); 6342 } 6343 6344 private void startNotificationGutsIntent(final Intent intent, final int appUid) { 6345 dismissKeyguardThenExecute(new OnDismissAction() { 6346 @Override 6347 public boolean onDismiss() { 6348 AsyncTask.execute(new Runnable() { 6349 @Override 6350 public void run() { 6351 TaskStackBuilder.create(mContext) 6352 .addNextIntentWithParentStack(intent) 6353 .startActivities(getActivityOptions(), 6354 new UserHandle(UserHandle.getUserId(appUid))); 6355 } 6356 }); 6357 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */); 6358 return true; 6359 } 6360 }, false /* afterKeyguardGone */); 6361 } 6362 6363 public void setNotificationSnoozed(StatusBarNotification sbn, SnoozeOption snoozeOption) { 6364 if (snoozeOption.getSnoozeCriterion() != null) { 6365 mNotificationListener.snoozeNotification(sbn.getKey(), 6366 snoozeOption.getSnoozeCriterion().getId()); 6367 } else { 6368 mNotificationListener.snoozeNotification(sbn.getKey(), 6369 snoozeOption.getMinutesToSnoozeFor() * 60 * 1000); 6370 } 6371 } 6372 6373 private void bindGuts(final ExpandableNotificationRow row, MenuItem item) { 6374 row.inflateGuts(); 6375 row.setGutsView(item); 6376 final StatusBarNotification sbn = row.getStatusBarNotification(); 6377 row.setTag(sbn.getPackageName()); 6378 final NotificationGuts guts = row.getGuts(); 6379 guts.setClosedListener((NotificationGuts g) -> { 6380 if (!g.willBeRemoved() && !row.isRemoved()) { 6381 mStackScroller.onHeightChanged(row, !isPanelFullyCollapsed() /* needsAnimation */); 6382 } 6383 if (mNotificationGutsExposed == g) { 6384 mNotificationGutsExposed = null; 6385 mGutsMenuItem = null; 6386 } 6387 String key = sbn.getKey(); 6388 if (key.equals(mKeyToRemoveOnGutsClosed)) { 6389 mKeyToRemoveOnGutsClosed = null; 6390 removeNotification(key, mLatestRankingMap); 6391 } 6392 }); 6393 6394 View gutsView = item.getGutsView(); 6395 if (gutsView instanceof NotificationSnooze) { 6396 NotificationSnooze snoozeGuts = (NotificationSnooze) gutsView; 6397 snoozeGuts.setSnoozeListener(mStackScroller.getSwipeActionHelper()); 6398 snoozeGuts.setStatusBarNotification(sbn); 6399 snoozeGuts.setSnoozeOptions(row.getEntry().snoozeCriteria); 6400 guts.setHeightChangedListener((NotificationGuts g) -> { 6401 mStackScroller.onHeightChanged(row, row.isShown() /* needsAnimation */); 6402 }); 6403 } 6404 6405 if (gutsView instanceof NotificationInfo) { 6406 final UserHandle userHandle = sbn.getUser(); 6407 PackageManager pmUser = getPackageManagerForUser(mContext, 6408 userHandle.getIdentifier()); 6409 final INotificationManager iNotificationManager = INotificationManager.Stub.asInterface( 6410 ServiceManager.getService(Context.NOTIFICATION_SERVICE)); 6411 final String pkg = sbn.getPackageName(); 6412 NotificationInfo info = (NotificationInfo) gutsView; 6413 // Settings link is only valid for notifications that specify a user, unless this is the 6414 // system user. 6415 NotificationInfo.OnSettingsClickListener onSettingsClick = null; 6416 if (!userHandle.equals(UserHandle.ALL) || mCurrentUserId == UserHandle.USER_SYSTEM) { 6417 onSettingsClick = (View v, NotificationChannel channel, int appUid) -> { 6418 mMetricsLogger.action(MetricsEvent.ACTION_NOTE_INFO); 6419 guts.resetFalsingCheck(); 6420 startAppNotificationSettingsActivity(pkg, appUid, channel); 6421 }; 6422 } 6423 final NotificationInfo.OnAppSettingsClickListener onAppSettingsClick = (View v, 6424 Intent intent) -> { 6425 mMetricsLogger.action(MetricsEvent.ACTION_APP_NOTE_SETTINGS); 6426 guts.resetFalsingCheck(); 6427 startNotificationGutsIntent(intent, sbn.getUid()); 6428 }; 6429 final View.OnClickListener onDoneClick = (View v) -> { 6430 saveAndCloseNotificationMenu(info, row, guts, v); 6431 }; 6432 final NotificationInfo.CheckSaveListener checkSaveListener = 6433 (Runnable saveImportance) -> { 6434 // If the user has security enabled, show challenge if the setting is changed. 6435 if (isLockscreenPublicMode(userHandle.getIdentifier()) 6436 && (mState == StatusBarState.KEYGUARD 6437 || mState == StatusBarState.SHADE_LOCKED)) { 6438 onLockedNotificationImportanceChange(() -> { 6439 saveImportance.run(); 6440 return true; 6441 }); 6442 } else { 6443 saveImportance.run(); 6444 } 6445 }; 6446 6447 ArraySet<NotificationChannel> channels = new ArraySet<NotificationChannel>(); 6448 channels.add(row.getEntry().channel); 6449 if (row.isSummaryWithChildren()) { 6450 // If this is a summary, then add in the children notification channels for the 6451 // same user and pkg. 6452 final List<ExpandableNotificationRow> childrenRows = row.getNotificationChildren(); 6453 final int numChildren = childrenRows.size(); 6454 for (int i = 0; i < numChildren; i++) { 6455 final ExpandableNotificationRow childRow = childrenRows.get(i); 6456 final NotificationChannel childChannel = childRow.getEntry().channel; 6457 final StatusBarNotification childSbn = childRow.getStatusBarNotification(); 6458 if (childSbn.getUser().equals(userHandle) && 6459 childSbn.getPackageName().equals(pkg)) { 6460 channels.add(childChannel); 6461 } 6462 } 6463 } 6464 try { 6465 info.bindNotification(pmUser, iNotificationManager, pkg, new ArrayList(channels), 6466 row.getEntry().channel.getImportance(), sbn, onSettingsClick, 6467 onAppSettingsClick, onDoneClick, checkSaveListener, 6468 mNonBlockablePkgs); 6469 } catch (RemoteException e) { 6470 Log.e(TAG, e.toString()); 6471 } 6472 } 6473 } 6474 6475 private void saveAndCloseNotificationMenu(NotificationInfo info, 6476 ExpandableNotificationRow row, NotificationGuts guts, View done) { 6477 guts.resetFalsingCheck(); 6478 int[] rowLocation = new int[2]; 6479 int[] doneLocation = new int[2]; 6480 row.getLocationOnScreen(rowLocation); 6481 done.getLocationOnScreen(doneLocation); 6482 6483 final int centerX = done.getWidth() / 2; 6484 final int centerY = done.getHeight() / 2; 6485 final int x = doneLocation[0] - rowLocation[0] + centerX; 6486 final int y = doneLocation[1] - rowLocation[1] + centerY; 6487 closeAndSaveGuts(false /* removeLeavebehind */, false /* force */, 6488 true /* removeControls */, x, y, true /* resetMenu */); 6489 } 6490 6491 protected SwipeHelper.LongPressListener getNotificationLongClicker() { 6492 return new SwipeHelper.LongPressListener() { 6493 @Override 6494 public boolean onLongPress(View v, final int x, final int y, 6495 MenuItem item) { 6496 if (!(v instanceof ExpandableNotificationRow)) { 6497 return false; 6498 } 6499 if (v.getWindowToken() == null) { 6500 Log.e(TAG, "Trying to show notification guts, but not attached to window"); 6501 return false; 6502 } 6503 6504 final ExpandableNotificationRow row = (ExpandableNotificationRow) v; 6505 if (row.isDark()) { 6506 return false; 6507 } 6508 v.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); 6509 if (row.areGutsExposed()) { 6510 closeAndSaveGuts(false /* removeLeavebehind */, false /* force */, 6511 true /* removeControls */, -1 /* x */, -1 /* y */, 6512 true /* resetMenu */); 6513 return false; 6514 } 6515 bindGuts(row, item); 6516 NotificationGuts guts = row.getGuts(); 6517 6518 // Assume we are a status_bar_notification_row 6519 if (guts == null) { 6520 // This view has no guts. Examples are the more card or the dismiss all view 6521 return false; 6522 } 6523 6524 mMetricsLogger.action(MetricsEvent.ACTION_NOTE_CONTROLS); 6525 6526 // ensure that it's laid but not visible until actually laid out 6527 guts.setVisibility(View.INVISIBLE); 6528 // Post to ensure the the guts are properly laid out. 6529 guts.post(new Runnable() { 6530 @Override 6531 public void run() { 6532 if (row.getWindowToken() == null) { 6533 Log.e(TAG, "Trying to show notification guts, but not attached to " 6534 + "window"); 6535 return; 6536 } 6537 closeAndSaveGuts(true /* removeLeavebehind */, true /* force */, 6538 true /* removeControls */, -1 /* x */, -1 /* y */, 6539 false /* resetMenu */); 6540 guts.setVisibility(View.VISIBLE); 6541 final double horz = Math.max(guts.getWidth() - x, x); 6542 final double vert = Math.max(guts.getHeight() - y, y); 6543 final float r = (float) Math.hypot(horz, vert); 6544 final Animator a 6545 = ViewAnimationUtils.createCircularReveal(guts, x, y, 0, r); 6546 a.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD); 6547 a.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN); 6548 a.addListener(new AnimatorListenerAdapter() { 6549 @Override 6550 public void onAnimationEnd(Animator animation) { 6551 super.onAnimationEnd(animation); 6552 // Move the notification view back over the menu 6553 row.resetTranslation(); 6554 } 6555 }); 6556 a.start(); 6557 final boolean needsFalsingProtection = 6558 (mState == StatusBarState.KEYGUARD && 6559 !mAccessibilityManager.isTouchExplorationEnabled()); 6560 guts.setExposed(true /* exposed */, needsFalsingProtection); 6561 row.closeRemoteInput(); 6562 mStackScroller.onHeightChanged(row, true /* needsAnimation */); 6563 mNotificationGutsExposed = guts; 6564 mGutsMenuItem = item; 6565 } 6566 }); 6567 return true; 6568 } 6569 }; 6570 } 6571 6572 /** 6573 * Returns the exposed NotificationGuts or null if none are exposed. 6574 */ 6575 public NotificationGuts getExposedGuts() { 6576 return mNotificationGutsExposed; 6577 } 6578 6579 /** 6580 * Closes guts or notification menus that might be visible and saves any changes. 6581 * 6582 * @param removeLeavebehinds true if leavebehinds (e.g. snooze) should be closed. 6583 * @param force true if guts should be closed regardless of state (used for snooze only). 6584 * @param removeControls true if controls (e.g. info) should be closed. 6585 * @param x if closed based on touch location, this is the x touch location. 6586 * @param y if closed based on touch location, this is the y touch location. 6587 * @param resetMenu if any notification menus that might be revealed should be closed. 6588 */ 6589 public void closeAndSaveGuts(boolean removeLeavebehinds, boolean force, boolean removeControls, 6590 int x, int y, boolean resetMenu) { 6591 if (mNotificationGutsExposed != null) { 6592 mNotificationGutsExposed.closeControls(removeLeavebehinds, removeControls, x, y, force); 6593 } 6594 if (resetMenu) { 6595 mStackScroller.resetExposedMenuView(false /* animate */, true /* force */); 6596 } 6597 } 6598 6599 @Override 6600 public void toggleSplitScreen() { 6601 toggleSplitScreenMode(-1 /* metricsDockAction */, -1 /* metricsUndockAction */); 6602 } 6603 6604 @Override 6605 public void preloadRecentApps() { 6606 int msg = MSG_PRELOAD_RECENT_APPS; 6607 mHandler.removeMessages(msg); 6608 mHandler.sendEmptyMessage(msg); 6609 } 6610 6611 @Override 6612 public void cancelPreloadRecentApps() { 6613 int msg = MSG_CANCEL_PRELOAD_RECENT_APPS; 6614 mHandler.removeMessages(msg); 6615 mHandler.sendEmptyMessage(msg); 6616 } 6617 6618 @Override 6619 public void dismissKeyboardShortcutsMenu() { 6620 int msg = MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU; 6621 mHandler.removeMessages(msg); 6622 mHandler.sendEmptyMessage(msg); 6623 } 6624 6625 @Override 6626 public void toggleKeyboardShortcutsMenu(int deviceId) { 6627 int msg = MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU; 6628 mHandler.removeMessages(msg); 6629 mHandler.obtainMessage(msg, deviceId, 0).sendToTarget(); 6630 } 6631 6632 @Override 6633 public void setTopAppHidesStatusBar(boolean topAppHidesStatusBar) { 6634 mTopHidesStatusBar = topAppHidesStatusBar; 6635 if (!topAppHidesStatusBar && mWereIconsJustHidden) { 6636 // Immediately update the icon hidden state, since that should only apply if we're 6637 // staying fullscreen. 6638 mWereIconsJustHidden = false; 6639 recomputeDisableFlags(true); 6640 } 6641 updateHideIconsForBouncer(true /* animate */); 6642 } 6643 6644 protected void sendCloseSystemWindows(String reason) { 6645 try { 6646 ActivityManager.getService().closeSystemDialogs(reason); 6647 } catch (RemoteException e) { 6648 } 6649 } 6650 6651 protected void toggleKeyboardShortcuts(int deviceId) { 6652 KeyboardShortcuts.toggle(mContext, deviceId); 6653 } 6654 6655 protected void dismissKeyboardShortcuts() { 6656 KeyboardShortcuts.dismiss(); 6657 } 6658 6659 /** 6660 * Save the current "public" (locked and secure) state of the lockscreen. 6661 */ 6662 public void setLockscreenPublicMode(boolean publicMode, int userId) { 6663 mLockscreenPublicMode.put(userId, publicMode); 6664 } 6665 6666 public boolean isLockscreenPublicMode(int userId) { 6667 if (userId == UserHandle.USER_ALL) { 6668 return mLockscreenPublicMode.get(mCurrentUserId, false); 6669 } 6670 return mLockscreenPublicMode.get(userId, false); 6671 } 6672 6673 /** 6674 * Has the given user chosen to allow notifications to be shown even when the lockscreen is in 6675 * "public" (secure & locked) mode? 6676 */ 6677 public boolean userAllowsNotificationsInPublic(int userHandle) { 6678 if (userHandle == UserHandle.USER_ALL) { 6679 return true; 6680 } 6681 6682 if (mUsersAllowingNotifications.indexOfKey(userHandle) < 0) { 6683 final boolean allowed = 0 != Settings.Secure.getIntForUser( 6684 mContext.getContentResolver(), 6685 Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0, userHandle); 6686 mUsersAllowingNotifications.append(userHandle, allowed); 6687 return allowed; 6688 } 6689 6690 return mUsersAllowingNotifications.get(userHandle); 6691 } 6692 6693 /** 6694 * Has the given user chosen to allow their private (full) notifications to be shown even 6695 * when the lockscreen is in "public" (secure & locked) mode? 6696 */ 6697 public boolean userAllowsPrivateNotificationsInPublic(int userHandle) { 6698 if (userHandle == UserHandle.USER_ALL) { 6699 return true; 6700 } 6701 6702 if (mUsersAllowingPrivateNotifications.indexOfKey(userHandle) < 0) { 6703 final boolean allowedByUser = 0 != Settings.Secure.getIntForUser( 6704 mContext.getContentResolver(), 6705 Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0, userHandle); 6706 final boolean allowedByDpm = adminAllowsUnredactedNotifications(userHandle); 6707 final boolean allowed = allowedByUser && allowedByDpm; 6708 mUsersAllowingPrivateNotifications.append(userHandle, allowed); 6709 return allowed; 6710 } 6711 6712 return mUsersAllowingPrivateNotifications.get(userHandle); 6713 } 6714 6715 private boolean adminAllowsUnredactedNotifications(int userHandle) { 6716 if (userHandle == UserHandle.USER_ALL) { 6717 return true; 6718 } 6719 final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures(null /* admin */, 6720 userHandle); 6721 return (dpmFlags & DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS) == 0; 6722 } 6723 6724 /** 6725 * Returns true if we're on a secure lockscreen and the user wants to hide notification data. 6726 * If so, notifications should be hidden. 6727 */ 6728 @Override // NotificationData.Environment 6729 public boolean shouldHideNotifications(int userId) { 6730 return isLockscreenPublicMode(userId) && !userAllowsNotificationsInPublic(userId) 6731 || (userId != mCurrentUserId && shouldHideNotifications(mCurrentUserId)); 6732 } 6733 6734 /** 6735 * Returns true if we're on a secure lockscreen and the user wants to hide notifications via 6736 * package-specific override. 6737 */ 6738 @Override // NotificationDate.Environment 6739 public boolean shouldHideNotifications(String key) { 6740 return isLockscreenPublicMode(mCurrentUserId) 6741 && mNotificationData.getVisibilityOverride(key) == Notification.VISIBILITY_SECRET; 6742 } 6743 6744 /** 6745 * Returns true if we're on a secure lockscreen. 6746 */ 6747 @Override // NotificationData.Environment 6748 public boolean isSecurelyLocked(int userId) { 6749 return isLockscreenPublicMode(userId); 6750 } 6751 6752 public void onNotificationClear(StatusBarNotification notification) { 6753 try { 6754 mBarService.onNotificationClear( 6755 notification.getPackageName(), 6756 notification.getTag(), 6757 notification.getId(), 6758 notification.getUserId()); 6759 } catch (android.os.RemoteException ex) { 6760 // oh well 6761 } 6762 } 6763 6764 /** 6765 * Called when the notification panel layouts 6766 */ 6767 public void onPanelLaidOut() { 6768 updateKeyguardMaxNotifications(); 6769 } 6770 6771 public void updateKeyguardMaxNotifications() { 6772 if (mState == StatusBarState.KEYGUARD) { 6773 // Since the number of notifications is determined based on the height of the view, we 6774 // need to update them. 6775 int maxBefore = getMaxKeyguardNotifications(false /* recompute */); 6776 int maxNotifications = getMaxKeyguardNotifications(true /* recompute */); 6777 if (maxBefore != maxNotifications) { 6778 updateRowStates(); 6779 } 6780 } 6781 } 6782 6783 protected void inflateViews(Entry entry, ViewGroup parent) { 6784 PackageManager pmUser = getPackageManagerForUser(mContext, 6785 entry.notification.getUser().getIdentifier()); 6786 6787 final StatusBarNotification sbn = entry.notification; 6788 if (entry.row != null) { 6789 entry.reset(); 6790 updateNotification(entry, pmUser, sbn, entry.row); 6791 } else { 6792 new RowInflaterTask().inflate(mContext, parent, entry, 6793 row -> { 6794 bindRow(entry, pmUser, sbn, row); 6795 updateNotification(entry, pmUser, sbn, row); 6796 }); 6797 } 6798 6799 } 6800 6801 private void bindRow(Entry entry, PackageManager pmUser, 6802 StatusBarNotification sbn, ExpandableNotificationRow row) { 6803 row.setExpansionLogger(this, entry.notification.getKey()); 6804 row.setGroupManager(mGroupManager); 6805 row.setHeadsUpManager(mHeadsUpManager); 6806 row.setAboveShelfChangedListener(mAboveShelfObserver); 6807 row.setRemoteInputController(mRemoteInputController); 6808 row.setOnExpandClickListener(this); 6809 row.setRemoteViewClickHandler(mOnClickHandler); 6810 row.setInflationCallback(this); 6811 row.setSecureStateProvider(this::isKeyguardCurrentlySecure); 6812 6813 // Get the app name. 6814 // Note that Notification.Builder#bindHeaderAppName has similar logic 6815 // but since this field is used in the guts, it must be accurate. 6816 // Therefore we will only show the application label, or, failing that, the 6817 // package name. No substitutions. 6818 final String pkg = sbn.getPackageName(); 6819 String appname = pkg; 6820 try { 6821 final ApplicationInfo info = pmUser.getApplicationInfo(pkg, 6822 PackageManager.MATCH_UNINSTALLED_PACKAGES 6823 | PackageManager.MATCH_DISABLED_COMPONENTS); 6824 if (info != null) { 6825 appname = String.valueOf(pmUser.getApplicationLabel(info)); 6826 } 6827 } catch (NameNotFoundException e) { 6828 // Do nothing 6829 } 6830 row.setAppName(appname); 6831 row.setOnDismissRunnable(() -> 6832 performRemoveNotification(row.getStatusBarNotification())); 6833 row.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); 6834 if (ENABLE_REMOTE_INPUT) { 6835 row.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS); 6836 } 6837 } 6838 6839 private void updateNotification(Entry entry, PackageManager pmUser, 6840 StatusBarNotification sbn, ExpandableNotificationRow row) { 6841 row.setNeedsRedaction(needsRedaction(entry)); 6842 boolean isLowPriority = mNotificationData.isAmbient(sbn.getKey()); 6843 boolean isUpdate = mNotificationData.get(entry.key) != null; 6844 boolean wasLowPriority = row.isLowPriority(); 6845 row.setIsLowPriority(isLowPriority); 6846 row.setLowPriorityStateUpdated(isUpdate && (wasLowPriority != isLowPriority)); 6847 // bind the click event to the content area 6848 mNotificationClicker.register(row, sbn); 6849 6850 // Extract target SDK version. 6851 try { 6852 ApplicationInfo info = pmUser.getApplicationInfo(sbn.getPackageName(), 0); 6853 entry.targetSdk = info.targetSdkVersion; 6854 } catch (NameNotFoundException ex) { 6855 Log.e(TAG, "Failed looking up ApplicationInfo for " + sbn.getPackageName(), ex); 6856 } 6857 row.setLegacy(entry.targetSdk >= Build.VERSION_CODES.GINGERBREAD 6858 && entry.targetSdk < Build.VERSION_CODES.LOLLIPOP); 6859 entry.setIconTag(R.id.icon_is_pre_L, entry.targetSdk < Build.VERSION_CODES.LOLLIPOP); 6860 entry.autoRedacted = entry.notification.getNotification().publicVersion == null; 6861 6862 entry.row = row; 6863 entry.row.setOnActivatedListener(this); 6864 6865 boolean useIncreasedCollapsedHeight = mMessagingUtil.isImportantMessaging(sbn, 6866 mNotificationData.getImportance(sbn.getKey())); 6867 boolean useIncreasedHeadsUp = useIncreasedCollapsedHeight && mPanelExpanded; 6868 row.setUseIncreasedCollapsedHeight(useIncreasedCollapsedHeight); 6869 row.setUseIncreasedHeadsUpHeight(useIncreasedHeadsUp); 6870 row.updateNotification(entry); 6871 } 6872 6873 /** 6874 * Adds RemoteInput actions from the WearableExtender; to be removed once more apps support this 6875 * via first-class API. 6876 * 6877 * TODO: Remove once enough apps specify remote inputs on their own. 6878 */ 6879 private void processForRemoteInput(Notification n) { 6880 if (!ENABLE_REMOTE_INPUT) return; 6881 6882 if (n.extras != null && n.extras.containsKey("android.wearable.EXTENSIONS") && 6883 (n.actions == null || n.actions.length == 0)) { 6884 Notification.Action viableAction = null; 6885 Notification.WearableExtender we = new Notification.WearableExtender(n); 6886 6887 List<Notification.Action> actions = we.getActions(); 6888 final int numActions = actions.size(); 6889 6890 for (int i = 0; i < numActions; i++) { 6891 Notification.Action action = actions.get(i); 6892 if (action == null) { 6893 continue; 6894 } 6895 RemoteInput[] remoteInputs = action.getRemoteInputs(); 6896 if (remoteInputs == null) { 6897 continue; 6898 } 6899 for (RemoteInput ri : remoteInputs) { 6900 if (ri.getAllowFreeFormInput()) { 6901 viableAction = action; 6902 break; 6903 } 6904 } 6905 if (viableAction != null) { 6906 break; 6907 } 6908 } 6909 6910 if (viableAction != null) { 6911 Notification.Builder rebuilder = Notification.Builder.recoverBuilder(mContext, n); 6912 rebuilder.setActions(viableAction); 6913 rebuilder.build(); // will rewrite n 6914 } 6915 } 6916 } 6917 6918 public void startPendingIntentDismissingKeyguard(final PendingIntent intent) { 6919 if (!isDeviceProvisioned()) return; 6920 6921 final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing(); 6922 final boolean afterKeyguardGone = intent.isActivity() 6923 && PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(), 6924 mCurrentUserId); 6925 dismissKeyguardThenExecute(new OnDismissAction() { 6926 @Override 6927 public boolean onDismiss() { 6928 new Thread() { 6929 @Override 6930 public void run() { 6931 try { 6932 // The intent we are sending is for the application, which 6933 // won't have permission to immediately start an activity after 6934 // the user switches to home. We know it is safe to do at this 6935 // point, so make sure new activity switches are now allowed. 6936 ActivityManager.getService().resumeAppSwitches(); 6937 } catch (RemoteException e) { 6938 } 6939 try { 6940 intent.send(null, 0, null, null, null, null, getActivityOptions()); 6941 } catch (PendingIntent.CanceledException e) { 6942 // the stack trace isn't very helpful here. 6943 // Just log the exception message. 6944 Log.w(TAG, "Sending intent failed: " + e); 6945 6946 // TODO: Dismiss Keyguard. 6947 } 6948 if (intent.isActivity()) { 6949 mAssistManager.hideAssist(); 6950 } 6951 } 6952 }.start(); 6953 6954 if (!mNotificationPanel.isFullyCollapsed()) { 6955 // close the shade if it was open 6956 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, 6957 true /* force */, true /* delayed */); 6958 visibilityChanged(false); 6959 6960 return true; 6961 } else { 6962 return false; 6963 } 6964 } 6965 }, afterKeyguardGone); 6966 } 6967 6968 6969 private final class NotificationClicker implements View.OnClickListener { 6970 6971 @Override 6972 public void onClick(final View v) { 6973 if (!(v instanceof ExpandableNotificationRow)) { 6974 Log.e(TAG, "NotificationClicker called on a view that is not a notification row."); 6975 return; 6976 } 6977 6978 wakeUpIfDozing(SystemClock.uptimeMillis(), v); 6979 6980 final ExpandableNotificationRow row = (ExpandableNotificationRow) v; 6981 final StatusBarNotification sbn = row.getStatusBarNotification(); 6982 if (sbn == null) { 6983 Log.e(TAG, "NotificationClicker called on an unclickable notification,"); 6984 return; 6985 } 6986 6987 // Check if the notification is displaying the menu, if so slide notification back 6988 if (row.getProvider() != null && row.getProvider().isMenuVisible()) { 6989 row.animateTranslateNotification(0); 6990 return; 6991 } 6992 6993 Notification notification = sbn.getNotification(); 6994 final PendingIntent intent = notification.contentIntent != null 6995 ? notification.contentIntent 6996 : notification.fullScreenIntent; 6997 final String notificationKey = sbn.getKey(); 6998 6999 // Mark notification for one frame. 7000 row.setJustClicked(true); 7001 DejankUtils.postAfterTraversal(new Runnable() { 7002 @Override 7003 public void run() { 7004 row.setJustClicked(false); 7005 } 7006 }); 7007 7008 final boolean afterKeyguardGone = intent.isActivity() 7009 && PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(), 7010 mCurrentUserId); 7011 dismissKeyguardThenExecute(new OnDismissAction() { 7012 @Override 7013 public boolean onDismiss() { 7014 if (mHeadsUpManager != null && mHeadsUpManager.isHeadsUp(notificationKey)) { 7015 // Release the HUN notification to the shade. 7016 7017 if (isPanelFullyCollapsed()) { 7018 HeadsUpManager.setIsClickedNotification(row, true); 7019 } 7020 // 7021 // In most cases, when FLAG_AUTO_CANCEL is set, the notification will 7022 // become canceled shortly by NoMan, but we can't assume that. 7023 mHeadsUpManager.releaseImmediately(notificationKey); 7024 } 7025 StatusBarNotification parentToCancel = null; 7026 if (shouldAutoCancel(sbn) && mGroupManager.isOnlyChildInGroup(sbn)) { 7027 StatusBarNotification summarySbn = mGroupManager.getLogicalGroupSummary(sbn) 7028 .getStatusBarNotification(); 7029 if (shouldAutoCancel(summarySbn)) { 7030 parentToCancel = summarySbn; 7031 } 7032 } 7033 final StatusBarNotification parentToCancelFinal = parentToCancel; 7034 final Runnable runnable = new Runnable() { 7035 @Override 7036 public void run() { 7037 try { 7038 // The intent we are sending is for the application, which 7039 // won't have permission to immediately start an activity after 7040 // the user switches to home. We know it is safe to do at this 7041 // point, so make sure new activity switches are now allowed. 7042 ActivityManager.getService().resumeAppSwitches(); 7043 } catch (RemoteException e) { 7044 } 7045 if (intent != null) { 7046 // If we are launching a work activity and require to launch 7047 // separate work challenge, we defer the activity action and cancel 7048 // notification until work challenge is unlocked. 7049 if (intent.isActivity()) { 7050 final int userId = intent.getCreatorUserHandle() 7051 .getIdentifier(); 7052 if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId) 7053 && mKeyguardManager.isDeviceLocked(userId)) { 7054 // TODO(b/28935539): should allow certain activities to 7055 // bypass work challenge 7056 if (startWorkChallengeIfNecessary(userId, 7057 intent.getIntentSender(), notificationKey)) { 7058 // Show work challenge, do not run PendingIntent and 7059 // remove notification 7060 return; 7061 } 7062 } 7063 } 7064 try { 7065 intent.send(null, 0, null, null, null, null, 7066 getActivityOptions()); 7067 } catch (PendingIntent.CanceledException e) { 7068 // the stack trace isn't very helpful here. 7069 // Just log the exception message. 7070 Log.w(TAG, "Sending contentIntent failed: " + e); 7071 7072 // TODO: Dismiss Keyguard. 7073 } 7074 if (intent.isActivity()) { 7075 mAssistManager.hideAssist(); 7076 } 7077 } 7078 7079 try { 7080 mBarService.onNotificationClick(notificationKey); 7081 } catch (RemoteException ex) { 7082 // system process is dead if we're here. 7083 } 7084 if (parentToCancelFinal != null) { 7085 // We have to post it to the UI thread for synchronization 7086 mHandler.post(new Runnable() { 7087 @Override 7088 public void run() { 7089 Runnable removeRunnable = new Runnable() { 7090 @Override 7091 public void run() { 7092 performRemoveNotification(parentToCancelFinal); 7093 } 7094 }; 7095 if (isCollapsing()) { 7096 // To avoid lags we're only performing the remove 7097 // after the shade was collapsed 7098 addPostCollapseAction(removeRunnable); 7099 } else { 7100 removeRunnable.run(); 7101 } 7102 } 7103 }); 7104 } 7105 } 7106 }; 7107 7108 if (mStatusBarKeyguardViewManager.isShowing() 7109 && mStatusBarKeyguardViewManager.isOccluded()) { 7110 mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(runnable); 7111 } else { 7112 new Thread(runnable).start(); 7113 } 7114 7115 if (!mNotificationPanel.isFullyCollapsed()) { 7116 // close the shade if it was open 7117 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, 7118 true /* force */, true /* delayed */); 7119 visibilityChanged(false); 7120 7121 return true; 7122 } else { 7123 return false; 7124 } 7125 } 7126 }, afterKeyguardGone); 7127 } 7128 7129 private boolean shouldAutoCancel(StatusBarNotification sbn) { 7130 int flags = sbn.getNotification().flags; 7131 if ((flags & Notification.FLAG_AUTO_CANCEL) != Notification.FLAG_AUTO_CANCEL) { 7132 return false; 7133 } 7134 if ((flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) { 7135 return false; 7136 } 7137 return true; 7138 } 7139 7140 public void register(ExpandableNotificationRow row, StatusBarNotification sbn) { 7141 Notification notification = sbn.getNotification(); 7142 if (notification.contentIntent != null || notification.fullScreenIntent != null) { 7143 row.setOnClickListener(this); 7144 } else { 7145 row.setOnClickListener(null); 7146 } 7147 } 7148 } 7149 7150 protected Bundle getActivityOptions() { 7151 // Anything launched from the notification shade should always go into the 7152 // fullscreen stack. 7153 ActivityOptions options = ActivityOptions.makeBasic(); 7154 options.setLaunchStackId(StackId.FULLSCREEN_WORKSPACE_STACK_ID); 7155 return options.toBundle(); 7156 } 7157 7158 protected void visibilityChanged(boolean visible) { 7159 if (mVisible != visible) { 7160 mVisible = visible; 7161 if (!visible) { 7162 closeAndSaveGuts(true /* removeLeavebehind */, true /* force */, 7163 true /* removeControls */, -1 /* x */, -1 /* y */, true /* resetMenu */); 7164 } 7165 } 7166 updateVisibleToUser(); 7167 } 7168 7169 protected void updateVisibleToUser() { 7170 boolean oldVisibleToUser = mVisibleToUser; 7171 mVisibleToUser = mVisible && mDeviceInteractive; 7172 7173 if (oldVisibleToUser != mVisibleToUser) { 7174 handleVisibleToUserChanged(mVisibleToUser); 7175 } 7176 } 7177 7178 /** 7179 * Clear Buzz/Beep/Blink. 7180 */ 7181 public void clearNotificationEffects() { 7182 try { 7183 mBarService.clearNotificationEffects(); 7184 } catch (RemoteException e) { 7185 // Won't fail unless the world has ended. 7186 } 7187 } 7188 7189 /** 7190 * Cancel this notification and tell the StatusBarManagerService / NotificationManagerService 7191 * about the failure. 7192 * 7193 * WARNING: this will call back into us. Don't hold any locks. 7194 */ 7195 void handleNotificationError(StatusBarNotification n, String message) { 7196 removeNotification(n.getKey(), null); 7197 try { 7198 mBarService.onNotificationError(n.getPackageName(), n.getTag(), n.getId(), n.getUid(), 7199 n.getInitialPid(), message, n.getUserId()); 7200 } catch (RemoteException ex) { 7201 // The end is nigh. 7202 } 7203 } 7204 7205 protected StatusBarNotification removeNotificationViews(String key, RankingMap ranking) { 7206 NotificationData.Entry entry = mNotificationData.remove(key, ranking); 7207 if (entry == null) { 7208 Log.w(TAG, "removeNotification for unknown key: " + key); 7209 return null; 7210 } 7211 updateNotifications(); 7212 Dependency.get(LeakDetector.class).trackGarbage(entry); 7213 return entry.notification; 7214 } 7215 7216 protected NotificationData.Entry createNotificationViews(StatusBarNotification sbn) 7217 throws InflationException { 7218 if (DEBUG) { 7219 Log.d(TAG, "createNotificationViews(notification=" + sbn); 7220 } 7221 NotificationData.Entry entry = new NotificationData.Entry(sbn); 7222 Dependency.get(LeakDetector.class).trackInstance(entry); 7223 entry.createIcons(mContext, sbn); 7224 // Construct the expanded view. 7225 inflateViews(entry, mStackScroller); 7226 return entry; 7227 } 7228 7229 protected void addNotificationViews(Entry entry) { 7230 if (entry == null) { 7231 return; 7232 } 7233 // Add the expanded view and icon. 7234 mNotificationData.add(entry); 7235 updateNotifications(); 7236 } 7237 7238 /** 7239 * Updates expanded, dimmed and locked states of notification rows. 7240 */ 7241 protected void updateRowStates() { 7242 final int N = mStackScroller.getChildCount(); 7243 7244 int visibleNotifications = 0; 7245 boolean onKeyguard = mState == StatusBarState.KEYGUARD; 7246 int maxNotifications = -1; 7247 if (onKeyguard) { 7248 maxNotifications = getMaxKeyguardNotifications(true /* recompute */); 7249 } 7250 mStackScroller.setMaxDisplayedNotifications(maxNotifications); 7251 Stack<ExpandableNotificationRow> stack = new Stack<>(); 7252 for (int i = N - 1; i >= 0; i--) { 7253 View child = mStackScroller.getChildAt(i); 7254 if (!(child instanceof ExpandableNotificationRow)) { 7255 continue; 7256 } 7257 stack.push((ExpandableNotificationRow) child); 7258 } 7259 while(!stack.isEmpty()) { 7260 ExpandableNotificationRow row = stack.pop(); 7261 NotificationData.Entry entry = row.getEntry(); 7262 boolean isChildNotification = 7263 mGroupManager.isChildInGroupWithSummary(entry.notification); 7264 7265 row.setOnKeyguard(onKeyguard); 7266 7267 if (!onKeyguard) { 7268 // If mAlwaysExpandNonGroupedNotification is false, then only expand the 7269 // very first notification and if it's not a child of grouped notifications. 7270 row.setSystemExpanded(mAlwaysExpandNonGroupedNotification 7271 || (visibleNotifications == 0 && !isChildNotification 7272 && !row.isLowPriority())); 7273 } 7274 7275 entry.row.setShowAmbient(isDozing()); 7276 int userId = entry.notification.getUserId(); 7277 boolean suppressedSummary = mGroupManager.isSummaryOfSuppressedGroup( 7278 entry.notification) && !entry.row.isRemoved(); 7279 boolean showOnKeyguard = shouldShowOnKeyguard(entry.notification); 7280 if (suppressedSummary 7281 || (isLockscreenPublicMode(userId) && !mShowLockscreenNotifications) 7282 || (onKeyguard && !showOnKeyguard)) { 7283 entry.row.setVisibility(View.GONE); 7284 } else { 7285 boolean wasGone = entry.row.getVisibility() == View.GONE; 7286 if (wasGone) { 7287 entry.row.setVisibility(View.VISIBLE); 7288 } 7289 if (!isChildNotification && !entry.row.isRemoved()) { 7290 if (wasGone) { 7291 // notify the scroller of a child addition 7292 mStackScroller.generateAddAnimation(entry.row, 7293 !showOnKeyguard /* fromMoreCard */); 7294 } 7295 visibleNotifications++; 7296 } 7297 } 7298 if (row.isSummaryWithChildren()) { 7299 List<ExpandableNotificationRow> notificationChildren = 7300 row.getNotificationChildren(); 7301 int size = notificationChildren.size(); 7302 for (int i = size - 1; i >= 0; i--) { 7303 stack.push(notificationChildren.get(i)); 7304 } 7305 } 7306 } 7307 mNotificationPanel.setNoVisibleNotifications(visibleNotifications == 0); 7308 7309 // The following views will be moved to the end of mStackScroller. This counter represents 7310 // the offset from the last child. Initialized to 1 for the very last position. It is post- 7311 // incremented in the following "changeViewPosition" calls so that its value is correct for 7312 // subsequent calls. 7313 int offsetFromEnd = 1; 7314 if (mDismissView != null) { 7315 mStackScroller.changeViewPosition(mDismissView, 7316 mStackScroller.getChildCount() - offsetFromEnd++); 7317 } 7318 7319 mStackScroller.changeViewPosition(mEmptyShadeView, 7320 mStackScroller.getChildCount() - offsetFromEnd++); 7321 7322 // No post-increment for this call because it is the last one. Make sure to add one if 7323 // another "changeViewPosition" call is ever added. 7324 mStackScroller.changeViewPosition(mNotificationShelf, 7325 mStackScroller.getChildCount() - offsetFromEnd); 7326 7327 // Scrim opacity varies based on notification count 7328 mScrimController.setNotificationCount(mStackScroller.getNotGoneChildCount()); 7329 } 7330 7331 public boolean shouldShowOnKeyguard(StatusBarNotification sbn) { 7332 return mShowLockscreenNotifications && !mNotificationData.isAmbient(sbn.getKey()); 7333 } 7334 7335 // extended in StatusBar 7336 protected void setShowLockscreenNotifications(boolean show) { 7337 mShowLockscreenNotifications = show; 7338 } 7339 7340 protected void setLockScreenAllowRemoteInput(boolean allowLockscreenRemoteInput) { 7341 mAllowLockscreenRemoteInput = allowLockscreenRemoteInput; 7342 } 7343 7344 private void updateLockscreenNotificationSetting() { 7345 final boolean show = Settings.Secure.getIntForUser(mContext.getContentResolver(), 7346 Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 7347 1, 7348 mCurrentUserId) != 0; 7349 final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures( 7350 null /* admin */, mCurrentUserId); 7351 final boolean allowedByDpm = (dpmFlags 7352 & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS) == 0; 7353 7354 setShowLockscreenNotifications(show && allowedByDpm); 7355 7356 if (ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT) { 7357 final boolean remoteInput = Settings.Secure.getIntForUser(mContext.getContentResolver(), 7358 Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT, 7359 0, 7360 mCurrentUserId) != 0; 7361 final boolean remoteInputDpm = 7362 (dpmFlags & DevicePolicyManager.KEYGUARD_DISABLE_REMOTE_INPUT) == 0; 7363 7364 setLockScreenAllowRemoteInput(remoteInput && remoteInputDpm); 7365 } else { 7366 setLockScreenAllowRemoteInput(false); 7367 } 7368 } 7369 7370 public void updateNotification(StatusBarNotification notification, RankingMap ranking) 7371 throws InflationException { 7372 if (DEBUG) Log.d(TAG, "updateNotification(" + notification + ")"); 7373 7374 final String key = notification.getKey(); 7375 abortExistingInflation(key); 7376 Entry entry = mNotificationData.get(key); 7377 if (entry == null) { 7378 return; 7379 } 7380 mHeadsUpEntriesToRemoveOnSwitch.remove(entry); 7381 mRemoteInputEntriesToRemoveOnCollapse.remove(entry); 7382 if (key.equals(mKeyToRemoveOnGutsClosed)) { 7383 mKeyToRemoveOnGutsClosed = null; 7384 Log.w(TAG, "Notification that was kept for guts was updated. " + key); 7385 } 7386 7387 Notification n = notification.getNotification(); 7388 mNotificationData.updateRanking(ranking); 7389 7390 final StatusBarNotification oldNotification = entry.notification; 7391 entry.notification = notification; 7392 mGroupManager.onEntryUpdated(entry, oldNotification); 7393 7394 entry.updateIcons(mContext, notification); 7395 inflateViews(entry, mStackScroller); 7396 7397 mForegroundServiceController.updateNotification(notification, 7398 mNotificationData.getImportance(key)); 7399 7400 boolean shouldPeek = shouldPeek(entry, notification); 7401 boolean alertAgain = alertAgain(entry, n); 7402 7403 updateHeadsUp(key, entry, shouldPeek, alertAgain); 7404 updateNotifications(); 7405 7406 if (!notification.isClearable()) { 7407 // The user may have performed a dismiss action on the notification, since it's 7408 // not clearable we should snap it back. 7409 mStackScroller.snapViewIfNeeded(entry.row); 7410 } 7411 7412 if (DEBUG) { 7413 // Is this for you? 7414 boolean isForCurrentUser = isNotificationForCurrentProfiles(notification); 7415 Log.d(TAG, "notification is " + (isForCurrentUser ? "" : "not ") + "for you"); 7416 } 7417 7418 setAreThereNotifications(); 7419 } 7420 7421 protected void notifyHeadsUpGoingToSleep() { 7422 maybeEscalateHeadsUp(); 7423 } 7424 7425 private boolean alertAgain(Entry oldEntry, Notification newNotification) { 7426 return oldEntry == null || !oldEntry.hasInterrupted() 7427 || (newNotification.flags & Notification.FLAG_ONLY_ALERT_ONCE) == 0; 7428 } 7429 7430 protected boolean shouldPeek(Entry entry) { 7431 return shouldPeek(entry, entry.notification); 7432 } 7433 7434 protected boolean shouldPeek(Entry entry, StatusBarNotification sbn) { 7435 if (!mUseHeadsUp || isDeviceInVrMode()) { 7436 if (DEBUG) Log.d(TAG, "No peeking: no huns or vr mode"); 7437 return false; 7438 } 7439 7440 if (mNotificationData.shouldFilterOut(sbn)) { 7441 if (DEBUG) Log.d(TAG, "No peeking: filtered notification: " + sbn.getKey()); 7442 return false; 7443 } 7444 7445 boolean inUse = mPowerManager.isScreenOn() && !mSystemServicesProxy.isDreaming(); 7446 7447 if (!inUse && !isDozing()) { 7448 if (DEBUG) { 7449 Log.d(TAG, "No peeking: not in use: " + sbn.getKey()); 7450 } 7451 return false; 7452 } 7453 7454 if (!isDozing() && mNotificationData.shouldSuppressScreenOn(sbn.getKey())) { 7455 if (DEBUG) Log.d(TAG, "No peeking: suppressed by DND: " + sbn.getKey()); 7456 return false; 7457 } 7458 7459 if (isDozing() && mNotificationData.shouldSuppressScreenOff(sbn.getKey())) { 7460 if (DEBUG) Log.d(TAG, "No peeking: suppressed by DND: " + sbn.getKey()); 7461 return false; 7462 } 7463 7464 if (entry.hasJustLaunchedFullScreenIntent()) { 7465 if (DEBUG) Log.d(TAG, "No peeking: recent fullscreen: " + sbn.getKey()); 7466 return false; 7467 } 7468 7469 if (isSnoozedPackage(sbn)) { 7470 if (DEBUG) Log.d(TAG, "No peeking: snoozed package: " + sbn.getKey()); 7471 return false; 7472 } 7473 7474 // Allow peeking for DEFAULT notifications only if we're on Ambient Display. 7475 int importanceLevel = isDozing() ? NotificationManager.IMPORTANCE_DEFAULT 7476 : NotificationManager.IMPORTANCE_HIGH; 7477 if (mNotificationData.getImportance(sbn.getKey()) < importanceLevel) { 7478 if (DEBUG) Log.d(TAG, "No peeking: unimportant notification: " + sbn.getKey()); 7479 return false; 7480 } 7481 7482 if (sbn.getNotification().fullScreenIntent != null) { 7483 if (mAccessibilityManager.isTouchExplorationEnabled()) { 7484 if (DEBUG) Log.d(TAG, "No peeking: accessible fullscreen: " + sbn.getKey()); 7485 return false; 7486 } else if (mDozing) { 7487 // We never want heads up when we are dozing. 7488 return false; 7489 } else { 7490 // we only allow head-up on the lockscreen if it doesn't have a fullscreen intent 7491 return !mStatusBarKeyguardViewManager.isShowing() 7492 || mStatusBarKeyguardViewManager.isOccluded(); 7493 } 7494 } 7495 7496 // Don't peek notifications that are suppressed due to group alert behavior 7497 if (sbn.isGroup() && sbn.getNotification().suppressAlertingDueToGrouping()) { 7498 if (DEBUG) Log.d(TAG, "No peeking: suppressed due to group alert behavior"); 7499 return false; 7500 } 7501 7502 return true; 7503 } 7504 7505 /** 7506 * @return Whether the security bouncer from Keyguard is showing. 7507 */ 7508 public boolean isBouncerShowing() { 7509 return mBouncerShowing; 7510 } 7511 7512 /** 7513 * @return a PackageManger for userId or if userId is < 0 (USER_ALL etc) then 7514 * return PackageManager for mContext 7515 */ 7516 public static PackageManager getPackageManagerForUser(Context context, int userId) { 7517 Context contextForUser = context; 7518 // UserHandle defines special userId as negative values, e.g. USER_ALL 7519 if (userId >= 0) { 7520 try { 7521 // Create a context for the correct user so if a package isn't installed 7522 // for user 0 we can still load information about the package. 7523 contextForUser = 7524 context.createPackageContextAsUser(context.getPackageName(), 7525 Context.CONTEXT_RESTRICTED, 7526 new UserHandle(userId)); 7527 } catch (NameNotFoundException e) { 7528 // Shouldn't fail to find the package name for system ui. 7529 } 7530 } 7531 return contextForUser.getPackageManager(); 7532 } 7533 7534 @Override 7535 public void logNotificationExpansion(String key, boolean userAction, boolean expanded) { 7536 mUiOffloadThread.submit(() -> { 7537 try { 7538 mBarService.onNotificationExpansionChanged(key, userAction, expanded); 7539 } catch (RemoteException e) { 7540 // Ignore. 7541 } 7542 }); 7543 } 7544 7545 public boolean isKeyguardSecure() { 7546 if (mStatusBarKeyguardViewManager == null) { 7547 // startKeyguard() hasn't been called yet, so we don't know. 7548 // Make sure anything that needs to know isKeyguardSecure() checks and re-checks this 7549 // value onVisibilityChanged(). 7550 Slog.w(TAG, "isKeyguardSecure() called before startKeyguard(), returning false", 7551 new Throwable()); 7552 return false; 7553 } 7554 return mStatusBarKeyguardViewManager.isSecure(); 7555 } 7556 7557 @Override 7558 public void showAssistDisclosure() { 7559 if (mAssistManager != null) { 7560 mAssistManager.showDisclosure(); 7561 } 7562 } 7563 7564 public NotificationPanelView getPanel() { 7565 return mNotificationPanel; 7566 } 7567 7568 @Override 7569 public void startAssist(Bundle args) { 7570 if (mAssistManager != null) { 7571 mAssistManager.startAssist(args); 7572 } 7573 } 7574 // End Extra BaseStatusBarMethods. 7575 7576 private final Runnable mAutoDim = () -> { 7577 if (mNavigationBar != null) { 7578 mNavigationBar.getBarTransitions().setAutoDim(true); 7579 } 7580 }; 7581 } 7582