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