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