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