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