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