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