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