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