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