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