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