1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.statusbar.phone; 18 19 20 import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT; 21 import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN; 22 import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN; 23 import static android.app.StatusBarManager.WINDOW_STATE_SHOWING; 24 import static android.app.StatusBarManager.windowStateToString; 25 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT; 26 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT; 27 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE; 28 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT; 29 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSLUCENT; 30 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT; 31 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_WARNING; 32 33 import android.animation.Animator; 34 import android.animation.AnimatorListenerAdapter; 35 import android.annotation.NonNull; 36 import android.app.ActivityManager; 37 import android.app.ActivityManagerNative; 38 import android.app.ActivityOptions; 39 import android.app.IActivityManager; 40 import android.app.Notification; 41 import android.app.PendingIntent; 42 import android.app.StatusBarManager; 43 import android.content.BroadcastReceiver; 44 import android.content.ComponentCallbacks2; 45 import android.content.ComponentName; 46 import android.content.Context; 47 import android.content.Intent; 48 import android.content.IntentFilter; 49 import android.content.IntentSender; 50 import android.content.pm.IPackageManager; 51 import android.content.pm.PackageManager; 52 import android.content.pm.UserInfo; 53 import android.content.res.Configuration; 54 import android.content.res.Resources; 55 import android.database.ContentObserver; 56 import android.graphics.Bitmap; 57 import android.graphics.Canvas; 58 import android.graphics.ColorFilter; 59 import android.graphics.PixelFormat; 60 import android.graphics.Point; 61 import android.graphics.PointF; 62 import android.graphics.PorterDuff; 63 import android.graphics.PorterDuffXfermode; 64 import android.graphics.Rect; 65 import android.graphics.drawable.BitmapDrawable; 66 import android.graphics.drawable.ColorDrawable; 67 import android.graphics.drawable.Drawable; 68 import android.inputmethodservice.InputMethodService; 69 import android.media.AudioAttributes; 70 import android.media.MediaMetadata; 71 import android.media.session.MediaController; 72 import android.media.session.MediaSession; 73 import android.media.session.MediaSessionManager; 74 import android.media.session.PlaybackState; 75 import android.net.Uri; 76 import android.os.AsyncTask; 77 import android.os.Bundle; 78 import android.os.Handler; 79 import android.os.HandlerThread; 80 import android.os.IBinder; 81 import android.os.Message; 82 import android.os.PowerManager; 83 import android.os.Process; 84 import android.os.RemoteException; 85 import android.os.ServiceManager; 86 import android.os.SystemClock; 87 import android.os.Trace; 88 import android.os.SystemProperties; 89 import android.os.UserHandle; 90 import android.os.UserManager; 91 import android.os.Vibrator; 92 import android.provider.Settings; 93 import android.service.notification.NotificationListenerService; 94 import android.service.notification.NotificationListenerService.RankingMap; 95 import android.service.notification.StatusBarNotification; 96 import android.telecom.TelecomManager; 97 import android.util.ArraySet; 98 import android.util.DisplayMetrics; 99 import android.util.EventLog; 100 import android.util.Log; 101 import android.view.Display; 102 import android.view.IRotationWatcher; 103 import android.view.KeyEvent; 104 import android.view.LayoutInflater; 105 import android.view.MotionEvent; 106 import android.view.ThreadedRenderer; 107 import android.view.View; 108 import android.view.ViewGroup; 109 import android.view.ViewGroup.LayoutParams; 110 import android.view.ViewParent; 111 import android.view.ViewStub; 112 import android.view.ViewTreeObserver; 113 import android.view.WindowManager; 114 import android.view.WindowManagerGlobal; 115 import android.view.animation.AccelerateInterpolator; 116 import android.view.animation.Interpolator; 117 import android.widget.ImageView; 118 import android.widget.TextView; 119 120 import com.android.internal.logging.MetricsLogger; 121 import com.android.internal.logging.MetricsProto.MetricsEvent; 122 import com.android.internal.statusbar.NotificationVisibility; 123 import com.android.internal.statusbar.StatusBarIcon; 124 import com.android.keyguard.KeyguardHostView.OnDismissAction; 125 import com.android.keyguard.KeyguardUpdateMonitor; 126 import com.android.keyguard.KeyguardUpdateMonitorCallback; 127 import com.android.keyguard.ViewMediatorCallback; 128 import com.android.systemui.AutoReinflateContainer; 129 import com.android.systemui.AutoReinflateContainer.InflateListener; 130 import com.android.systemui.BatteryMeterView; 131 import com.android.systemui.DemoMode; 132 import com.android.systemui.EventLogConstants; 133 import com.android.systemui.EventLogTags; 134 import com.android.systemui.Interpolators; 135 import com.android.systemui.Prefs; 136 import com.android.systemui.R; 137 import com.android.systemui.SystemUIFactory; 138 import com.android.systemui.classifier.FalsingLog; 139 import com.android.systemui.classifier.FalsingManager; 140 import com.android.systemui.doze.DozeHost; 141 import com.android.systemui.doze.DozeLog; 142 import com.android.systemui.keyguard.KeyguardViewMediator; 143 import com.android.systemui.qs.QSContainer; 144 import com.android.systemui.qs.QSPanel; 145 import com.android.systemui.recents.ScreenPinningRequest; 146 import com.android.systemui.recents.events.EventBus; 147 import com.android.systemui.recents.events.activity.AppTransitionFinishedEvent; 148 import com.android.systemui.recents.events.activity.UndockingTaskEvent; 149 import com.android.systemui.stackdivider.Divider; 150 import com.android.systemui.stackdivider.WindowManagerProxy; 151 import com.android.systemui.statusbar.ActivatableNotificationView; 152 import com.android.systemui.statusbar.BackDropView; 153 import com.android.systemui.statusbar.BaseStatusBar; 154 import com.android.systemui.statusbar.CommandQueue; 155 import com.android.systemui.statusbar.DismissView; 156 import com.android.systemui.statusbar.DragDownHelper; 157 import com.android.systemui.statusbar.EmptyShadeView; 158 import com.android.systemui.statusbar.ExpandableNotificationRow; 159 import com.android.systemui.statusbar.GestureRecorder; 160 import com.android.systemui.statusbar.KeyboardShortcuts; 161 import com.android.systemui.statusbar.KeyguardIndicationController; 162 import com.android.systemui.statusbar.NotificationData; 163 import com.android.systemui.statusbar.NotificationData.Entry; 164 import com.android.systemui.statusbar.NotificationOverflowContainer; 165 import com.android.systemui.statusbar.RemoteInputController; 166 import com.android.systemui.statusbar.ScrimView; 167 import com.android.systemui.statusbar.SignalClusterView; 168 import com.android.systemui.statusbar.StatusBarState; 169 import com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChangedListener; 170 import com.android.systemui.statusbar.policy.AccessibilityController; 171 import com.android.systemui.statusbar.policy.BatteryController; 172 import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback; 173 import com.android.systemui.statusbar.policy.BatteryControllerImpl; 174 import com.android.systemui.statusbar.policy.BluetoothControllerImpl; 175 import com.android.systemui.statusbar.policy.BrightnessMirrorController; 176 import com.android.systemui.statusbar.policy.CastControllerImpl; 177 import com.android.systemui.statusbar.policy.FlashlightController; 178 import com.android.systemui.statusbar.policy.HeadsUpManager; 179 import com.android.systemui.statusbar.policy.HotspotControllerImpl; 180 import com.android.systemui.statusbar.policy.KeyguardMonitor; 181 import com.android.systemui.statusbar.policy.KeyguardUserSwitcher; 182 import com.android.systemui.statusbar.policy.LocationControllerImpl; 183 import com.android.systemui.statusbar.policy.NetworkControllerImpl; 184 import com.android.systemui.statusbar.policy.NextAlarmController; 185 import com.android.systemui.statusbar.policy.PreviewInflater; 186 import com.android.systemui.statusbar.policy.RotationLockControllerImpl; 187 import com.android.systemui.statusbar.policy.SecurityControllerImpl; 188 import com.android.systemui.statusbar.policy.UserInfoController; 189 import com.android.systemui.statusbar.policy.UserSwitcherController; 190 import com.android.systemui.statusbar.policy.ZenModeController; 191 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout; 192 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout 193 .OnChildLocationsChangedListener; 194 import com.android.systemui.statusbar.stack.StackStateAnimator; 195 import com.android.systemui.statusbar.stack.StackViewState; 196 import com.android.systemui.volume.VolumeComponent; 197 198 import java.io.FileDescriptor; 199 import java.io.PrintWriter; 200 import java.io.StringWriter; 201 import java.util.ArrayList; 202 import java.util.Collection; 203 import java.util.Collections; 204 import java.util.HashMap; 205 import java.util.List; 206 import java.util.Map; 207 208 public class PhoneStatusBar extends BaseStatusBar implements DemoMode, 209 DragDownHelper.DragDownCallback, ActivityStarter, OnUnlockMethodChangedListener, 210 HeadsUpManager.OnHeadsUpChangedListener { 211 static final String TAG = "PhoneStatusBar"; 212 public static final boolean DEBUG = BaseStatusBar.DEBUG; 213 public static final boolean SPEW = false; 214 public static final boolean DUMPTRUCK = true; // extra dumpsys info 215 public static final boolean DEBUG_GESTURES = false; 216 public static final boolean DEBUG_MEDIA = false; 217 public static final boolean DEBUG_MEDIA_FAKE_ARTWORK = false; 218 219 public static final boolean DEBUG_WINDOW_STATE = false; 220 221 // additional instrumentation for testing purposes; intended to be left on during development 222 public static final boolean CHATTY = DEBUG; 223 224 public static final boolean SHOW_LOCKSCREEN_MEDIA_ARTWORK = true; 225 226 public static final String ACTION_FAKE_ARTWORK = "fake_artwork"; 227 228 private static final int MSG_OPEN_NOTIFICATION_PANEL = 1000; 229 private static final int MSG_CLOSE_PANELS = 1001; 230 private static final int MSG_OPEN_SETTINGS_PANEL = 1002; 231 private static final int MSG_LAUNCH_TRANSITION_TIMEOUT = 1003; 232 // 1020-1040 reserved for BaseStatusBar 233 234 // Time after we abort the launch transition. 235 private static final long LAUNCH_TRANSITION_TIMEOUT_MS = 5000; 236 237 private static final boolean CLOSE_PANEL_WHEN_EMPTIED = true; 238 239 private static final int STATUS_OR_NAV_TRANSIENT = 240 View.STATUS_BAR_TRANSIENT | View.NAVIGATION_BAR_TRANSIENT; 241 private static final long AUTOHIDE_TIMEOUT_MS = 3000; 242 243 /** The minimum delay in ms between reports of notification visibility. */ 244 private static final int VISIBILITY_REPORT_MIN_DELAY_MS = 500; 245 246 /** 247 * The delay to reset the hint text when the hint animation is finished running. 248 */ 249 private static final int HINT_RESET_DELAY_MS = 1200; 250 251 private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder() 252 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) 253 .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION) 254 .build(); 255 256 public static final int FADE_KEYGUARD_START_DELAY = 100; 257 public static final int FADE_KEYGUARD_DURATION = 300; 258 public static final int FADE_KEYGUARD_DURATION_PULSING = 96; 259 260 /** Allow some time inbetween the long press for back and recents. */ 261 private static final int LOCK_TO_APP_GESTURE_TOLERENCE = 200; 262 263 /** If true, the system is in the half-boot-to-decryption-screen state. 264 * Prudently disable QS and notifications. */ 265 private static final boolean ONLY_CORE_APPS; 266 267 /** If true, the lockscreen will show a distinct wallpaper */ 268 private static final boolean ENABLE_LOCKSCREEN_WALLPAPER = true; 269 270 /* If true, the device supports freeform window management. 271 * This affects the status bar UI. */ 272 private static final boolean FREEFORM_WINDOW_MANAGEMENT; 273 274 /** 275 * How long to wait before auto-dismissing a notification that was kept for remote input, and 276 * has now sent a remote input. We auto-dismiss, because the app may not see a reason to cancel 277 * these given that they technically don't exist anymore. We wait a bit in case the app issues 278 * an update. 279 */ 280 private static final int REMOTE_INPUT_KEPT_ENTRY_AUTO_CANCEL_DELAY = 200; 281 282 static { 283 boolean onlyCoreApps; 284 boolean freeformWindowManagement; 285 try { 286 IPackageManager packageManager = 287 IPackageManager.Stub.asInterface(ServiceManager.getService("package")); 288 onlyCoreApps = packageManager.isOnlyCoreApps(); 289 freeformWindowManagement = packageManager.hasSystemFeature( 290 PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT, 0); 291 } catch (RemoteException e) { 292 onlyCoreApps = false; 293 freeformWindowManagement = false; 294 } 295 ONLY_CORE_APPS = onlyCoreApps; 296 FREEFORM_WINDOW_MANAGEMENT = freeformWindowManagement; 297 } 298 299 PhoneStatusBarPolicy mIconPolicy; 300 301 // These are no longer handled by the policy, because we need custom strategies for them 302 BluetoothControllerImpl mBluetoothController; 303 SecurityControllerImpl mSecurityController; 304 protected BatteryController mBatteryController; 305 LocationControllerImpl mLocationController; 306 NetworkControllerImpl mNetworkController; 307 HotspotControllerImpl mHotspotController; 308 RotationLockControllerImpl mRotationLockController; 309 UserInfoController mUserInfoController; 310 protected ZenModeController mZenModeController; 311 CastControllerImpl mCastController; 312 VolumeComponent mVolumeComponent; 313 KeyguardUserSwitcher mKeyguardUserSwitcher; 314 FlashlightController mFlashlightController; 315 protected UserSwitcherController mUserSwitcherController; 316 NextAlarmController mNextAlarmController; 317 protected KeyguardMonitor mKeyguardMonitor; 318 BrightnessMirrorController mBrightnessMirrorController; 319 AccessibilityController mAccessibilityController; 320 FingerprintUnlockController mFingerprintUnlockController; 321 LightStatusBarController mLightStatusBarController; 322 protected LockscreenWallpaper mLockscreenWallpaper; 323 324 int mNaturalBarHeight = -1; 325 326 Display mDisplay; 327 Point mCurrentDisplaySize = new Point(); 328 329 protected StatusBarWindowView mStatusBarWindow; 330 protected PhoneStatusBarView mStatusBarView; 331 private int mStatusBarWindowState = WINDOW_STATE_SHOWING; 332 protected StatusBarWindowManager mStatusBarWindowManager; 333 private UnlockMethodCache mUnlockMethodCache; 334 private DozeServiceHost mDozeServiceHost; 335 private boolean mWakeUpComingFromTouch; 336 private PointF mWakeUpTouchLocation; 337 private boolean mScreenTurningOn; 338 339 int mPixelFormat; 340 Object mQueueLock = new Object(); 341 342 protected StatusBarIconController mIconController; 343 344 // expanded notifications 345 protected NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window 346 View mExpandedContents; 347 TextView mNotificationPanelDebugText; 348 349 // settings 350 private QSPanel mQSPanel; 351 352 // top bar 353 BaseStatusBarHeader mHeader; 354 protected KeyguardStatusBarView mKeyguardStatusBar; 355 View mKeyguardStatusView; 356 KeyguardBottomAreaView mKeyguardBottomArea; 357 boolean mLeaveOpenOnKeyguardHide; 358 KeyguardIndicationController mKeyguardIndicationController; 359 360 // Keyguard is going away soon. 361 private boolean mKeyguardGoingAway; 362 // Keyguard is actually fading away now. 363 private boolean mKeyguardFadingAway; 364 private long mKeyguardFadingAwayDelay; 365 private long mKeyguardFadingAwayDuration; 366 367 // RemoteInputView to be activated after unlock 368 private View mPendingRemoteInputView; 369 private View mPendingWorkRemoteInputView; 370 371 private View mReportRejectedTouch; 372 373 int mMaxAllowedKeyguardNotifications; 374 375 boolean mExpandedVisible; 376 377 private int mNavigationBarWindowState = WINDOW_STATE_SHOWING; 378 379 // the tracker view 380 int mTrackingPosition; // the position of the top of the tracking view. 381 382 // Tracking finger for opening/closing. 383 boolean mTracking; 384 385 int[] mAbsPos = new int[2]; 386 ArrayList<Runnable> mPostCollapseRunnables = new ArrayList<>(); 387 388 // for disabling the status bar 389 int mDisabled1 = 0; 390 int mDisabled2 = 0; 391 392 // tracking calls to View.setSystemUiVisibility() 393 int mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE; 394 private final Rect mLastFullscreenStackBounds = new Rect(); 395 private final Rect mLastDockedStackBounds = new Rect(); 396 397 // last value sent to window manager 398 private int mLastDispatchedSystemUiVisibility = ~View.SYSTEM_UI_FLAG_VISIBLE; 399 400 DisplayMetrics mDisplayMetrics = new DisplayMetrics(); 401 402 // XXX: gesture research 403 private final GestureRecorder mGestureRec = DEBUG_GESTURES 404 ? new GestureRecorder("/sdcard/statusbar_gestures.dat") 405 : null; 406 407 private ScreenPinningRequest mScreenPinningRequest; 408 409 private int mNavigationIconHints = 0; 410 private HandlerThread mHandlerThread; 411 412 // ensure quick settings is disabled until the current user makes it through the setup wizard 413 private boolean mUserSetup = false; 414 private ContentObserver mUserSetupObserver = new ContentObserver(new Handler()) { 415 @Override 416 public void onChange(boolean selfChange) { 417 final boolean userSetup = 0 != Settings.Secure.getIntForUser( 418 mContext.getContentResolver(), 419 Settings.Secure.USER_SETUP_COMPLETE, 420 0 /*default */, 421 mCurrentUserId); 422 if (MULTIUSER_DEBUG) Log.d(TAG, String.format("User setup changed: " + 423 "selfChange=%s userSetup=%s mUserSetup=%s", 424 selfChange, userSetup, mUserSetup)); 425 426 if (userSetup != mUserSetup) { 427 mUserSetup = userSetup; 428 if (!mUserSetup && mStatusBarView != null) 429 animateCollapseQuickSettings(); 430 if (mKeyguardBottomArea != null) { 431 mKeyguardBottomArea.setUserSetupComplete(mUserSetup); 432 } 433 if (mNetworkController != null) { 434 mNetworkController.setUserSetupComplete(mUserSetup); 435 } 436 } 437 if (mIconPolicy != null) { 438 mIconPolicy.setCurrentUserSetup(mUserSetup); 439 } 440 } 441 }; 442 443 final private ContentObserver mHeadsUpObserver = new ContentObserver(mHandler) { 444 @Override 445 public void onChange(boolean selfChange) { 446 boolean wasUsing = mUseHeadsUp; 447 mUseHeadsUp = ENABLE_HEADS_UP && !mDisableNotificationAlerts 448 && Settings.Global.HEADS_UP_OFF != Settings.Global.getInt( 449 mContext.getContentResolver(), Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED, 450 Settings.Global.HEADS_UP_OFF); 451 mHeadsUpTicker = mUseHeadsUp && 0 != Settings.Global.getInt( 452 mContext.getContentResolver(), SETTING_HEADS_UP_TICKER, 0); 453 Log.d(TAG, "heads up is " + (mUseHeadsUp ? "enabled" : "disabled")); 454 if (wasUsing != mUseHeadsUp) { 455 if (!mUseHeadsUp) { 456 Log.d(TAG, "dismissing any existing heads up notification on disable event"); 457 mHeadsUpManager.releaseAllImmediately(); 458 } 459 } 460 } 461 }; 462 463 private int mInteractingWindows; 464 private boolean mAutohideSuspended; 465 private int mStatusBarMode; 466 private int mNavigationBarMode; 467 private int mMaxKeyguardNotifications; 468 469 private ViewMediatorCallback mKeyguardViewMediatorCallback; 470 protected ScrimController mScrimController; 471 protected DozeScrimController mDozeScrimController; 472 473 private final Runnable mAutohide = new Runnable() { 474 @Override 475 public void run() { 476 int requested = mSystemUiVisibility & ~STATUS_OR_NAV_TRANSIENT; 477 if (mSystemUiVisibility != requested) { 478 notifyUiVisibilityChanged(requested); 479 } 480 }}; 481 482 private boolean mWaitingForKeyguardExit; 483 private boolean mDozing; 484 private boolean mDozingRequested; 485 protected boolean mScrimSrcModeEnabled; 486 487 public static final Interpolator ALPHA_IN = Interpolators.ALPHA_IN; 488 public static final Interpolator ALPHA_OUT = Interpolators.ALPHA_OUT; 489 490 private BackDropView mBackdrop; 491 private ImageView mBackdropFront, mBackdropBack; 492 private PorterDuffXfermode mSrcXferMode = new PorterDuffXfermode(PorterDuff.Mode.SRC); 493 private PorterDuffXfermode mSrcOverXferMode = new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER); 494 495 private MediaSessionManager mMediaSessionManager; 496 private MediaController mMediaController; 497 private String mMediaNotificationKey; 498 private MediaMetadata mMediaMetadata; 499 private MediaController.Callback mMediaListener 500 = new MediaController.Callback() { 501 @Override 502 public void onPlaybackStateChanged(PlaybackState state) { 503 super.onPlaybackStateChanged(state); 504 if (DEBUG_MEDIA) Log.v(TAG, "DEBUG_MEDIA: onPlaybackStateChanged: " + state); 505 if (state != null) { 506 if (!isPlaybackActive(state.getState())) { 507 clearCurrentMediaNotification(); 508 updateMediaMetaData(true, true); 509 } 510 } 511 } 512 513 @Override 514 public void onMetadataChanged(MediaMetadata metadata) { 515 super.onMetadataChanged(metadata); 516 if (DEBUG_MEDIA) Log.v(TAG, "DEBUG_MEDIA: onMetadataChanged: " + metadata); 517 mMediaMetadata = metadata; 518 updateMediaMetaData(true, true); 519 } 520 }; 521 522 private final OnChildLocationsChangedListener mOnChildLocationsChangedListener = 523 new OnChildLocationsChangedListener() { 524 @Override 525 public void onChildLocationsChanged(NotificationStackScrollLayout stackScrollLayout) { 526 userActivity(); 527 } 528 }; 529 530 private int mDisabledUnmodified1; 531 private int mDisabledUnmodified2; 532 533 /** Keys of notifications currently visible to the user. */ 534 private final ArraySet<NotificationVisibility> mCurrentlyVisibleNotifications = 535 new ArraySet<>(); 536 private long mLastVisibilityReportUptimeMs; 537 538 private final ShadeUpdates mShadeUpdates = new ShadeUpdates(); 539 540 private Runnable mLaunchTransitionEndRunnable; 541 private boolean mLaunchTransitionFadingAway; 542 private ExpandableNotificationRow mDraggedDownRow; 543 private boolean mLaunchCameraOnScreenTurningOn; 544 private boolean mLaunchCameraOnFinishedGoingToSleep; 545 private int mLastCameraLaunchSource; 546 private PowerManager.WakeLock mGestureWakeLock; 547 private Vibrator mVibrator; 548 549 // Fingerprint (as computed by getLoggingFingerprint() of the last logged state. 550 private int mLastLoggedStateFingerprint; 551 552 /** 553 * If set, the device has started going to sleep but isn't fully non-interactive yet. 554 */ 555 protected boolean mStartedGoingToSleep; 556 557 private static final int VISIBLE_LOCATIONS = StackViewState.LOCATION_FIRST_HUN 558 | StackViewState.LOCATION_MAIN_AREA; 559 560 private final OnChildLocationsChangedListener mNotificationLocationsChangedListener = 561 new OnChildLocationsChangedListener() { 562 @Override 563 public void onChildLocationsChanged( 564 NotificationStackScrollLayout stackScrollLayout) { 565 if (mHandler.hasCallbacks(mVisibilityReporter)) { 566 // Visibilities will be reported when the existing 567 // callback is executed. 568 return; 569 } 570 // Calculate when we're allowed to run the visibility 571 // reporter. Note that this timestamp might already have 572 // passed. That's OK, the callback will just be executed 573 // ASAP. 574 long nextReportUptimeMs = 575 mLastVisibilityReportUptimeMs + VISIBILITY_REPORT_MIN_DELAY_MS; 576 mHandler.postAtTime(mVisibilityReporter, nextReportUptimeMs); 577 } 578 }; 579 580 // Tracks notifications currently visible in mNotificationStackScroller and 581 // emits visibility events via NoMan on changes. 582 private final Runnable mVisibilityReporter = new Runnable() { 583 private final ArraySet<NotificationVisibility> mTmpNewlyVisibleNotifications = 584 new ArraySet<>(); 585 private final ArraySet<NotificationVisibility> mTmpCurrentlyVisibleNotifications = 586 new ArraySet<>(); 587 private final ArraySet<NotificationVisibility> mTmpNoLongerVisibleNotifications = 588 new ArraySet<>(); 589 590 @Override 591 public void run() { 592 mLastVisibilityReportUptimeMs = SystemClock.uptimeMillis(); 593 final String mediaKey = getCurrentMediaNotificationKey(); 594 595 // 1. Loop over mNotificationData entries: 596 // A. Keep list of visible notifications. 597 // B. Keep list of previously hidden, now visible notifications. 598 // 2. Compute no-longer visible notifications by removing currently 599 // visible notifications from the set of previously visible 600 // notifications. 601 // 3. Report newly visible and no-longer visible notifications. 602 // 4. Keep currently visible notifications for next report. 603 ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications(); 604 int N = activeNotifications.size(); 605 for (int i = 0; i < N; i++) { 606 Entry entry = activeNotifications.get(i); 607 String key = entry.notification.getKey(); 608 boolean isVisible = 609 (mStackScroller.getChildLocation(entry.row) & VISIBLE_LOCATIONS) != 0; 610 NotificationVisibility visObj = NotificationVisibility.obtain(key, i, isVisible); 611 boolean previouslyVisible = mCurrentlyVisibleNotifications.contains(visObj); 612 if (isVisible) { 613 // Build new set of visible notifications. 614 mTmpCurrentlyVisibleNotifications.add(visObj); 615 if (!previouslyVisible) { 616 mTmpNewlyVisibleNotifications.add(visObj); 617 } 618 } else { 619 // release object 620 visObj.recycle(); 621 } 622 } 623 mTmpNoLongerVisibleNotifications.addAll(mCurrentlyVisibleNotifications); 624 mTmpNoLongerVisibleNotifications.removeAll(mTmpCurrentlyVisibleNotifications); 625 626 logNotificationVisibilityChanges( 627 mTmpNewlyVisibleNotifications, mTmpNoLongerVisibleNotifications); 628 629 recycleAllVisibilityObjects(mCurrentlyVisibleNotifications); 630 mCurrentlyVisibleNotifications.addAll(mTmpCurrentlyVisibleNotifications); 631 632 recycleAllVisibilityObjects(mTmpNoLongerVisibleNotifications); 633 mTmpCurrentlyVisibleNotifications.clear(); 634 mTmpNewlyVisibleNotifications.clear(); 635 mTmpNoLongerVisibleNotifications.clear(); 636 } 637 }; 638 recycleAllVisibilityObjects(ArraySet<NotificationVisibility> array)639 private void recycleAllVisibilityObjects(ArraySet<NotificationVisibility> array) { 640 final int N = array.size(); 641 for (int i = 0 ; i < N; i++) { 642 array.valueAt(i).recycle(); 643 } 644 array.clear(); 645 } 646 647 private final View.OnClickListener mOverflowClickListener = new View.OnClickListener() { 648 @Override 649 public void onClick(View v) { 650 goToLockedShade(null); 651 } 652 }; 653 private HashMap<ExpandableNotificationRow, List<ExpandableNotificationRow>> mTmpChildOrderMap 654 = new HashMap<>(); 655 private RankingMap mLatestRankingMap; 656 private boolean mNoAnimationOnNextBarModeChange; 657 private FalsingManager mFalsingManager; 658 659 @Override start()660 public void start() { 661 mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE)) 662 .getDefaultDisplay(); 663 updateDisplaySize(); 664 mScrimSrcModeEnabled = mContext.getResources().getBoolean( 665 R.bool.config_status_bar_scrim_behind_use_src); 666 667 super.start(); // calls createAndAddWindows() 668 669 mMediaSessionManager 670 = (MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE); 671 // TODO: use MediaSessionManager.SessionListener to hook us up to future updates 672 // in session state 673 674 addNavigationBar(); 675 676 // Lastly, call to the icon policy to install/update all the icons. 677 mIconPolicy = new PhoneStatusBarPolicy(mContext, mIconController, mCastController, 678 mHotspotController, mUserInfoController, mBluetoothController, 679 mRotationLockController, mNetworkController.getDataSaverController()); 680 mIconPolicy.setCurrentUserSetup(mUserSetup); 681 mSettingsObserver.onChange(false); // set up 682 683 mHeadsUpObserver.onChange(true); // set up 684 if (ENABLE_HEADS_UP) { 685 mContext.getContentResolver().registerContentObserver( 686 Settings.Global.getUriFor(Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED), true, 687 mHeadsUpObserver); 688 mContext.getContentResolver().registerContentObserver( 689 Settings.Global.getUriFor(SETTING_HEADS_UP_TICKER), true, 690 mHeadsUpObserver); 691 } 692 mUnlockMethodCache = UnlockMethodCache.getInstance(mContext); 693 mUnlockMethodCache.addListener(this); 694 startKeyguard(); 695 696 mDozeServiceHost = new DozeServiceHost(); 697 KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mDozeServiceHost); 698 putComponent(DozeHost.class, mDozeServiceHost); 699 putComponent(PhoneStatusBar.class, this); 700 701 setControllerUsers(); 702 703 notifyUserAboutHiddenNotifications(); 704 705 mScreenPinningRequest = new ScreenPinningRequest(mContext); 706 mFalsingManager = FalsingManager.getInstance(mContext); 707 } 708 createIconController()709 protected void createIconController() { 710 mIconController = new StatusBarIconController( 711 mContext, mStatusBarView, mKeyguardStatusBar, this); 712 } 713 714 // ================================================================================ 715 // Constructing the view 716 // ================================================================================ makeStatusBarView()717 protected PhoneStatusBarView makeStatusBarView() { 718 final Context context = mContext; 719 720 updateDisplaySize(); // populates mDisplayMetrics 721 updateResources(); 722 723 inflateStatusBarWindow(context); 724 mStatusBarWindow.setService(this); 725 mStatusBarWindow.setOnTouchListener(new View.OnTouchListener() { 726 @Override 727 public boolean onTouch(View v, MotionEvent event) { 728 checkUserAutohide(v, event); 729 if (event.getAction() == MotionEvent.ACTION_DOWN) { 730 if (mExpandedVisible) { 731 animateCollapsePanels(); 732 } 733 } 734 return mStatusBarWindow.onTouchEvent(event); 735 } 736 }); 737 738 mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById( 739 R.id.notification_panel); 740 mNotificationPanel.setStatusBar(this); 741 mNotificationPanel.setGroupManager(mGroupManager); 742 743 mStatusBarView = (PhoneStatusBarView) mStatusBarWindow.findViewById(R.id.status_bar); 744 mStatusBarView.setBar(this); 745 mStatusBarView.setPanel(mNotificationPanel); 746 747 if (!ActivityManager.isHighEndGfx()) { 748 mStatusBarWindow.setBackground(null); 749 mNotificationPanel.setBackground(new FastColorDrawable(context.getColor( 750 R.color.notification_panel_solid_background))); 751 } 752 753 mHeadsUpManager = new HeadsUpManager(context, mStatusBarWindow, mGroupManager); 754 mHeadsUpManager.setBar(this); 755 mHeadsUpManager.addListener(this); 756 mHeadsUpManager.addListener(mNotificationPanel); 757 mHeadsUpManager.addListener(mGroupManager); 758 mNotificationPanel.setHeadsUpManager(mHeadsUpManager); 759 mNotificationData.setHeadsUpManager(mHeadsUpManager); 760 mGroupManager.setHeadsUpManager(mHeadsUpManager); 761 762 if (MULTIUSER_DEBUG) { 763 mNotificationPanelDebugText = (TextView) mNotificationPanel.findViewById( 764 R.id.header_debug_info); 765 mNotificationPanelDebugText.setVisibility(View.VISIBLE); 766 } 767 768 try { 769 boolean showNav = mWindowManagerService.hasNavigationBar(); 770 if (DEBUG) Log.v(TAG, "hasNavigationBar=" + showNav); 771 if (showNav) { 772 createNavigationBarView(context); 773 } 774 } catch (RemoteException ex) { 775 // no window manager? good luck with that 776 } 777 778 mAssistManager = SystemUIFactory.getInstance().createAssistManager(this, context); 779 780 // figure out which pixel-format to use for the status bar. 781 mPixelFormat = PixelFormat.OPAQUE; 782 783 mStackScroller = (NotificationStackScrollLayout) mStatusBarWindow.findViewById( 784 R.id.notification_stack_scroller); 785 mStackScroller.setLongPressListener(getNotificationLongClicker()); 786 mStackScroller.setPhoneStatusBar(this); 787 mStackScroller.setGroupManager(mGroupManager); 788 mStackScroller.setHeadsUpManager(mHeadsUpManager); 789 mGroupManager.setOnGroupChangeListener(mStackScroller); 790 791 inflateOverflowContainer(); 792 inflateEmptyShadeView(); 793 inflateDismissView(); 794 mExpandedContents = mStackScroller; 795 796 mBackdrop = (BackDropView) mStatusBarWindow.findViewById(R.id.backdrop); 797 mBackdropFront = (ImageView) mBackdrop.findViewById(R.id.backdrop_front); 798 mBackdropBack = (ImageView) mBackdrop.findViewById(R.id.backdrop_back); 799 800 if (ENABLE_LOCKSCREEN_WALLPAPER) { 801 mLockscreenWallpaper = new LockscreenWallpaper(mContext, this, mHandler); 802 } 803 804 ScrimView scrimBehind = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_behind); 805 ScrimView scrimInFront = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_in_front); 806 View headsUpScrim = mStatusBarWindow.findViewById(R.id.heads_up_scrim); 807 mScrimController = SystemUIFactory.getInstance().createScrimController( 808 scrimBehind, scrimInFront, headsUpScrim, mLockscreenWallpaper); 809 if (mScrimSrcModeEnabled) { 810 Runnable runnable = new Runnable() { 811 @Override 812 public void run() { 813 boolean asSrc = mBackdrop.getVisibility() != View.VISIBLE; 814 mScrimController.setDrawBehindAsSrc(asSrc); 815 mStackScroller.setDrawBackgroundAsSrc(asSrc); 816 } 817 }; 818 mBackdrop.setOnVisibilityChangedRunnable(runnable); 819 runnable.run(); 820 } 821 mHeadsUpManager.addListener(mScrimController); 822 mStackScroller.setScrimController(mScrimController); 823 mStatusBarView.setScrimController(mScrimController); 824 mDozeScrimController = new DozeScrimController(mScrimController, context); 825 826 mKeyguardStatusBar = (KeyguardStatusBarView) mStatusBarWindow.findViewById(R.id.keyguard_header); 827 mKeyguardStatusView = mStatusBarWindow.findViewById(R.id.keyguard_status_view); 828 mKeyguardBottomArea = 829 (KeyguardBottomAreaView) mStatusBarWindow.findViewById(R.id.keyguard_bottom_area); 830 mKeyguardBottomArea.setActivityStarter(this); 831 mKeyguardBottomArea.setAssistManager(mAssistManager); 832 mKeyguardIndicationController = new KeyguardIndicationController(mContext, 833 (KeyguardIndicationTextView) mStatusBarWindow.findViewById( 834 R.id.keyguard_indication_text), 835 mKeyguardBottomArea.getLockIcon()); 836 mKeyguardBottomArea.setKeyguardIndicationController(mKeyguardIndicationController); 837 838 // set the initial view visibility 839 setAreThereNotifications(); 840 841 createIconController(); 842 843 // Background thread for any controllers that need it. 844 mHandlerThread = new HandlerThread(TAG, Process.THREAD_PRIORITY_BACKGROUND); 845 mHandlerThread.start(); 846 847 // Other icons 848 mLocationController = new LocationControllerImpl(mContext, 849 mHandlerThread.getLooper()); // will post a notification 850 mBatteryController = createBatteryController(); 851 mBatteryController.addStateChangedCallback(new BatteryStateChangeCallback() { 852 @Override 853 public void onPowerSaveChanged(boolean isPowerSave) { 854 mHandler.post(mCheckBarModes); 855 if (mDozeServiceHost != null) { 856 mDozeServiceHost.firePowerSaveChanged(isPowerSave); 857 } 858 } 859 @Override 860 public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) { 861 // noop 862 } 863 }); 864 mNetworkController = new NetworkControllerImpl(mContext, mHandlerThread.getLooper()); 865 mNetworkController.setUserSetupComplete(mUserSetup); 866 mHotspotController = new HotspotControllerImpl(mContext); 867 mBluetoothController = new BluetoothControllerImpl(mContext, mHandlerThread.getLooper()); 868 mSecurityController = new SecurityControllerImpl(mContext); 869 if (mContext.getResources().getBoolean(R.bool.config_showRotationLock)) { 870 mRotationLockController = new RotationLockControllerImpl(mContext); 871 } 872 mUserInfoController = new UserInfoController(mContext); 873 mVolumeComponent = getComponent(VolumeComponent.class); 874 if (mVolumeComponent != null) { 875 mZenModeController = mVolumeComponent.getZenController(); 876 } 877 mCastController = new CastControllerImpl(mContext); 878 879 initSignalCluster(mStatusBarView); 880 initSignalCluster(mKeyguardStatusBar); 881 882 mFlashlightController = new FlashlightController(mContext); 883 mKeyguardBottomArea.setFlashlightController(mFlashlightController); 884 mKeyguardBottomArea.setPhoneStatusBar(this); 885 mKeyguardBottomArea.setUserSetupComplete(mUserSetup); 886 mAccessibilityController = new AccessibilityController(mContext); 887 mKeyguardBottomArea.setAccessibilityController(mAccessibilityController); 888 mNextAlarmController = new NextAlarmController(mContext); 889 mLightStatusBarController = new LightStatusBarController(mIconController, 890 mBatteryController); 891 mKeyguardMonitor = new KeyguardMonitor(mContext); 892 mUserSwitcherController = new UserSwitcherController(mContext, mKeyguardMonitor, 893 mHandler, this); 894 if (UserManager.get(mContext).isUserSwitcherEnabled()) { 895 createUserSwitcher(); 896 } 897 898 // Set up the quick settings tile panel 899 AutoReinflateContainer container = (AutoReinflateContainer) mStatusBarWindow.findViewById( 900 R.id.qs_auto_reinflate_container); 901 if (container != null) { 902 final QSTileHost qsh = SystemUIFactory.getInstance().createQSTileHost(mContext, this, 903 mBluetoothController, mLocationController, mRotationLockController, 904 mNetworkController, mZenModeController, mHotspotController, 905 mCastController, mFlashlightController, 906 mUserSwitcherController, mUserInfoController, mKeyguardMonitor, 907 mSecurityController, mBatteryController, mIconController, 908 mNextAlarmController); 909 mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow); 910 container.addInflateListener(new InflateListener() { 911 @Override 912 public void onInflated(View v) { 913 QSContainer qsContainer = (QSContainer) v.findViewById( 914 R.id.quick_settings_container); 915 qsContainer.setHost(qsh); 916 mQSPanel = qsContainer.getQsPanel(); 917 mQSPanel.setBrightnessMirror(mBrightnessMirrorController); 918 mKeyguardStatusBar.setQSPanel(mQSPanel); 919 mHeader = qsContainer.getHeader(); 920 initSignalCluster(mHeader); 921 mHeader.setActivityStarter(PhoneStatusBar.this); 922 } 923 }); 924 } 925 926 // User info. Trigger first load. 927 mKeyguardStatusBar.setUserInfoController(mUserInfoController); 928 mKeyguardStatusBar.setUserSwitcherController(mUserSwitcherController); 929 mUserInfoController.reloadUserInfo(); 930 931 ((BatteryMeterView) mStatusBarView.findViewById(R.id.battery)).setBatteryController( 932 mBatteryController); 933 mKeyguardStatusBar.setBatteryController(mBatteryController); 934 935 mReportRejectedTouch = mStatusBarWindow.findViewById(R.id.report_rejected_touch); 936 if (mReportRejectedTouch != null) { 937 updateReportRejectedTouchVisibility(); 938 mReportRejectedTouch.setOnClickListener(v -> { 939 Uri session = mFalsingManager.reportRejectedTouch(); 940 if (session == null) { return; } 941 942 StringWriter message = new StringWriter(); 943 message.write("Build info: "); 944 message.write(SystemProperties.get("ro.build.description")); 945 message.write("\nSerial number: "); 946 message.write(SystemProperties.get("ro.serialno")); 947 message.write("\n"); 948 949 PrintWriter falsingPw = new PrintWriter(message); 950 FalsingLog.dump(falsingPw); 951 falsingPw.flush(); 952 953 startActivityDismissingKeyguard(Intent.createChooser(new Intent(Intent.ACTION_SEND) 954 .setType("*/*") 955 .putExtra(Intent.EXTRA_SUBJECT, "Rejected touch report") 956 .putExtra(Intent.EXTRA_STREAM, session) 957 .putExtra(Intent.EXTRA_TEXT, message.toString()), 958 "Share rejected touch report") 959 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), 960 true /* onlyProvisioned */, true /* dismissShade */); 961 }); 962 } 963 964 965 PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 966 mBroadcastReceiver.onReceive(mContext, 967 new Intent(pm.isScreenOn() ? Intent.ACTION_SCREEN_ON : Intent.ACTION_SCREEN_OFF)); 968 mGestureWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, 969 "GestureWakeLock"); 970 mVibrator = mContext.getSystemService(Vibrator.class); 971 972 // receive broadcasts 973 IntentFilter filter = new IntentFilter(); 974 filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); 975 filter.addAction(Intent.ACTION_SCREEN_OFF); 976 filter.addAction(Intent.ACTION_SCREEN_ON); 977 context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null); 978 979 IntentFilter demoFilter = new IntentFilter(); 980 if (DEBUG_MEDIA_FAKE_ARTWORK) { 981 demoFilter.addAction(ACTION_FAKE_ARTWORK); 982 } 983 demoFilter.addAction(ACTION_DEMO); 984 context.registerReceiverAsUser(mDemoReceiver, UserHandle.ALL, demoFilter, 985 android.Manifest.permission.DUMP, null); 986 987 // listen for USER_SETUP_COMPLETE setting (per-user) 988 resetUserSetupObserver(); 989 990 // disable profiling bars, since they overlap and clutter the output on app windows 991 ThreadedRenderer.overrideProperty("disableProfileBars", "true"); 992 993 // Private API call to make the shadows look better for Recents 994 ThreadedRenderer.overrideProperty("ambientRatio", String.valueOf(1.5f)); 995 996 return mStatusBarView; 997 } 998 createBatteryController()999 protected BatteryController createBatteryController() { 1000 return new BatteryControllerImpl(mContext); 1001 } 1002 inflateOverflowContainer()1003 private void inflateOverflowContainer() { 1004 mKeyguardIconOverflowContainer = 1005 (NotificationOverflowContainer) LayoutInflater.from(mContext).inflate( 1006 R.layout.status_bar_notification_keyguard_overflow, mStackScroller, false); 1007 mKeyguardIconOverflowContainer.setOnActivatedListener(this); 1008 mKeyguardIconOverflowContainer.setOnClickListener(mOverflowClickListener); 1009 mStackScroller.setOverflowContainer(mKeyguardIconOverflowContainer); 1010 } 1011 1012 @Override onDensityOrFontScaleChanged()1013 protected void onDensityOrFontScaleChanged() { 1014 super.onDensityOrFontScaleChanged(); 1015 mScrimController.onDensityOrFontScaleChanged(); 1016 mStatusBarView.onDensityOrFontScaleChanged(); 1017 if (mBrightnessMirrorController != null) { 1018 mBrightnessMirrorController.onDensityOrFontScaleChanged(); 1019 } 1020 inflateSignalClusters(); 1021 mIconController.onDensityOrFontScaleChanged(); 1022 inflateDismissView(); 1023 updateClearAll(); 1024 inflateEmptyShadeView(); 1025 updateEmptyShadeView(); 1026 inflateOverflowContainer(); 1027 mStatusBarKeyguardViewManager.onDensityOrFontScaleChanged(); 1028 mUserInfoController.onDensityOrFontScaleChanged(); 1029 if (mUserSwitcherController != null) { 1030 mUserSwitcherController.onDensityOrFontScaleChanged(); 1031 } 1032 if (mKeyguardUserSwitcher != null) { 1033 mKeyguardUserSwitcher.onDensityOrFontScaleChanged(); 1034 } 1035 } 1036 inflateSignalClusters()1037 private void inflateSignalClusters() { 1038 SignalClusterView signalClusterView = reinflateSignalCluster(mStatusBarView); 1039 mIconController.setSignalCluster(signalClusterView); 1040 reinflateSignalCluster(mKeyguardStatusBar); 1041 } 1042 reinflateSignalCluster(View view)1043 private SignalClusterView reinflateSignalCluster(View view) { 1044 SignalClusterView signalCluster = 1045 (SignalClusterView) view.findViewById(R.id.signal_cluster); 1046 if (signalCluster != null) { 1047 ViewParent parent = signalCluster.getParent(); 1048 if (parent instanceof ViewGroup) { 1049 ViewGroup viewParent = (ViewGroup) parent; 1050 int index = viewParent.indexOfChild(signalCluster); 1051 viewParent.removeView(signalCluster); 1052 SignalClusterView newCluster = (SignalClusterView) LayoutInflater.from(mContext) 1053 .inflate(R.layout.signal_cluster_view, viewParent, false); 1054 ViewGroup.MarginLayoutParams layoutParams = 1055 (ViewGroup.MarginLayoutParams) viewParent.getLayoutParams(); 1056 layoutParams.setMarginsRelative( 1057 mContext.getResources().getDimensionPixelSize( 1058 R.dimen.signal_cluster_margin_start), 1059 0, 0, 0); 1060 newCluster.setLayoutParams(layoutParams); 1061 newCluster.setSecurityController(mSecurityController); 1062 newCluster.setNetworkController(mNetworkController); 1063 viewParent.addView(newCluster, index); 1064 return newCluster; 1065 } 1066 return signalCluster; 1067 } 1068 return null; 1069 } 1070 inflateEmptyShadeView()1071 private void inflateEmptyShadeView() { 1072 mEmptyShadeView = (EmptyShadeView) LayoutInflater.from(mContext).inflate( 1073 R.layout.status_bar_no_notifications, mStackScroller, false); 1074 mStackScroller.setEmptyShadeView(mEmptyShadeView); 1075 } 1076 inflateDismissView()1077 private void inflateDismissView() { 1078 mDismissView = (DismissView) LayoutInflater.from(mContext).inflate( 1079 R.layout.status_bar_notification_dismiss_all, mStackScroller, false); 1080 mDismissView.setOnButtonClickListener(new View.OnClickListener() { 1081 @Override 1082 public void onClick(View v) { 1083 MetricsLogger.action(mContext, MetricsEvent.ACTION_DISMISS_ALL_NOTES); 1084 clearAllNotifications(); 1085 } 1086 }); 1087 mStackScroller.setDismissView(mDismissView); 1088 } 1089 createUserSwitcher()1090 protected void createUserSwitcher() { 1091 mKeyguardUserSwitcher = new KeyguardUserSwitcher(mContext, 1092 (ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_user_switcher), 1093 mKeyguardStatusBar, mNotificationPanel, mUserSwitcherController); 1094 } 1095 inflateStatusBarWindow(Context context)1096 protected void inflateStatusBarWindow(Context context) { 1097 mStatusBarWindow = (StatusBarWindowView) View.inflate(context, 1098 R.layout.super_status_bar, null); 1099 } 1100 createNavigationBarView(Context context)1101 protected void createNavigationBarView(Context context) { 1102 inflateNavigationBarView(context); 1103 mNavigationBarView.setDisabledFlags(mDisabled1); 1104 mNavigationBarView.setComponents(mRecents, getComponent(Divider.class)); 1105 mNavigationBarView.setOnVerticalChangedListener( 1106 new NavigationBarView.OnVerticalChangedListener() { 1107 @Override 1108 public void onVerticalChanged(boolean isVertical) { 1109 if (mAssistManager != null) { 1110 mAssistManager.onConfigurationChanged(); 1111 } 1112 mNotificationPanel.setQsScrimEnabled(!isVertical); 1113 } 1114 }); 1115 mNavigationBarView.setOnTouchListener(new View.OnTouchListener() { 1116 @Override 1117 public boolean onTouch(View v, MotionEvent event) { 1118 checkUserAutohide(v, event); 1119 return false; 1120 }}); 1121 } 1122 inflateNavigationBarView(Context context)1123 protected void inflateNavigationBarView(Context context) { 1124 mNavigationBarView = (NavigationBarView) View.inflate( 1125 context, R.layout.navigation_bar, null); 1126 } 1127 initSignalCluster(View containerView)1128 protected void initSignalCluster(View containerView) { 1129 SignalClusterView signalCluster = 1130 (SignalClusterView) containerView.findViewById(R.id.signal_cluster); 1131 if (signalCluster != null) { 1132 signalCluster.setSecurityController(mSecurityController); 1133 signalCluster.setNetworkController(mNetworkController); 1134 } 1135 } 1136 clearAllNotifications()1137 public void clearAllNotifications() { 1138 1139 // animate-swipe all dismissable notifications, then animate the shade closed 1140 int numChildren = mStackScroller.getChildCount(); 1141 1142 final ArrayList<View> viewsToHide = new ArrayList<View>(numChildren); 1143 for (int i = 0; i < numChildren; i++) { 1144 final View child = mStackScroller.getChildAt(i); 1145 if (child instanceof ExpandableNotificationRow) { 1146 if (mStackScroller.canChildBeDismissed(child)) { 1147 if (child.getVisibility() == View.VISIBLE) { 1148 viewsToHide.add(child); 1149 } 1150 } 1151 ExpandableNotificationRow row = (ExpandableNotificationRow) child; 1152 List<ExpandableNotificationRow> children = row.getNotificationChildren(); 1153 if (row.areChildrenExpanded() && children != null) { 1154 for (ExpandableNotificationRow childRow : children) { 1155 if (childRow.getVisibility() == View.VISIBLE) { 1156 viewsToHide.add(childRow); 1157 } 1158 } 1159 } 1160 } 1161 } 1162 if (viewsToHide.isEmpty()) { 1163 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE); 1164 return; 1165 } 1166 1167 addPostCollapseAction(new Runnable() { 1168 @Override 1169 public void run() { 1170 mStackScroller.setDismissAllInProgress(false); 1171 try { 1172 mBarService.onClearAllNotifications(mCurrentUserId); 1173 } catch (Exception ex) { } 1174 } 1175 }); 1176 1177 performDismissAllAnimations(viewsToHide); 1178 1179 } 1180 performDismissAllAnimations(ArrayList<View> hideAnimatedList)1181 private void performDismissAllAnimations(ArrayList<View> hideAnimatedList) { 1182 Runnable animationFinishAction = new Runnable() { 1183 @Override 1184 public void run() { 1185 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE); 1186 } 1187 }; 1188 1189 // let's disable our normal animations 1190 mStackScroller.setDismissAllInProgress(true); 1191 1192 // Decrease the delay for every row we animate to give the sense of 1193 // accelerating the swipes 1194 int rowDelayDecrement = 10; 1195 int currentDelay = 140; 1196 int totalDelay = 180; 1197 int numItems = hideAnimatedList.size(); 1198 for (int i = numItems - 1; i >= 0; i--) { 1199 View view = hideAnimatedList.get(i); 1200 Runnable endRunnable = null; 1201 if (i == 0) { 1202 endRunnable = animationFinishAction; 1203 } 1204 mStackScroller.dismissViewAnimated(view, endRunnable, totalDelay, 260); 1205 currentDelay = Math.max(50, currentDelay - rowDelayDecrement); 1206 totalDelay += currentDelay; 1207 } 1208 } 1209 1210 @Override setZenMode(int mode)1211 protected void setZenMode(int mode) { 1212 super.setZenMode(mode); 1213 if (mIconPolicy != null) { 1214 mIconPolicy.setZenMode(mode); 1215 } 1216 } 1217 startKeyguard()1218 protected void startKeyguard() { 1219 Trace.beginSection("PhoneStatusBar#startKeyguard"); 1220 KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class); 1221 mFingerprintUnlockController = new FingerprintUnlockController(mContext, 1222 mStatusBarWindowManager, mDozeScrimController, keyguardViewMediator, 1223 mScrimController, this); 1224 mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this, 1225 getBouncerContainer(), mStatusBarWindowManager, mScrimController, 1226 mFingerprintUnlockController); 1227 mKeyguardIndicationController.setStatusBarKeyguardViewManager( 1228 mStatusBarKeyguardViewManager); 1229 mFingerprintUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager); 1230 mIconPolicy.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager); 1231 mRemoteInputController.addCallback(mStatusBarKeyguardViewManager); 1232 1233 mRemoteInputController.addCallback(new RemoteInputController.Callback() { 1234 @Override 1235 public void onRemoteInputSent(Entry entry) { 1236 if (FORCE_REMOTE_INPUT_HISTORY && mKeysKeptForRemoteInput.contains(entry.key)) { 1237 removeNotification(entry.key, null); 1238 } else if (mRemoteInputEntriesToRemoveOnCollapse.contains(entry)) { 1239 // We're currently holding onto this notification, but from the apps point of 1240 // view it is already canceled, so we'll need to cancel it on the apps behalf 1241 // after sending - unless the app posts an update in the mean time, so wait a 1242 // bit. 1243 mHandler.postDelayed(() -> { 1244 if (mRemoteInputEntriesToRemoveOnCollapse.remove(entry)) { 1245 removeNotification(entry.key, null); 1246 } 1247 }, REMOTE_INPUT_KEPT_ENTRY_AUTO_CANCEL_DELAY); 1248 } 1249 } 1250 }); 1251 1252 mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback(); 1253 mLightStatusBarController.setFingerprintUnlockController(mFingerprintUnlockController); 1254 Trace.endSection(); 1255 } 1256 1257 @Override getStatusBarView()1258 protected View getStatusBarView() { 1259 return mStatusBarView; 1260 } 1261 getStatusBarWindow()1262 public StatusBarWindowView getStatusBarWindow() { 1263 return mStatusBarWindow; 1264 } 1265 getBouncerContainer()1266 protected ViewGroup getBouncerContainer() { 1267 return mStatusBarWindow; 1268 } 1269 getStatusBarHeight()1270 public int getStatusBarHeight() { 1271 if (mNaturalBarHeight < 0) { 1272 final Resources res = mContext.getResources(); 1273 mNaturalBarHeight = 1274 res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height); 1275 } 1276 return mNaturalBarHeight; 1277 } 1278 1279 private View.OnClickListener mRecentsClickListener = new View.OnClickListener() { 1280 @Override 1281 public void onClick(View v) { 1282 awakenDreams(); 1283 toggleRecentApps(); 1284 } 1285 }; 1286 1287 private View.OnLongClickListener mLongPressBackListener = new View.OnLongClickListener() { 1288 @Override 1289 public boolean onLongClick(View v) { 1290 return handleLongPressBack(); 1291 } 1292 }; 1293 1294 private View.OnLongClickListener mRecentsLongClickListener = new View.OnLongClickListener() { 1295 1296 @Override 1297 public boolean onLongClick(View v) { 1298 if (mRecents == null || !ActivityManager.supportsMultiWindow() 1299 || !getComponent(Divider.class).getView().getSnapAlgorithm() 1300 .isSplitScreenFeasible()) { 1301 return false; 1302 } 1303 1304 toggleSplitScreenMode(MetricsEvent.ACTION_WINDOW_DOCK_LONGPRESS, 1305 MetricsEvent.ACTION_WINDOW_UNDOCK_LONGPRESS); 1306 return true; 1307 } 1308 }; 1309 1310 @Override toggleSplitScreenMode(int metricsDockAction, int metricsUndockAction)1311 protected void toggleSplitScreenMode(int metricsDockAction, int metricsUndockAction) { 1312 if (mRecents == null) { 1313 return; 1314 } 1315 int dockSide = WindowManagerProxy.getInstance().getDockSide(); 1316 if (dockSide == WindowManager.DOCKED_INVALID) { 1317 mRecents.dockTopTask(NavigationBarGestureHelper.DRAG_MODE_NONE, 1318 ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, null, metricsDockAction); 1319 } else { 1320 EventBus.getDefault().send(new UndockingTaskEvent()); 1321 if (metricsUndockAction != -1) { 1322 MetricsLogger.action(mContext, metricsUndockAction); 1323 } 1324 } 1325 } 1326 1327 private final View.OnLongClickListener mLongPressHomeListener 1328 = new View.OnLongClickListener() { 1329 @Override 1330 public boolean onLongClick(View v) { 1331 if (shouldDisableNavbarGestures()) { 1332 return false; 1333 } 1334 MetricsLogger.action(mContext, MetricsEvent.ACTION_ASSIST_LONG_PRESS); 1335 mAssistManager.startAssist(new Bundle() /* args */); 1336 awakenDreams(); 1337 if (mNavigationBarView != null) { 1338 mNavigationBarView.abortCurrentGesture(); 1339 } 1340 return true; 1341 } 1342 }; 1343 1344 private final View.OnTouchListener mHomeActionListener = new View.OnTouchListener() { 1345 public boolean mBlockedThisTouch; 1346 1347 @Override 1348 public boolean onTouch(View v, MotionEvent event) { 1349 if (mBlockedThisTouch && event.getActionMasked() != MotionEvent.ACTION_DOWN) { 1350 return true; 1351 } 1352 // If an incoming call is ringing, HOME is totally disabled. 1353 // (The user is already on the InCallUI at this point, 1354 // and his ONLY options are to answer or reject the call.) 1355 switch (event.getAction()) { 1356 case MotionEvent.ACTION_DOWN: 1357 mBlockedThisTouch = false; 1358 TelecomManager telecomManager = mContext.getSystemService(TelecomManager.class); 1359 if (telecomManager != null && telecomManager.isRinging()) { 1360 if (mStatusBarKeyguardViewManager.isShowing()) { 1361 Log.i(TAG, "Ignoring HOME; there's a ringing incoming call. " + 1362 "No heads up"); 1363 mBlockedThisTouch = true; 1364 return true; 1365 } 1366 } 1367 break; 1368 case MotionEvent.ACTION_UP: 1369 case MotionEvent.ACTION_CANCEL: 1370 awakenDreams(); 1371 break; 1372 } 1373 return false; 1374 } 1375 }; 1376 awakenDreams()1377 private void awakenDreams() { 1378 if (mDreamManager != null) { 1379 try { 1380 mDreamManager.awaken(); 1381 } catch (RemoteException e) { 1382 // fine, stay asleep then 1383 } 1384 } 1385 } 1386 prepareNavigationBarView()1387 private void prepareNavigationBarView() { 1388 mNavigationBarView.reorient(); 1389 1390 ButtonDispatcher recentsButton = mNavigationBarView.getRecentsButton(); 1391 recentsButton.setOnClickListener(mRecentsClickListener); 1392 recentsButton.setOnTouchListener(mRecentsPreloadOnTouchListener); 1393 recentsButton.setLongClickable(true); 1394 recentsButton.setOnLongClickListener(mRecentsLongClickListener); 1395 1396 ButtonDispatcher backButton = mNavigationBarView.getBackButton(); 1397 backButton.setLongClickable(true); 1398 backButton.setOnLongClickListener(mLongPressBackListener); 1399 1400 ButtonDispatcher homeButton = mNavigationBarView.getHomeButton(); 1401 homeButton.setOnTouchListener(mHomeActionListener); 1402 homeButton.setOnLongClickListener(mLongPressHomeListener); 1403 1404 mAssistManager.onConfigurationChanged(); 1405 } 1406 1407 // For small-screen devices (read: phones) that lack hardware navigation buttons addNavigationBar()1408 protected void addNavigationBar() { 1409 if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + mNavigationBarView); 1410 if (mNavigationBarView == null) return; 1411 1412 try { 1413 WindowManagerGlobal.getWindowManagerService() 1414 .watchRotation(new IRotationWatcher.Stub() { 1415 @Override 1416 public void onRotationChanged(int rotation) throws RemoteException { 1417 // We need this to be scheduled as early as possible to beat the redrawing of 1418 // window in response to the orientation change. 1419 Message msg = Message.obtain(mHandler, () -> { 1420 if (mNavigationBarView != null 1421 && mNavigationBarView.needsReorient(rotation)) { 1422 repositionNavigationBar(); 1423 } 1424 }); 1425 msg.setAsynchronous(true); 1426 mHandler.sendMessageAtFrontOfQueue(msg); 1427 } 1428 }); 1429 } catch (RemoteException e) { 1430 throw e.rethrowFromSystemServer(); 1431 } 1432 1433 prepareNavigationBarView(); 1434 1435 mWindowManager.addView(mNavigationBarView, getNavigationBarLayoutParams()); 1436 } 1437 repositionNavigationBar()1438 protected void repositionNavigationBar() { 1439 if (mNavigationBarView == null || !mNavigationBarView.isAttachedToWindow()) return; 1440 1441 prepareNavigationBarView(); 1442 1443 mWindowManager.updateViewLayout(mNavigationBarView, mNavigationBarView.getLayoutParams()); 1444 } 1445 notifyNavigationBarScreenOn(boolean screenOn)1446 private void notifyNavigationBarScreenOn(boolean screenOn) { 1447 if (mNavigationBarView == null) return; 1448 mNavigationBarView.notifyScreenOn(screenOn); 1449 } 1450 getNavigationBarLayoutParams()1451 private WindowManager.LayoutParams getNavigationBarLayoutParams() { 1452 WindowManager.LayoutParams lp = new WindowManager.LayoutParams( 1453 LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, 1454 WindowManager.LayoutParams.TYPE_NAVIGATION_BAR, 1455 0 1456 | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING 1457 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 1458 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL 1459 | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH 1460 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH 1461 | WindowManager.LayoutParams.FLAG_SLIPPERY, 1462 PixelFormat.TRANSLUCENT); 1463 // this will allow the navbar to run in an overlay on devices that support this 1464 if (ActivityManager.isHighEndGfx()) { 1465 lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; 1466 } 1467 1468 lp.setTitle("NavigationBar"); 1469 lp.windowAnimations = 0; 1470 return lp; 1471 } 1472 1473 @Override setIcon(String slot, StatusBarIcon icon)1474 public void setIcon(String slot, StatusBarIcon icon) { 1475 mIconController.setIcon(slot, icon); 1476 } 1477 1478 @Override removeIcon(String slot)1479 public void removeIcon(String slot) { 1480 mIconController.removeIcon(slot); 1481 } 1482 getCurrentUserHandle()1483 public UserHandle getCurrentUserHandle() { 1484 return new UserHandle(mCurrentUserId); 1485 } 1486 1487 @Override addNotification(StatusBarNotification notification, RankingMap ranking, Entry oldEntry)1488 public void addNotification(StatusBarNotification notification, RankingMap ranking, 1489 Entry oldEntry) { 1490 if (DEBUG) Log.d(TAG, "addNotification key=" + notification.getKey()); 1491 1492 mNotificationData.updateRanking(ranking); 1493 Entry shadeEntry = createNotificationViews(notification); 1494 if (shadeEntry == null) { 1495 return; 1496 } 1497 boolean isHeadsUped = shouldPeek(shadeEntry); 1498 if (isHeadsUped) { 1499 mHeadsUpManager.showNotification(shadeEntry); 1500 // Mark as seen immediately 1501 setNotificationShown(notification); 1502 } 1503 1504 if (!isHeadsUped && notification.getNotification().fullScreenIntent != null) { 1505 if (shouldSuppressFullScreenIntent(notification.getKey())) { 1506 if (DEBUG) { 1507 Log.d(TAG, "No Fullscreen intent: suppressed by DND: " + notification.getKey()); 1508 } 1509 } else if (mNotificationData.getImportance(notification.getKey()) 1510 < NotificationListenerService.Ranking.IMPORTANCE_MAX) { 1511 if (DEBUG) { 1512 Log.d(TAG, "No Fullscreen intent: not important enough: " 1513 + notification.getKey()); 1514 } 1515 } else { 1516 // Stop screensaver if the notification has a full-screen intent. 1517 // (like an incoming phone call) 1518 awakenDreams(); 1519 1520 // not immersive & a full-screen alert should be shown 1521 if (DEBUG) 1522 Log.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent"); 1523 try { 1524 EventLog.writeEvent(EventLogTags.SYSUI_FULLSCREEN_NOTIFICATION, 1525 notification.getKey()); 1526 notification.getNotification().fullScreenIntent.send(); 1527 shadeEntry.notifyFullScreenIntentLaunched(); 1528 MetricsLogger.count(mContext, "note_fullscreen", 1); 1529 } catch (PendingIntent.CanceledException e) { 1530 } 1531 } 1532 } 1533 addNotificationViews(shadeEntry, ranking); 1534 // Recalculate the position of the sliding windows and the titles. 1535 setAreThereNotifications(); 1536 } 1537 shouldSuppressFullScreenIntent(String key)1538 private boolean shouldSuppressFullScreenIntent(String key) { 1539 if (isDeviceInVrMode()) { 1540 return true; 1541 } 1542 1543 if (mPowerManager.isInteractive()) { 1544 return mNotificationData.shouldSuppressScreenOn(key); 1545 } else { 1546 return mNotificationData.shouldSuppressScreenOff(key); 1547 } 1548 } 1549 1550 @Override updateNotificationRanking(RankingMap ranking)1551 protected void updateNotificationRanking(RankingMap ranking) { 1552 mNotificationData.updateRanking(ranking); 1553 updateNotifications(); 1554 } 1555 1556 @Override removeNotification(String key, RankingMap ranking)1557 public void removeNotification(String key, RankingMap ranking) { 1558 boolean deferRemoval = false; 1559 if (mHeadsUpManager.isHeadsUp(key)) { 1560 // A cancel() in repsonse to a remote input shouldn't be delayed, as it makes the 1561 // sending look longer than it takes. 1562 boolean ignoreEarliestRemovalTime = mRemoteInputController.isSpinning(key) 1563 && !FORCE_REMOTE_INPUT_HISTORY; 1564 deferRemoval = !mHeadsUpManager.removeNotification(key, ignoreEarliestRemovalTime); 1565 } 1566 if (key.equals(mMediaNotificationKey)) { 1567 clearCurrentMediaNotification(); 1568 updateMediaMetaData(true, true); 1569 } 1570 if (FORCE_REMOTE_INPUT_HISTORY && mRemoteInputController.isSpinning(key)) { 1571 Entry entry = mNotificationData.get(key); 1572 StatusBarNotification sbn = entry.notification; 1573 1574 Notification.Builder b = Notification.Builder 1575 .recoverBuilder(mContext, sbn.getNotification().clone()); 1576 CharSequence[] oldHistory = sbn.getNotification().extras 1577 .getCharSequenceArray(Notification.EXTRA_REMOTE_INPUT_HISTORY); 1578 CharSequence[] newHistory; 1579 if (oldHistory == null) { 1580 newHistory = new CharSequence[1]; 1581 } else { 1582 newHistory = new CharSequence[oldHistory.length + 1]; 1583 for (int i = 0; i < oldHistory.length; i++) { 1584 newHistory[i + 1] = oldHistory[i]; 1585 } 1586 } 1587 newHistory[0] = String.valueOf(entry.remoteInputText); 1588 b.setRemoteInputHistory(newHistory); 1589 1590 Notification newNotification = b.build(); 1591 1592 // Undo any compatibility view inflation 1593 newNotification.contentView = sbn.getNotification().contentView; 1594 newNotification.bigContentView = sbn.getNotification().bigContentView; 1595 newNotification.headsUpContentView = sbn.getNotification().headsUpContentView; 1596 1597 StatusBarNotification newSbn = new StatusBarNotification(sbn.getPackageName(), 1598 sbn.getOpPkg(), 1599 sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(), 1600 0, newNotification, sbn.getUser(), sbn.getPostTime()); 1601 1602 updateNotification(newSbn, null); 1603 mKeysKeptForRemoteInput.add(entry.key); 1604 return; 1605 } 1606 if (deferRemoval) { 1607 mLatestRankingMap = ranking; 1608 mHeadsUpEntriesToRemoveOnSwitch.add(mHeadsUpManager.getEntry(key)); 1609 return; 1610 } 1611 Entry entry = mNotificationData.get(key); 1612 1613 if (entry != null && mRemoteInputController.isRemoteInputActive(entry) 1614 && (entry.row != null && !entry.row.isDismissed())) { 1615 mLatestRankingMap = ranking; 1616 mRemoteInputEntriesToRemoveOnCollapse.add(entry); 1617 return; 1618 } 1619 1620 if (entry != null && entry.row != null) { 1621 entry.row.setRemoved(); 1622 } 1623 // Let's remove the children if this was a summary 1624 handleGroupSummaryRemoved(key, ranking); 1625 StatusBarNotification old = removeNotificationViews(key, ranking); 1626 if (SPEW) Log.d(TAG, "removeNotification key=" + key + " old=" + old); 1627 1628 if (old != null) { 1629 if (CLOSE_PANEL_WHEN_EMPTIED && !hasActiveNotifications() 1630 && !mNotificationPanel.isTracking() && !mNotificationPanel.isQsExpanded()) { 1631 if (mState == StatusBarState.SHADE) { 1632 animateCollapsePanels(); 1633 } else if (mState == StatusBarState.SHADE_LOCKED && !isCollapsing()) { 1634 goToKeyguard(); 1635 } 1636 } 1637 } 1638 setAreThereNotifications(); 1639 } 1640 1641 /** 1642 * Ensures that the group children are cancelled immediately when the group summary is cancelled 1643 * instead of waiting for the notification manager to send all cancels. Otherwise this could 1644 * lead to flickers. 1645 * 1646 * This also ensures that the animation looks nice and only consists of a single disappear 1647 * animation instead of multiple. 1648 * 1649 * @param key the key of the notification was removed 1650 * @param ranking the current ranking 1651 */ handleGroupSummaryRemoved(String key, RankingMap ranking)1652 private void handleGroupSummaryRemoved(String key, 1653 RankingMap ranking) { 1654 Entry entry = mNotificationData.get(key); 1655 if (entry != null && entry.row != null 1656 && entry.row.isSummaryWithChildren()) { 1657 if (entry.notification.getOverrideGroupKey() != null && !entry.row.isDismissed()) { 1658 // We don't want to remove children for autobundled notifications as they are not 1659 // always cancelled. We only remove them if they were dismissed by the user. 1660 return; 1661 } 1662 List<ExpandableNotificationRow> notificationChildren = 1663 entry.row.getNotificationChildren(); 1664 ArrayList<ExpandableNotificationRow> toRemove = new ArrayList<>(notificationChildren); 1665 for (int i = 0; i < toRemove.size(); i++) { 1666 toRemove.get(i).setKeepInParent(true); 1667 // we need to set this state earlier as otherwise we might generate some weird 1668 // animations 1669 toRemove.get(i).setRemoved(); 1670 } 1671 for (int i = 0; i < toRemove.size(); i++) { 1672 removeNotification(toRemove.get(i).getStatusBarNotification().getKey(), ranking); 1673 // we need to ensure that the view is actually properly removed from the viewstate 1674 // as this won't happen anymore when kept in the parent. 1675 mStackScroller.removeViewStateForView(toRemove.get(i)); 1676 } 1677 } 1678 } 1679 1680 @Override performRemoveNotification(StatusBarNotification n, boolean removeView)1681 protected void performRemoveNotification(StatusBarNotification n, boolean removeView) { 1682 Entry entry = mNotificationData.get(n.getKey()); 1683 if (mRemoteInputController.isRemoteInputActive(entry)) { 1684 mRemoteInputController.removeRemoteInput(entry); 1685 } 1686 super.performRemoveNotification(n, removeView); 1687 } 1688 1689 @Override refreshLayout(int layoutDirection)1690 protected void refreshLayout(int layoutDirection) { 1691 if (mNavigationBarView != null) { 1692 mNavigationBarView.setLayoutDirection(layoutDirection); 1693 } 1694 } 1695 updateNotificationShade()1696 private void updateNotificationShade() { 1697 if (mStackScroller == null) return; 1698 1699 // Do not modify the notifications during collapse. 1700 if (isCollapsing()) { 1701 addPostCollapseAction(new Runnable() { 1702 @Override 1703 public void run() { 1704 updateNotificationShade(); 1705 } 1706 }); 1707 return; 1708 } 1709 1710 ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications(); 1711 ArrayList<ExpandableNotificationRow> toShow = new ArrayList<>(activeNotifications.size()); 1712 final int N = activeNotifications.size(); 1713 for (int i=0; i<N; i++) { 1714 Entry ent = activeNotifications.get(i); 1715 int vis = ent.notification.getNotification().visibility; 1716 1717 // Display public version of the notification if we need to redact. 1718 final boolean hideSensitive = 1719 !userAllowsPrivateNotificationsInPublic(ent.notification.getUserId()); 1720 boolean sensitiveNote = vis == Notification.VISIBILITY_PRIVATE; 1721 boolean sensitivePackage = packageHasVisibilityOverride(ent.notification.getKey()); 1722 boolean sensitive = (sensitiveNote && hideSensitive) || sensitivePackage; 1723 boolean showingPublic = sensitive && isLockscreenPublicMode(); 1724 if (showingPublic) { 1725 updatePublicContentView(ent, ent.notification); 1726 } 1727 ent.row.setSensitive(sensitive, hideSensitive); 1728 if (ent.autoRedacted && ent.legacy) { 1729 // TODO: Also fade this? Or, maybe easier (and better), provide a dark redacted form 1730 // for legacy auto redacted notifications. 1731 if (showingPublic) { 1732 ent.row.setShowingLegacyBackground(false); 1733 } else { 1734 ent.row.setShowingLegacyBackground(true); 1735 } 1736 } 1737 if (mGroupManager.isChildInGroupWithSummary(ent.row.getStatusBarNotification())) { 1738 ExpandableNotificationRow summary = mGroupManager.getGroupSummary( 1739 ent.row.getStatusBarNotification()); 1740 List<ExpandableNotificationRow> orderedChildren = 1741 mTmpChildOrderMap.get(summary); 1742 if (orderedChildren == null) { 1743 orderedChildren = new ArrayList<>(); 1744 mTmpChildOrderMap.put(summary, orderedChildren); 1745 } 1746 orderedChildren.add(ent.row); 1747 } else { 1748 toShow.add(ent.row); 1749 } 1750 1751 } 1752 1753 ArrayList<ExpandableNotificationRow> toRemove = new ArrayList<>(); 1754 for (int i=0; i< mStackScroller.getChildCount(); i++) { 1755 View child = mStackScroller.getChildAt(i); 1756 if (!toShow.contains(child) && child instanceof ExpandableNotificationRow) { 1757 toRemove.add((ExpandableNotificationRow) child); 1758 } 1759 } 1760 1761 for (ExpandableNotificationRow remove : toRemove) { 1762 if (mGroupManager.isChildInGroupWithSummary(remove.getStatusBarNotification())) { 1763 // we are only transfering this notification to its parent, don't generate an animation 1764 mStackScroller.setChildTransferInProgress(true); 1765 } 1766 if (remove.isSummaryWithChildren()) { 1767 remove.removeAllChildren(); 1768 } 1769 mStackScroller.removeView(remove); 1770 mStackScroller.setChildTransferInProgress(false); 1771 } 1772 1773 removeNotificationChildren(); 1774 1775 for (int i=0; i<toShow.size(); i++) { 1776 View v = toShow.get(i); 1777 if (v.getParent() == null) { 1778 mStackScroller.addView(v); 1779 } 1780 } 1781 1782 addNotificationChildrenAndSort(); 1783 1784 // So after all this work notifications still aren't sorted correctly. 1785 // Let's do that now by advancing through toShow and mStackScroller in 1786 // lock-step, making sure mStackScroller matches what we see in toShow. 1787 int j = 0; 1788 for (int i = 0; i < mStackScroller.getChildCount(); i++) { 1789 View child = mStackScroller.getChildAt(i); 1790 if (!(child instanceof ExpandableNotificationRow)) { 1791 // We don't care about non-notification views. 1792 continue; 1793 } 1794 1795 ExpandableNotificationRow targetChild = toShow.get(j); 1796 if (child != targetChild) { 1797 // Oops, wrong notification at this position. Put the right one 1798 // here and advance both lists. 1799 mStackScroller.changeViewPosition(targetChild, i); 1800 } 1801 j++; 1802 1803 } 1804 1805 // clear the map again for the next usage 1806 mTmpChildOrderMap.clear(); 1807 1808 updateRowStates(); 1809 updateSpeedbump(); 1810 updateClearAll(); 1811 updateEmptyShadeView(); 1812 1813 updateQsExpansionEnabled(); 1814 mShadeUpdates.check(); 1815 } 1816 1817 /** 1818 * Disable QS if device not provisioned. 1819 * If the user switcher is simple then disable QS during setup because 1820 * the user intends to use the lock screen user switcher, QS in not needed. 1821 */ updateQsExpansionEnabled()1822 private void updateQsExpansionEnabled() { 1823 mNotificationPanel.setQsExpansionEnabled(isDeviceProvisioned() 1824 && (mUserSetup || mUserSwitcherController == null 1825 || !mUserSwitcherController.isSimpleUserSwitcher()) 1826 && ((mDisabled2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) == 0) 1827 && !ONLY_CORE_APPS); 1828 } 1829 addNotificationChildrenAndSort()1830 private void addNotificationChildrenAndSort() { 1831 // Let's now add all notification children which are missing 1832 boolean orderChanged = false; 1833 for (int i = 0; i < mStackScroller.getChildCount(); i++) { 1834 View view = mStackScroller.getChildAt(i); 1835 if (!(view instanceof ExpandableNotificationRow)) { 1836 // We don't care about non-notification views. 1837 continue; 1838 } 1839 1840 ExpandableNotificationRow parent = (ExpandableNotificationRow) view; 1841 List<ExpandableNotificationRow> children = parent.getNotificationChildren(); 1842 List<ExpandableNotificationRow> orderedChildren = mTmpChildOrderMap.get(parent); 1843 1844 for (int childIndex = 0; orderedChildren != null && childIndex < orderedChildren.size(); 1845 childIndex++) { 1846 ExpandableNotificationRow childView = orderedChildren.get(childIndex); 1847 if (children == null || !children.contains(childView)) { 1848 parent.addChildNotification(childView, childIndex); 1849 mStackScroller.notifyGroupChildAdded(childView); 1850 } 1851 } 1852 1853 // Finally after removing and adding has been beformed we can apply the order. 1854 orderChanged |= parent.applyChildOrder(orderedChildren); 1855 } 1856 if (orderChanged) { 1857 mStackScroller.generateChildOrderChangedEvent(); 1858 } 1859 } 1860 removeNotificationChildren()1861 private void removeNotificationChildren() { 1862 // First let's remove all children which don't belong in the parents 1863 ArrayList<ExpandableNotificationRow> toRemove = new ArrayList<>(); 1864 for (int i = 0; i < mStackScroller.getChildCount(); i++) { 1865 View view = mStackScroller.getChildAt(i); 1866 if (!(view instanceof ExpandableNotificationRow)) { 1867 // We don't care about non-notification views. 1868 continue; 1869 } 1870 1871 ExpandableNotificationRow parent = (ExpandableNotificationRow) view; 1872 List<ExpandableNotificationRow> children = parent.getNotificationChildren(); 1873 List<ExpandableNotificationRow> orderedChildren = mTmpChildOrderMap.get(parent); 1874 1875 if (children != null) { 1876 toRemove.clear(); 1877 for (ExpandableNotificationRow childRow : children) { 1878 if ((orderedChildren == null 1879 || !orderedChildren.contains(childRow)) 1880 && !childRow.keepInParent()) { 1881 toRemove.add(childRow); 1882 } 1883 } 1884 for (ExpandableNotificationRow remove : toRemove) { 1885 parent.removeChildNotification(remove); 1886 if (mNotificationData.get(remove.getStatusBarNotification().getKey()) == null) { 1887 // We only want to add an animation if the view is completely removed 1888 // otherwise it's just a transfer 1889 mStackScroller.notifyGroupChildRemoved(remove, 1890 parent.getChildrenContainer()); 1891 } 1892 } 1893 } 1894 } 1895 } 1896 1897 @Override addQsTile(ComponentName tile)1898 public void addQsTile(ComponentName tile) { 1899 mQSPanel.getHost().addTile(tile); 1900 } 1901 1902 @Override remQsTile(ComponentName tile)1903 public void remQsTile(ComponentName tile) { 1904 mQSPanel.getHost().removeTile(tile); 1905 } 1906 1907 @Override clickTile(ComponentName tile)1908 public void clickTile(ComponentName tile) { 1909 mQSPanel.clickTile(tile); 1910 } 1911 packageHasVisibilityOverride(String key)1912 private boolean packageHasVisibilityOverride(String key) { 1913 return mNotificationData.getVisibilityOverride(key) == Notification.VISIBILITY_PRIVATE; 1914 } 1915 updateClearAll()1916 private void updateClearAll() { 1917 boolean showDismissView = 1918 mState != StatusBarState.KEYGUARD && 1919 mNotificationData.hasActiveClearableNotifications(); 1920 mStackScroller.updateDismissView(showDismissView); 1921 } 1922 updateEmptyShadeView()1923 private void updateEmptyShadeView() { 1924 boolean showEmptyShade = 1925 mState != StatusBarState.KEYGUARD && 1926 mNotificationData.getActiveNotifications().size() == 0; 1927 mNotificationPanel.setShadeEmpty(showEmptyShade); 1928 } 1929 updateSpeedbump()1930 private void updateSpeedbump() { 1931 int speedbumpIndex = -1; 1932 int currentIndex = 0; 1933 final int N = mStackScroller.getChildCount(); 1934 for (int i = 0; i < N; i++) { 1935 View view = mStackScroller.getChildAt(i); 1936 if (view.getVisibility() == View.GONE || !(view instanceof ExpandableNotificationRow)) { 1937 continue; 1938 } 1939 ExpandableNotificationRow row = (ExpandableNotificationRow) view; 1940 if (mNotificationData.isAmbient(row.getStatusBarNotification().getKey())) { 1941 speedbumpIndex = currentIndex; 1942 break; 1943 } 1944 currentIndex++; 1945 } 1946 mStackScroller.updateSpeedBumpIndex(speedbumpIndex); 1947 } 1948 isTopLevelChild(Entry entry)1949 public static boolean isTopLevelChild(Entry entry) { 1950 return entry.row.getParent() instanceof NotificationStackScrollLayout; 1951 } 1952 1953 @Override updateNotifications()1954 protected void updateNotifications() { 1955 mNotificationData.filterAndSort(); 1956 1957 updateNotificationShade(); 1958 mIconController.updateNotificationIcons(mNotificationData); 1959 } 1960 requestNotificationUpdate()1961 public void requestNotificationUpdate() { 1962 updateNotifications(); 1963 } 1964 1965 @Override setAreThereNotifications()1966 protected void setAreThereNotifications() { 1967 1968 if (SPEW) { 1969 final boolean clearable = hasActiveNotifications() && 1970 mNotificationData.hasActiveClearableNotifications(); 1971 Log.d(TAG, "setAreThereNotifications: N=" + 1972 mNotificationData.getActiveNotifications().size() + " any=" + 1973 hasActiveNotifications() + " clearable=" + clearable); 1974 } 1975 1976 final View nlo = mStatusBarView.findViewById(R.id.notification_lights_out); 1977 final boolean showDot = hasActiveNotifications() && !areLightsOn(); 1978 if (showDot != (nlo.getAlpha() == 1.0f)) { 1979 if (showDot) { 1980 nlo.setAlpha(0f); 1981 nlo.setVisibility(View.VISIBLE); 1982 } 1983 nlo.animate() 1984 .alpha(showDot?1:0) 1985 .setDuration(showDot?750:250) 1986 .setInterpolator(new AccelerateInterpolator(2.0f)) 1987 .setListener(showDot ? null : new AnimatorListenerAdapter() { 1988 @Override 1989 public void onAnimationEnd(Animator _a) { 1990 nlo.setVisibility(View.GONE); 1991 } 1992 }) 1993 .start(); 1994 } 1995 1996 findAndUpdateMediaNotifications(); 1997 } 1998 findAndUpdateMediaNotifications()1999 public void findAndUpdateMediaNotifications() { 2000 boolean metaDataChanged = false; 2001 2002 synchronized (mNotificationData) { 2003 ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications(); 2004 final int N = activeNotifications.size(); 2005 2006 // Promote the media notification with a controller in 'playing' state, if any. 2007 Entry mediaNotification = null; 2008 MediaController controller = null; 2009 for (int i = 0; i < N; i++) { 2010 final Entry entry = activeNotifications.get(i); 2011 if (isMediaNotification(entry)) { 2012 final MediaSession.Token token = 2013 entry.notification.getNotification().extras 2014 .getParcelable(Notification.EXTRA_MEDIA_SESSION); 2015 if (token != null) { 2016 MediaController aController = new MediaController(mContext, token); 2017 if (PlaybackState.STATE_PLAYING == 2018 getMediaControllerPlaybackState(aController)) { 2019 if (DEBUG_MEDIA) { 2020 Log.v(TAG, "DEBUG_MEDIA: found mediastyle controller matching " 2021 + entry.notification.getKey()); 2022 } 2023 mediaNotification = entry; 2024 controller = aController; 2025 break; 2026 } 2027 } 2028 } 2029 } 2030 if (mediaNotification == null) { 2031 // Still nothing? OK, let's just look for live media sessions and see if they match 2032 // one of our notifications. This will catch apps that aren't (yet!) using media 2033 // notifications. 2034 2035 if (mMediaSessionManager != null) { 2036 final List<MediaController> sessions 2037 = mMediaSessionManager.getActiveSessionsForUser( 2038 null, 2039 UserHandle.USER_ALL); 2040 2041 for (MediaController aController : sessions) { 2042 if (PlaybackState.STATE_PLAYING == 2043 getMediaControllerPlaybackState(aController)) { 2044 // now to see if we have one like this 2045 final String pkg = aController.getPackageName(); 2046 2047 for (int i = 0; i < N; i++) { 2048 final Entry entry = activeNotifications.get(i); 2049 if (entry.notification.getPackageName().equals(pkg)) { 2050 if (DEBUG_MEDIA) { 2051 Log.v(TAG, "DEBUG_MEDIA: found controller matching " 2052 + entry.notification.getKey()); 2053 } 2054 controller = aController; 2055 mediaNotification = entry; 2056 break; 2057 } 2058 } 2059 } 2060 } 2061 } 2062 } 2063 2064 if (controller != null && !sameSessions(mMediaController, controller)) { 2065 // We have a new media session 2066 clearCurrentMediaNotification(); 2067 mMediaController = controller; 2068 mMediaController.registerCallback(mMediaListener); 2069 mMediaMetadata = mMediaController.getMetadata(); 2070 if (DEBUG_MEDIA) { 2071 Log.v(TAG, "DEBUG_MEDIA: insert listener, receive metadata: " 2072 + mMediaMetadata); 2073 } 2074 2075 if (mediaNotification != null) { 2076 mMediaNotificationKey = mediaNotification.notification.getKey(); 2077 if (DEBUG_MEDIA) { 2078 Log.v(TAG, "DEBUG_MEDIA: Found new media notification: key=" 2079 + mMediaNotificationKey + " controller=" + mMediaController); 2080 } 2081 } 2082 metaDataChanged = true; 2083 } 2084 } 2085 2086 if (metaDataChanged) { 2087 updateNotifications(); 2088 } 2089 updateMediaMetaData(metaDataChanged, true); 2090 } 2091 getMediaControllerPlaybackState(MediaController controller)2092 private int getMediaControllerPlaybackState(MediaController controller) { 2093 if (controller != null) { 2094 final PlaybackState playbackState = controller.getPlaybackState(); 2095 if (playbackState != null) { 2096 return playbackState.getState(); 2097 } 2098 } 2099 return PlaybackState.STATE_NONE; 2100 } 2101 isPlaybackActive(int state)2102 private boolean isPlaybackActive(int state) { 2103 if (state != PlaybackState.STATE_STOPPED 2104 && state != PlaybackState.STATE_ERROR 2105 && state != PlaybackState.STATE_NONE) { 2106 return true; 2107 } 2108 return false; 2109 } 2110 clearCurrentMediaNotification()2111 private void clearCurrentMediaNotification() { 2112 mMediaNotificationKey = null; 2113 mMediaMetadata = null; 2114 if (mMediaController != null) { 2115 if (DEBUG_MEDIA) { 2116 Log.v(TAG, "DEBUG_MEDIA: Disconnecting from old controller: " 2117 + mMediaController.getPackageName()); 2118 } 2119 mMediaController.unregisterCallback(mMediaListener); 2120 } 2121 mMediaController = null; 2122 } 2123 sameSessions(MediaController a, MediaController b)2124 private boolean sameSessions(MediaController a, MediaController b) { 2125 if (a == b) return true; 2126 if (a == null) return false; 2127 return a.controlsSameSession(b); 2128 } 2129 2130 /** 2131 * Hide the album artwork that is fading out and release its bitmap. 2132 */ 2133 private Runnable mHideBackdropFront = new Runnable() { 2134 @Override 2135 public void run() { 2136 if (DEBUG_MEDIA) { 2137 Log.v(TAG, "DEBUG_MEDIA: removing fade layer"); 2138 } 2139 mBackdropFront.setVisibility(View.INVISIBLE); 2140 mBackdropFront.animate().cancel(); 2141 mBackdropFront.setImageDrawable(null); 2142 } 2143 }; 2144 2145 /** 2146 * Refresh or remove lockscreen artwork from media metadata or the lockscreen wallpaper. 2147 */ updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation)2148 public void updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation) { 2149 Trace.beginSection("PhoneStatusBar#updateMediaMetaData"); 2150 if (!SHOW_LOCKSCREEN_MEDIA_ARTWORK) { 2151 Trace.endSection(); 2152 return; 2153 } 2154 2155 if (mBackdrop == null) { 2156 Trace.endSection(); 2157 return; // called too early 2158 } 2159 2160 if (mLaunchTransitionFadingAway) { 2161 mBackdrop.setVisibility(View.INVISIBLE); 2162 Trace.endSection(); 2163 return; 2164 } 2165 2166 if (DEBUG_MEDIA) { 2167 Log.v(TAG, "DEBUG_MEDIA: updating album art for notification " + mMediaNotificationKey 2168 + " metadata=" + mMediaMetadata 2169 + " metaDataChanged=" + metaDataChanged 2170 + " state=" + mState); 2171 } 2172 2173 Drawable artworkDrawable = null; 2174 if (mMediaMetadata != null) { 2175 Bitmap artworkBitmap = null; 2176 artworkBitmap = mMediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ART); 2177 if (artworkBitmap == null) { 2178 artworkBitmap = mMediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART); 2179 // might still be null 2180 } 2181 if (artworkBitmap != null) { 2182 artworkDrawable = new BitmapDrawable(mBackdropBack.getResources(), artworkBitmap); 2183 } 2184 } 2185 boolean allowWhenShade = false; 2186 if (ENABLE_LOCKSCREEN_WALLPAPER && artworkDrawable == null) { 2187 Bitmap lockWallpaper = mLockscreenWallpaper.getBitmap(); 2188 if (lockWallpaper != null) { 2189 artworkDrawable = new LockscreenWallpaper.WallpaperDrawable( 2190 mBackdropBack.getResources(), lockWallpaper); 2191 // We're in the SHADE mode on the SIM screen - yet we still need to show 2192 // the lockscreen wallpaper in that mode. 2193 allowWhenShade = mStatusBarKeyguardViewManager != null 2194 && mStatusBarKeyguardViewManager.isShowing(); 2195 } 2196 } 2197 2198 boolean hideBecauseOccluded = mStatusBarKeyguardViewManager != null 2199 && mStatusBarKeyguardViewManager.isOccluded(); 2200 2201 final boolean hasArtwork = artworkDrawable != null; 2202 2203 if ((hasArtwork || DEBUG_MEDIA_FAKE_ARTWORK) 2204 && (mState != StatusBarState.SHADE || allowWhenShade) 2205 && mFingerprintUnlockController.getMode() 2206 != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING 2207 && !hideBecauseOccluded) { 2208 // time to show some art! 2209 if (mBackdrop.getVisibility() != View.VISIBLE) { 2210 mBackdrop.setVisibility(View.VISIBLE); 2211 if (allowEnterAnimation) { 2212 mBackdrop.animate().alpha(1f).withEndAction(new Runnable() { 2213 @Override 2214 public void run() { 2215 mStatusBarWindowManager.setBackdropShowing(true); 2216 } 2217 }); 2218 } else { 2219 mBackdrop.animate().cancel(); 2220 mBackdrop.setAlpha(1f); 2221 mStatusBarWindowManager.setBackdropShowing(true); 2222 } 2223 metaDataChanged = true; 2224 if (DEBUG_MEDIA) { 2225 Log.v(TAG, "DEBUG_MEDIA: Fading in album artwork"); 2226 } 2227 } 2228 if (metaDataChanged) { 2229 if (mBackdropBack.getDrawable() != null) { 2230 Drawable drawable = 2231 mBackdropBack.getDrawable().getConstantState() 2232 .newDrawable(mBackdropFront.getResources()).mutate(); 2233 mBackdropFront.setImageDrawable(drawable); 2234 if (mScrimSrcModeEnabled) { 2235 mBackdropFront.getDrawable().mutate().setXfermode(mSrcOverXferMode); 2236 } 2237 mBackdropFront.setAlpha(1f); 2238 mBackdropFront.setVisibility(View.VISIBLE); 2239 } else { 2240 mBackdropFront.setVisibility(View.INVISIBLE); 2241 } 2242 2243 if (DEBUG_MEDIA_FAKE_ARTWORK) { 2244 final int c = 0xFF000000 | (int)(Math.random() * 0xFFFFFF); 2245 Log.v(TAG, String.format("DEBUG_MEDIA: setting new color: 0x%08x", c)); 2246 mBackdropBack.setBackgroundColor(0xFFFFFFFF); 2247 mBackdropBack.setImageDrawable(new ColorDrawable(c)); 2248 } else { 2249 mBackdropBack.setImageDrawable(artworkDrawable); 2250 } 2251 if (mScrimSrcModeEnabled) { 2252 mBackdropBack.getDrawable().mutate().setXfermode(mSrcXferMode); 2253 } 2254 2255 if (mBackdropFront.getVisibility() == View.VISIBLE) { 2256 if (DEBUG_MEDIA) { 2257 Log.v(TAG, "DEBUG_MEDIA: Crossfading album artwork from " 2258 + mBackdropFront.getDrawable() 2259 + " to " 2260 + mBackdropBack.getDrawable()); 2261 } 2262 mBackdropFront.animate() 2263 .setDuration(250) 2264 .alpha(0f).withEndAction(mHideBackdropFront); 2265 } 2266 } 2267 } else { 2268 // need to hide the album art, either because we are unlocked or because 2269 // the metadata isn't there to support it 2270 if (mBackdrop.getVisibility() != View.GONE) { 2271 if (DEBUG_MEDIA) { 2272 Log.v(TAG, "DEBUG_MEDIA: Fading out album artwork"); 2273 } 2274 if (mFingerprintUnlockController.getMode() 2275 == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING 2276 || hideBecauseOccluded) { 2277 2278 // We are unlocking directly - no animation! 2279 mBackdrop.setVisibility(View.GONE); 2280 mBackdropBack.setImageDrawable(null); 2281 mStatusBarWindowManager.setBackdropShowing(false); 2282 } else { 2283 mStatusBarWindowManager.setBackdropShowing(false); 2284 mBackdrop.animate() 2285 // Never let the alpha become zero - otherwise the RenderNode 2286 // won't draw anything and uninitialized memory will show through 2287 // if mScrimSrcModeEnabled. Note that 0.001 is rounded down to 0 in 2288 // libhwui. 2289 .alpha(0.002f) 2290 .setInterpolator(Interpolators.ACCELERATE_DECELERATE) 2291 .setDuration(300) 2292 .setStartDelay(0) 2293 .withEndAction(new Runnable() { 2294 @Override 2295 public void run() { 2296 mBackdrop.setVisibility(View.GONE); 2297 mBackdropFront.animate().cancel(); 2298 mBackdropBack.setImageDrawable(null); 2299 mHandler.post(mHideBackdropFront); 2300 } 2301 }); 2302 if (mKeyguardFadingAway) { 2303 mBackdrop.animate() 2304 2305 // Make it disappear faster, as the focus should be on the activity 2306 // behind. 2307 .setDuration(mKeyguardFadingAwayDuration / 2) 2308 .setStartDelay(mKeyguardFadingAwayDelay) 2309 .setInterpolator(Interpolators.LINEAR) 2310 .start(); 2311 } 2312 } 2313 } 2314 } 2315 Trace.endSection(); 2316 } 2317 updateReportRejectedTouchVisibility()2318 private void updateReportRejectedTouchVisibility() { 2319 if (mReportRejectedTouch == null) { 2320 return; 2321 } 2322 mReportRejectedTouch.setVisibility(mState == StatusBarState.KEYGUARD 2323 && mFalsingManager.isReportingEnabled() ? View.VISIBLE : View.INVISIBLE); 2324 } 2325 adjustDisableFlags(int state)2326 protected int adjustDisableFlags(int state) { 2327 if (!mLaunchTransitionFadingAway && !mKeyguardFadingAway 2328 && (mExpandedVisible || mBouncerShowing || mWaitingForKeyguardExit)) { 2329 state |= StatusBarManager.DISABLE_NOTIFICATION_ICONS; 2330 state |= StatusBarManager.DISABLE_SYSTEM_INFO; 2331 } 2332 return state; 2333 } 2334 2335 /** 2336 * State is one or more of the DISABLE constants from StatusBarManager. 2337 */ 2338 @Override disable(int state1, int state2, boolean animate)2339 public void disable(int state1, int state2, boolean animate) { 2340 animate &= mStatusBarWindowState != WINDOW_STATE_HIDDEN; 2341 mDisabledUnmodified1 = state1; 2342 mDisabledUnmodified2 = state2; 2343 state1 = adjustDisableFlags(state1); 2344 final int old1 = mDisabled1; 2345 final int diff1 = state1 ^ old1; 2346 mDisabled1 = state1; 2347 2348 final int old2 = mDisabled2; 2349 final int diff2 = state2 ^ old2; 2350 mDisabled2 = state2; 2351 2352 if (DEBUG) { 2353 Log.d(TAG, String.format("disable1: 0x%08x -> 0x%08x (diff1: 0x%08x)", 2354 old1, state1, diff1)); 2355 Log.d(TAG, String.format("disable2: 0x%08x -> 0x%08x (diff2: 0x%08x)", 2356 old2, state2, diff2)); 2357 } 2358 2359 StringBuilder flagdbg = new StringBuilder(); 2360 flagdbg.append("disable: < "); 2361 flagdbg.append(((state1 & StatusBarManager.DISABLE_EXPAND) != 0) ? "EXPAND" : "expand"); 2362 flagdbg.append(((diff1 & StatusBarManager.DISABLE_EXPAND) != 0) ? "* " : " "); 2363 flagdbg.append(((state1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) ? "ICONS" : "icons"); 2364 flagdbg.append(((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) ? "* " : " "); 2365 flagdbg.append(((state1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) ? "ALERTS" : "alerts"); 2366 flagdbg.append(((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) ? "* " : " "); 2367 flagdbg.append(((state1 & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) ? "SYSTEM_INFO" : "system_info"); 2368 flagdbg.append(((diff1 & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) ? "* " : " "); 2369 flagdbg.append(((state1 & StatusBarManager.DISABLE_BACK) != 0) ? "BACK" : "back"); 2370 flagdbg.append(((diff1 & StatusBarManager.DISABLE_BACK) != 0) ? "* " : " "); 2371 flagdbg.append(((state1 & StatusBarManager.DISABLE_HOME) != 0) ? "HOME" : "home"); 2372 flagdbg.append(((diff1 & StatusBarManager.DISABLE_HOME) != 0) ? "* " : " "); 2373 flagdbg.append(((state1 & StatusBarManager.DISABLE_RECENT) != 0) ? "RECENT" : "recent"); 2374 flagdbg.append(((diff1 & StatusBarManager.DISABLE_RECENT) != 0) ? "* " : " "); 2375 flagdbg.append(((state1 & StatusBarManager.DISABLE_CLOCK) != 0) ? "CLOCK" : "clock"); 2376 flagdbg.append(((diff1 & StatusBarManager.DISABLE_CLOCK) != 0) ? "* " : " "); 2377 flagdbg.append(((state1 & StatusBarManager.DISABLE_SEARCH) != 0) ? "SEARCH" : "search"); 2378 flagdbg.append(((diff1 & StatusBarManager.DISABLE_SEARCH) != 0) ? "* " : " "); 2379 flagdbg.append(((state2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) ? "QUICK_SETTINGS" 2380 : "quick_settings"); 2381 flagdbg.append(((diff2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) ? "* " : " "); 2382 flagdbg.append(">"); 2383 Log.d(TAG, flagdbg.toString()); 2384 2385 if ((diff1 & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) { 2386 if ((state1 & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) { 2387 mIconController.hideSystemIconArea(animate); 2388 } else { 2389 mIconController.showSystemIconArea(animate); 2390 } 2391 } 2392 2393 if ((diff1 & StatusBarManager.DISABLE_CLOCK) != 0) { 2394 boolean visible = (state1 & StatusBarManager.DISABLE_CLOCK) == 0; 2395 mIconController.setClockVisibility(visible); 2396 } 2397 if ((diff1 & StatusBarManager.DISABLE_EXPAND) != 0) { 2398 if ((state1 & StatusBarManager.DISABLE_EXPAND) != 0) { 2399 animateCollapsePanels(); 2400 } 2401 } 2402 2403 if ((diff1 & (StatusBarManager.DISABLE_HOME 2404 | StatusBarManager.DISABLE_RECENT 2405 | StatusBarManager.DISABLE_BACK 2406 | StatusBarManager.DISABLE_SEARCH)) != 0) { 2407 // the nav bar will take care of these 2408 if (mNavigationBarView != null) mNavigationBarView.setDisabledFlags(state1); 2409 2410 if ((state1 & StatusBarManager.DISABLE_RECENT) != 0) { 2411 // close recents if it's visible 2412 mHandler.removeMessages(MSG_HIDE_RECENT_APPS); 2413 mHandler.sendEmptyMessage(MSG_HIDE_RECENT_APPS); 2414 } 2415 } 2416 2417 if ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) { 2418 if ((state1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) { 2419 mIconController.hideNotificationIconArea(animate); 2420 } else { 2421 mIconController.showNotificationIconArea(animate); 2422 } 2423 } 2424 2425 if ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) { 2426 mDisableNotificationAlerts = 2427 (state1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0; 2428 mHeadsUpObserver.onChange(true); 2429 } 2430 2431 if ((diff2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) { 2432 updateQsExpansionEnabled(); 2433 } 2434 } 2435 2436 @Override createHandler()2437 protected BaseStatusBar.H createHandler() { 2438 return new PhoneStatusBar.H(); 2439 } 2440 2441 @Override startActivity(Intent intent, boolean dismissShade)2442 public void startActivity(Intent intent, boolean dismissShade) { 2443 startActivityDismissingKeyguard(intent, false, dismissShade); 2444 } 2445 2446 @Override startActivity(Intent intent, boolean dismissShade, Callback callback)2447 public void startActivity(Intent intent, boolean dismissShade, Callback callback) { 2448 startActivityDismissingKeyguard(intent, false, dismissShade, callback); 2449 } 2450 2451 @Override preventNextAnimation()2452 public void preventNextAnimation() { 2453 overrideActivityPendingAppTransition(true /* keyguardShowing */); 2454 } 2455 setQsExpanded(boolean expanded)2456 public void setQsExpanded(boolean expanded) { 2457 mStatusBarWindowManager.setQsExpanded(expanded); 2458 mKeyguardStatusView.setImportantForAccessibility(expanded 2459 ? View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 2460 : View.IMPORTANT_FOR_ACCESSIBILITY_AUTO); 2461 } 2462 isGoingToNotificationShade()2463 public boolean isGoingToNotificationShade() { 2464 return mLeaveOpenOnKeyguardHide; 2465 } 2466 isQsExpanded()2467 public boolean isQsExpanded() { 2468 return mNotificationPanel.isQsExpanded(); 2469 } 2470 isWakeUpComingFromTouch()2471 public boolean isWakeUpComingFromTouch() { 2472 return mWakeUpComingFromTouch; 2473 } 2474 isFalsingThresholdNeeded()2475 public boolean isFalsingThresholdNeeded() { 2476 return getBarState() == StatusBarState.KEYGUARD; 2477 } 2478 isDozing()2479 public boolean isDozing() { 2480 return mDozing; 2481 } 2482 2483 @Override // NotificationData.Environment getCurrentMediaNotificationKey()2484 public String getCurrentMediaNotificationKey() { 2485 return mMediaNotificationKey; 2486 } 2487 isScrimSrcModeEnabled()2488 public boolean isScrimSrcModeEnabled() { 2489 return mScrimSrcModeEnabled; 2490 } 2491 2492 /** 2493 * To be called when there's a state change in StatusBarKeyguardViewManager. 2494 */ onKeyguardViewManagerStatesUpdated()2495 public void onKeyguardViewManagerStatesUpdated() { 2496 logStateToEventlog(); 2497 } 2498 2499 @Override // UnlockMethodCache.OnUnlockMethodChangedListener onUnlockMethodStateChanged()2500 public void onUnlockMethodStateChanged() { 2501 logStateToEventlog(); 2502 } 2503 2504 @Override onHeadsUpPinnedModeChanged(boolean inPinnedMode)2505 public void onHeadsUpPinnedModeChanged(boolean inPinnedMode) { 2506 if (inPinnedMode) { 2507 mStatusBarWindowManager.setHeadsUpShowing(true); 2508 mStatusBarWindowManager.setForceStatusBarVisible(true); 2509 if (mNotificationPanel.isFullyCollapsed()) { 2510 // We need to ensure that the touchable region is updated before the window will be 2511 // resized, in order to not catch any touches. A layout will ensure that 2512 // onComputeInternalInsets will be called and after that we can resize the layout. Let's 2513 // make sure that the window stays small for one frame until the touchableRegion is set. 2514 mNotificationPanel.requestLayout(); 2515 mStatusBarWindowManager.setForceWindowCollapsed(true); 2516 mNotificationPanel.post(new Runnable() { 2517 @Override 2518 public void run() { 2519 mStatusBarWindowManager.setForceWindowCollapsed(false); 2520 } 2521 }); 2522 } 2523 } else { 2524 if (!mNotificationPanel.isFullyCollapsed() || mNotificationPanel.isTracking()) { 2525 // We are currently tracking or is open and the shade doesn't need to be kept 2526 // open artificially. 2527 mStatusBarWindowManager.setHeadsUpShowing(false); 2528 } else { 2529 // we need to keep the panel open artificially, let's wait until the animation 2530 // is finished. 2531 mHeadsUpManager.setHeadsUpGoingAway(true); 2532 mStackScroller.runAfterAnimationFinished(new Runnable() { 2533 @Override 2534 public void run() { 2535 if (!mHeadsUpManager.hasPinnedHeadsUp()) { 2536 mStatusBarWindowManager.setHeadsUpShowing(false); 2537 mHeadsUpManager.setHeadsUpGoingAway(false); 2538 } 2539 removeRemoteInputEntriesKeptUntilCollapsed(); 2540 } 2541 }); 2542 } 2543 } 2544 } 2545 2546 @Override onHeadsUpPinned(ExpandableNotificationRow headsUp)2547 public void onHeadsUpPinned(ExpandableNotificationRow headsUp) { 2548 dismissVolumeDialog(); 2549 } 2550 2551 @Override onHeadsUpUnPinned(ExpandableNotificationRow headsUp)2552 public void onHeadsUpUnPinned(ExpandableNotificationRow headsUp) { 2553 } 2554 2555 @Override onHeadsUpStateChanged(Entry entry, boolean isHeadsUp)2556 public void onHeadsUpStateChanged(Entry entry, boolean isHeadsUp) { 2557 if (!isHeadsUp && mHeadsUpEntriesToRemoveOnSwitch.contains(entry)) { 2558 removeNotification(entry.key, mLatestRankingMap); 2559 mHeadsUpEntriesToRemoveOnSwitch.remove(entry); 2560 if (mHeadsUpEntriesToRemoveOnSwitch.isEmpty()) { 2561 mLatestRankingMap = null; 2562 } 2563 } else { 2564 updateNotificationRanking(null); 2565 } 2566 2567 } 2568 2569 @Override updateHeadsUp(String key, Entry entry, boolean shouldPeek, boolean alertAgain)2570 protected void updateHeadsUp(String key, Entry entry, boolean shouldPeek, 2571 boolean alertAgain) { 2572 final boolean wasHeadsUp = isHeadsUp(key); 2573 if (wasHeadsUp) { 2574 if (!shouldPeek) { 2575 // We don't want this to be interrupting anymore, lets remove it 2576 mHeadsUpManager.removeNotification(key, false /* ignoreEarliestRemovalTime */); 2577 } else { 2578 mHeadsUpManager.updateNotification(entry, alertAgain); 2579 } 2580 } else if (shouldPeek && alertAgain) { 2581 // This notification was updated to be a heads-up, show it! 2582 mHeadsUpManager.showNotification(entry); 2583 } 2584 } 2585 2586 @Override setHeadsUpUser(int newUserId)2587 protected void setHeadsUpUser(int newUserId) { 2588 if (mHeadsUpManager != null) { 2589 mHeadsUpManager.setUser(newUserId); 2590 } 2591 } 2592 isHeadsUp(String key)2593 public boolean isHeadsUp(String key) { 2594 return mHeadsUpManager.isHeadsUp(key); 2595 } 2596 2597 @Override isSnoozedPackage(StatusBarNotification sbn)2598 protected boolean isSnoozedPackage(StatusBarNotification sbn) { 2599 return mHeadsUpManager.isSnoozed(sbn.getPackageName()); 2600 } 2601 isKeyguardCurrentlySecure()2602 public boolean isKeyguardCurrentlySecure() { 2603 return !mUnlockMethodCache.canSkipBouncer(); 2604 } 2605 setPanelExpanded(boolean isExpanded)2606 public void setPanelExpanded(boolean isExpanded) { 2607 mStatusBarWindowManager.setPanelExpanded(isExpanded); 2608 2609 if (isExpanded && getBarState() != StatusBarState.KEYGUARD) { 2610 if (DEBUG) { 2611 Log.v(TAG, "clearing notification effects from setPanelExpanded"); 2612 } 2613 clearNotificationEffects(); 2614 } 2615 2616 if (!isExpanded) { 2617 removeRemoteInputEntriesKeptUntilCollapsed(); 2618 } 2619 } 2620 removeRemoteInputEntriesKeptUntilCollapsed()2621 private void removeRemoteInputEntriesKeptUntilCollapsed() { 2622 for (int i = 0; i < mRemoteInputEntriesToRemoveOnCollapse.size(); i++) { 2623 Entry entry = mRemoteInputEntriesToRemoveOnCollapse.valueAt(i); 2624 mRemoteInputController.removeRemoteInput(entry); 2625 removeNotification(entry.key, mLatestRankingMap); 2626 } 2627 mRemoteInputEntriesToRemoveOnCollapse.clear(); 2628 } 2629 onScreenTurnedOff()2630 public void onScreenTurnedOff() { 2631 mFalsingManager.onScreenOff(); 2632 } 2633 2634 /** 2635 * All changes to the status bar and notifications funnel through here and are batched. 2636 */ 2637 private class H extends BaseStatusBar.H { 2638 @Override handleMessage(Message m)2639 public void handleMessage(Message m) { 2640 super.handleMessage(m); 2641 switch (m.what) { 2642 case MSG_OPEN_NOTIFICATION_PANEL: 2643 animateExpandNotificationsPanel(); 2644 break; 2645 case MSG_OPEN_SETTINGS_PANEL: 2646 animateExpandSettingsPanel((String) m.obj); 2647 break; 2648 case MSG_CLOSE_PANELS: 2649 animateCollapsePanels(); 2650 break; 2651 case MSG_LAUNCH_TRANSITION_TIMEOUT: 2652 onLaunchTransitionTimeout(); 2653 break; 2654 } 2655 } 2656 } 2657 2658 @Override maybeEscalateHeadsUp()2659 public void maybeEscalateHeadsUp() { 2660 Collection<HeadsUpManager.HeadsUpEntry> entries = mHeadsUpManager.getAllEntries(); 2661 for (HeadsUpManager.HeadsUpEntry entry : entries) { 2662 final StatusBarNotification sbn = entry.entry.notification; 2663 final Notification notification = sbn.getNotification(); 2664 if (notification.fullScreenIntent != null) { 2665 if (DEBUG) { 2666 Log.d(TAG, "converting a heads up to fullScreen"); 2667 } 2668 try { 2669 EventLog.writeEvent(EventLogTags.SYSUI_HEADS_UP_ESCALATION, 2670 sbn.getKey()); 2671 notification.fullScreenIntent.send(); 2672 entry.entry.notifyFullScreenIntentLaunched(); 2673 } catch (PendingIntent.CanceledException e) { 2674 } 2675 } 2676 } 2677 mHeadsUpManager.releaseAllImmediately(); 2678 } 2679 2680 /** 2681 * Called for system navigation gestures. First action opens the panel, second opens 2682 * settings. Down action closes the entire panel. 2683 */ 2684 @Override handleSystemNavigationKey(int key)2685 public void handleSystemNavigationKey(int key) { 2686 if (SPEW) Log.d(TAG, "handleSystemNavigationKey: " + key); 2687 if (!panelsEnabled() || !mKeyguardMonitor.isDeviceInteractive() 2688 || mKeyguardMonitor.isShowing()) { 2689 return; 2690 } 2691 2692 // Panels are not available in setup 2693 if (!mUserSetup) return; 2694 2695 if (KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP == key) { 2696 MetricsLogger.action(mContext, MetricsEvent.ACTION_SYSTEM_NAVIGATION_KEY_UP); 2697 mNotificationPanel.collapse(false /* delayed */, 1.0f /* speedUpFactor */); 2698 } else if (KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN == key) { 2699 MetricsLogger.action(mContext, MetricsEvent.ACTION_SYSTEM_NAVIGATION_KEY_DOWN); 2700 if (mNotificationPanel.isFullyCollapsed()) { 2701 mNotificationPanel.expand(true /* animate */); 2702 MetricsLogger.count(mContext, NotificationPanelView.COUNTER_PANEL_OPEN, 1); 2703 } else if (!mNotificationPanel.isInSettings() && !mNotificationPanel.isExpanding()){ 2704 mNotificationPanel.flingSettings(0 /* velocity */, true /* expand */); 2705 MetricsLogger.count(mContext, NotificationPanelView.COUNTER_PANEL_OPEN_QS, 1); 2706 } 2707 } 2708 2709 } 2710 panelsEnabled()2711 boolean panelsEnabled() { 2712 return (mDisabled1 & StatusBarManager.DISABLE_EXPAND) == 0 && !ONLY_CORE_APPS; 2713 } 2714 makeExpandedVisible(boolean force)2715 void makeExpandedVisible(boolean force) { 2716 if (SPEW) Log.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible); 2717 if (!force && (mExpandedVisible || !panelsEnabled())) { 2718 return; 2719 } 2720 2721 mExpandedVisible = true; 2722 2723 // Expand the window to encompass the full screen in anticipation of the drag. 2724 // This is only possible to do atomically because the status bar is at the top of the screen! 2725 mStatusBarWindowManager.setPanelVisible(true); 2726 2727 visibilityChanged(true); 2728 mWaitingForKeyguardExit = false; 2729 disable(mDisabledUnmodified1, mDisabledUnmodified2, !force /* animate */); 2730 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true); 2731 } 2732 animateCollapsePanels()2733 public void animateCollapsePanels() { 2734 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE); 2735 } 2736 2737 private final Runnable mAnimateCollapsePanels = new Runnable() { 2738 @Override 2739 public void run() { 2740 animateCollapsePanels(); 2741 } 2742 }; 2743 postAnimateCollapsePanels()2744 public void postAnimateCollapsePanels() { 2745 mHandler.post(mAnimateCollapsePanels); 2746 } 2747 postAnimateOpenPanels()2748 public void postAnimateOpenPanels() { 2749 mHandler.sendEmptyMessage(MSG_OPEN_SETTINGS_PANEL); 2750 } 2751 2752 @Override animateCollapsePanels(int flags)2753 public void animateCollapsePanels(int flags) { 2754 animateCollapsePanels(flags, false /* force */, false /* delayed */, 2755 1.0f /* speedUpFactor */); 2756 } 2757 2758 @Override animateCollapsePanels(int flags, boolean force)2759 public void animateCollapsePanels(int flags, boolean force) { 2760 animateCollapsePanels(flags, force, false /* delayed */, 1.0f /* speedUpFactor */); 2761 } 2762 2763 @Override animateCollapsePanels(int flags, boolean force, boolean delayed)2764 public void animateCollapsePanels(int flags, boolean force, boolean delayed) { 2765 animateCollapsePanels(flags, force, delayed, 1.0f /* speedUpFactor */); 2766 } 2767 animateCollapsePanels(int flags, boolean force, boolean delayed, float speedUpFactor)2768 public void animateCollapsePanels(int flags, boolean force, boolean delayed, 2769 float speedUpFactor) { 2770 if (!force && mState != StatusBarState.SHADE) { 2771 runPostCollapseRunnables(); 2772 return; 2773 } 2774 if (SPEW) { 2775 Log.d(TAG, "animateCollapse():" 2776 + " mExpandedVisible=" + mExpandedVisible 2777 + " flags=" + flags); 2778 } 2779 2780 if ((flags & CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL) == 0) { 2781 if (!mHandler.hasMessages(MSG_HIDE_RECENT_APPS)) { 2782 mHandler.removeMessages(MSG_HIDE_RECENT_APPS); 2783 mHandler.sendEmptyMessage(MSG_HIDE_RECENT_APPS); 2784 } 2785 } 2786 2787 if (mStatusBarWindow != null) { 2788 // release focus immediately to kick off focus change transition 2789 mStatusBarWindowManager.setStatusBarFocusable(false); 2790 2791 mStatusBarWindow.cancelExpandHelper(); 2792 mStatusBarView.collapsePanel(true /* animate */, delayed, speedUpFactor); 2793 } 2794 } 2795 runPostCollapseRunnables()2796 private void runPostCollapseRunnables() { 2797 ArrayList<Runnable> clonedList = new ArrayList<>(mPostCollapseRunnables); 2798 mPostCollapseRunnables.clear(); 2799 int size = clonedList.size(); 2800 for (int i = 0; i < size; i++) { 2801 clonedList.get(i).run(); 2802 } 2803 2804 } 2805 2806 @Override animateExpandNotificationsPanel()2807 public void animateExpandNotificationsPanel() { 2808 if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible); 2809 if (!panelsEnabled()) { 2810 return ; 2811 } 2812 2813 mNotificationPanel.expand(true /* animate */); 2814 2815 if (false) postStartTracing(); 2816 } 2817 2818 @Override animateExpandSettingsPanel(String subPanel)2819 public void animateExpandSettingsPanel(String subPanel) { 2820 if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible); 2821 if (!panelsEnabled()) { 2822 return; 2823 } 2824 2825 // Settings are not available in setup 2826 if (!mUserSetup) return; 2827 2828 2829 if (subPanel != null) { 2830 mQSPanel.openDetails(subPanel); 2831 } 2832 mNotificationPanel.expandWithQs(); 2833 2834 if (false) postStartTracing(); 2835 } 2836 animateCollapseQuickSettings()2837 public void animateCollapseQuickSettings() { 2838 if (mState == StatusBarState.SHADE) { 2839 mStatusBarView.collapsePanel(true, false /* delayed */, 1.0f /* speedUpFactor */); 2840 } 2841 } 2842 makeExpandedInvisible()2843 void makeExpandedInvisible() { 2844 if (SPEW) Log.d(TAG, "makeExpandedInvisible: mExpandedVisible=" + mExpandedVisible 2845 + " mExpandedVisible=" + mExpandedVisible); 2846 2847 if (!mExpandedVisible || mStatusBarWindow == null) { 2848 return; 2849 } 2850 2851 // Ensure the panel is fully collapsed (just in case; bug 6765842, 7260868) 2852 mStatusBarView.collapsePanel(/*animate=*/ false, false /* delayed*/, 2853 1.0f /* speedUpFactor */); 2854 2855 mNotificationPanel.closeQs(); 2856 2857 mExpandedVisible = false; 2858 2859 visibilityChanged(false); 2860 2861 // Shrink the window to the size of the status bar only 2862 mStatusBarWindowManager.setPanelVisible(false); 2863 mStatusBarWindowManager.setForceStatusBarVisible(false); 2864 2865 // Close any "App info" popups that might have snuck on-screen 2866 dismissPopups(); 2867 2868 runPostCollapseRunnables(); 2869 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false); 2870 showBouncer(); 2871 disable(mDisabledUnmodified1, mDisabledUnmodified2, true /* animate */); 2872 2873 // Trimming will happen later if Keyguard is showing - doing it here might cause a jank in 2874 // the bouncer appear animation. 2875 if (!mStatusBarKeyguardViewManager.isShowing()) { 2876 WindowManagerGlobal.getInstance().trimMemory(ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN); 2877 } 2878 } 2879 interceptTouchEvent(MotionEvent event)2880 public boolean interceptTouchEvent(MotionEvent event) { 2881 if (DEBUG_GESTURES) { 2882 if (event.getActionMasked() != MotionEvent.ACTION_MOVE) { 2883 EventLog.writeEvent(EventLogTags.SYSUI_STATUSBAR_TOUCH, 2884 event.getActionMasked(), (int) event.getX(), (int) event.getY(), 2885 mDisabled1, mDisabled2); 2886 } 2887 2888 } 2889 2890 if (SPEW) { 2891 Log.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled1=" 2892 + mDisabled1 + " mDisabled2=" + mDisabled2 + " mTracking=" + mTracking); 2893 } else if (CHATTY) { 2894 if (event.getAction() != MotionEvent.ACTION_MOVE) { 2895 Log.d(TAG, String.format( 2896 "panel: %s at (%f, %f) mDisabled1=0x%08x mDisabled2=0x%08x", 2897 MotionEvent.actionToString(event.getAction()), 2898 event.getRawX(), event.getRawY(), mDisabled1, mDisabled2)); 2899 } 2900 } 2901 2902 if (DEBUG_GESTURES) { 2903 mGestureRec.add(event); 2904 } 2905 2906 if (mStatusBarWindowState == WINDOW_STATE_SHOWING) { 2907 final boolean upOrCancel = 2908 event.getAction() == MotionEvent.ACTION_UP || 2909 event.getAction() == MotionEvent.ACTION_CANCEL; 2910 if (upOrCancel && !mExpandedVisible) { 2911 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false); 2912 } else { 2913 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true); 2914 } 2915 } 2916 return false; 2917 } 2918 getGestureRecorder()2919 public GestureRecorder getGestureRecorder() { 2920 return mGestureRec; 2921 } 2922 setNavigationIconHints(int hints)2923 private void setNavigationIconHints(int hints) { 2924 if (hints == mNavigationIconHints) return; 2925 2926 mNavigationIconHints = hints; 2927 2928 if (mNavigationBarView != null) { 2929 mNavigationBarView.setNavigationIconHints(hints); 2930 } 2931 checkBarModes(); 2932 } 2933 2934 @Override // CommandQueue setWindowState(int window, int state)2935 public void setWindowState(int window, int state) { 2936 boolean showing = state == WINDOW_STATE_SHOWING; 2937 if (mStatusBarWindow != null 2938 && window == StatusBarManager.WINDOW_STATUS_BAR 2939 && mStatusBarWindowState != state) { 2940 mStatusBarWindowState = state; 2941 if (DEBUG_WINDOW_STATE) Log.d(TAG, "Status bar " + windowStateToString(state)); 2942 if (!showing && mState == StatusBarState.SHADE) { 2943 mStatusBarView.collapsePanel(false /* animate */, false /* delayed */, 2944 1.0f /* speedUpFactor */); 2945 } 2946 } 2947 if (mNavigationBarView != null 2948 && window == StatusBarManager.WINDOW_NAVIGATION_BAR 2949 && mNavigationBarWindowState != state) { 2950 mNavigationBarWindowState = state; 2951 if (DEBUG_WINDOW_STATE) Log.d(TAG, "Navigation bar " + windowStateToString(state)); 2952 } 2953 } 2954 2955 @Override // CommandQueue buzzBeepBlinked()2956 public void buzzBeepBlinked() { 2957 if (mDozeServiceHost != null) { 2958 mDozeServiceHost.fireBuzzBeepBlinked(); 2959 } 2960 } 2961 2962 @Override notificationLightOff()2963 public void notificationLightOff() { 2964 if (mDozeServiceHost != null) { 2965 mDozeServiceHost.fireNotificationLight(false); 2966 } 2967 } 2968 2969 @Override notificationLightPulse(int argb, int onMillis, int offMillis)2970 public void notificationLightPulse(int argb, int onMillis, int offMillis) { 2971 if (mDozeServiceHost != null) { 2972 mDozeServiceHost.fireNotificationLight(true); 2973 } 2974 } 2975 2976 @Override // CommandQueue setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds)2977 public void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis, 2978 int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) { 2979 final int oldVal = mSystemUiVisibility; 2980 final int newVal = (oldVal&~mask) | (vis&mask); 2981 final int diff = newVal ^ oldVal; 2982 if (DEBUG) Log.d(TAG, String.format( 2983 "setSystemUiVisibility vis=%s mask=%s oldVal=%s newVal=%s diff=%s", 2984 Integer.toHexString(vis), Integer.toHexString(mask), 2985 Integer.toHexString(oldVal), Integer.toHexString(newVal), 2986 Integer.toHexString(diff))); 2987 boolean sbModeChanged = false; 2988 if (diff != 0) { 2989 // we never set the recents bit via this method, so save the prior state to prevent 2990 // clobbering the bit below 2991 final boolean wasRecentsVisible = (mSystemUiVisibility & View.RECENT_APPS_VISIBLE) > 0; 2992 2993 mSystemUiVisibility = newVal; 2994 2995 // update low profile 2996 if ((diff & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0) { 2997 setAreThereNotifications(); 2998 } 2999 3000 // ready to unhide 3001 if ((vis & View.STATUS_BAR_UNHIDE) != 0) { 3002 mSystemUiVisibility &= ~View.STATUS_BAR_UNHIDE; 3003 mNoAnimationOnNextBarModeChange = true; 3004 } 3005 3006 // update status bar mode 3007 final int sbMode = computeBarMode(oldVal, newVal, mStatusBarView.getBarTransitions(), 3008 View.STATUS_BAR_TRANSIENT, View.STATUS_BAR_TRANSLUCENT, 3009 View.STATUS_BAR_TRANSPARENT); 3010 3011 // update navigation bar mode 3012 final int nbMode = mNavigationBarView == null ? -1 : computeBarMode( 3013 oldVal, newVal, mNavigationBarView.getBarTransitions(), 3014 View.NAVIGATION_BAR_TRANSIENT, View.NAVIGATION_BAR_TRANSLUCENT, 3015 View.NAVIGATION_BAR_TRANSPARENT); 3016 sbModeChanged = sbMode != -1; 3017 final boolean nbModeChanged = nbMode != -1; 3018 boolean checkBarModes = false; 3019 if (sbModeChanged && sbMode != mStatusBarMode) { 3020 mStatusBarMode = sbMode; 3021 checkBarModes = true; 3022 } 3023 if (nbModeChanged && nbMode != mNavigationBarMode) { 3024 mNavigationBarMode = nbMode; 3025 checkBarModes = true; 3026 } 3027 if (checkBarModes) { 3028 checkBarModes(); 3029 } 3030 if (sbModeChanged || nbModeChanged) { 3031 // update transient bar autohide 3032 if (mStatusBarMode == MODE_SEMI_TRANSPARENT || mNavigationBarMode == MODE_SEMI_TRANSPARENT) { 3033 scheduleAutohide(); 3034 } else { 3035 cancelAutohide(); 3036 } 3037 } 3038 3039 if ((vis & View.NAVIGATION_BAR_UNHIDE) != 0) { 3040 mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE; 3041 } 3042 3043 // restore the recents bit 3044 if (wasRecentsVisible) { 3045 mSystemUiVisibility |= View.RECENT_APPS_VISIBLE; 3046 } 3047 3048 // send updated sysui visibility to window manager 3049 notifyUiVisibilityChanged(mSystemUiVisibility); 3050 } 3051 3052 mLightStatusBarController.onSystemUiVisibilityChanged(fullscreenStackVis, dockedStackVis, 3053 mask, fullscreenStackBounds, dockedStackBounds, sbModeChanged, mStatusBarMode); 3054 } 3055 computeBarMode(int oldVis, int newVis, BarTransitions transitions, int transientFlag, int translucentFlag, int transparentFlag)3056 private int computeBarMode(int oldVis, int newVis, BarTransitions transitions, 3057 int transientFlag, int translucentFlag, int transparentFlag) { 3058 final int oldMode = barMode(oldVis, transientFlag, translucentFlag, transparentFlag); 3059 final int newMode = barMode(newVis, transientFlag, translucentFlag, transparentFlag); 3060 if (oldMode == newMode) { 3061 return -1; // no mode change 3062 } 3063 return newMode; 3064 } 3065 barMode(int vis, int transientFlag, int translucentFlag, int transparentFlag)3066 private int barMode(int vis, int transientFlag, int translucentFlag, int transparentFlag) { 3067 int lightsOutTransparent = View.SYSTEM_UI_FLAG_LOW_PROFILE | transparentFlag; 3068 return (vis & transientFlag) != 0 ? MODE_SEMI_TRANSPARENT 3069 : (vis & translucentFlag) != 0 ? MODE_TRANSLUCENT 3070 : (vis & lightsOutTransparent) == lightsOutTransparent ? MODE_LIGHTS_OUT_TRANSPARENT 3071 : (vis & transparentFlag) != 0 ? MODE_TRANSPARENT 3072 : (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0 ? MODE_LIGHTS_OUT 3073 : MODE_OPAQUE; 3074 } 3075 checkBarModes()3076 private void checkBarModes() { 3077 if (mDemoMode) return; 3078 checkBarMode(mStatusBarMode, mStatusBarWindowState, mStatusBarView.getBarTransitions(), 3079 mNoAnimationOnNextBarModeChange); 3080 if (mNavigationBarView != null) { 3081 checkBarMode(mNavigationBarMode, 3082 mNavigationBarWindowState, mNavigationBarView.getBarTransitions(), 3083 mNoAnimationOnNextBarModeChange); 3084 } 3085 mNoAnimationOnNextBarModeChange = false; 3086 } 3087 checkBarMode(int mode, int windowState, BarTransitions transitions, boolean noAnimation)3088 private void checkBarMode(int mode, int windowState, BarTransitions transitions, 3089 boolean noAnimation) { 3090 final boolean powerSave = mBatteryController.isPowerSave(); 3091 final boolean anim = !noAnimation && mDeviceInteractive 3092 && windowState != WINDOW_STATE_HIDDEN && !powerSave; 3093 if (powerSave && getBarState() == StatusBarState.SHADE) { 3094 mode = MODE_WARNING; 3095 } 3096 transitions.transitionTo(mode, anim); 3097 } 3098 finishBarAnimations()3099 private void finishBarAnimations() { 3100 mStatusBarView.getBarTransitions().finishAnimations(); 3101 if (mNavigationBarView != null) { 3102 mNavigationBarView.getBarTransitions().finishAnimations(); 3103 } 3104 } 3105 3106 private final Runnable mCheckBarModes = new Runnable() { 3107 @Override 3108 public void run() { 3109 checkBarModes(); 3110 } 3111 }; 3112 3113 @Override setInteracting(int barWindow, boolean interacting)3114 public void setInteracting(int barWindow, boolean interacting) { 3115 final boolean changing = ((mInteractingWindows & barWindow) != 0) != interacting; 3116 mInteractingWindows = interacting 3117 ? (mInteractingWindows | barWindow) 3118 : (mInteractingWindows & ~barWindow); 3119 if (mInteractingWindows != 0) { 3120 suspendAutohide(); 3121 } else { 3122 resumeSuspendedAutohide(); 3123 } 3124 // manually dismiss the volume panel when interacting with the nav bar 3125 if (changing && interacting && barWindow == StatusBarManager.WINDOW_NAVIGATION_BAR) { 3126 dismissVolumeDialog(); 3127 } 3128 checkBarModes(); 3129 } 3130 dismissVolumeDialog()3131 private void dismissVolumeDialog() { 3132 if (mVolumeComponent != null) { 3133 mVolumeComponent.dismissNow(); 3134 } 3135 } 3136 resumeSuspendedAutohide()3137 private void resumeSuspendedAutohide() { 3138 if (mAutohideSuspended) { 3139 scheduleAutohide(); 3140 mHandler.postDelayed(mCheckBarModes, 500); // longer than home -> launcher 3141 } 3142 } 3143 suspendAutohide()3144 private void suspendAutohide() { 3145 mHandler.removeCallbacks(mAutohide); 3146 mHandler.removeCallbacks(mCheckBarModes); 3147 mAutohideSuspended = (mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0; 3148 } 3149 cancelAutohide()3150 private void cancelAutohide() { 3151 mAutohideSuspended = false; 3152 mHandler.removeCallbacks(mAutohide); 3153 } 3154 scheduleAutohide()3155 private void scheduleAutohide() { 3156 cancelAutohide(); 3157 mHandler.postDelayed(mAutohide, AUTOHIDE_TIMEOUT_MS); 3158 } 3159 checkUserAutohide(View v, MotionEvent event)3160 private void checkUserAutohide(View v, MotionEvent event) { 3161 if ((mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0 // a transient bar is revealed 3162 && event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar 3163 && event.getX() == 0 && event.getY() == 0 // a touch outside both bars 3164 && !mRemoteInputController.isRemoteInputActive()) { // not due to typing in IME 3165 userAutohide(); 3166 } 3167 } 3168 userAutohide()3169 private void userAutohide() { 3170 cancelAutohide(); 3171 mHandler.postDelayed(mAutohide, 350); // longer than app gesture -> flag clear 3172 } 3173 areLightsOn()3174 private boolean areLightsOn() { 3175 return 0 == (mSystemUiVisibility & View.SYSTEM_UI_FLAG_LOW_PROFILE); 3176 } 3177 setLightsOn(boolean on)3178 public void setLightsOn(boolean on) { 3179 Log.v(TAG, "setLightsOn(" + on + ")"); 3180 if (on) { 3181 setSystemUiVisibility(0, 0, 0, View.SYSTEM_UI_FLAG_LOW_PROFILE, 3182 mLastFullscreenStackBounds, mLastDockedStackBounds); 3183 } else { 3184 setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE, 0, 0, 3185 View.SYSTEM_UI_FLAG_LOW_PROFILE, mLastFullscreenStackBounds, 3186 mLastDockedStackBounds); 3187 } 3188 } 3189 notifyUiVisibilityChanged(int vis)3190 private void notifyUiVisibilityChanged(int vis) { 3191 try { 3192 if (mLastDispatchedSystemUiVisibility != vis) { 3193 mWindowManagerService.statusBarVisibilityChanged(vis); 3194 mLastDispatchedSystemUiVisibility = vis; 3195 } 3196 } catch (RemoteException ex) { 3197 } 3198 } 3199 3200 @Override topAppWindowChanged(boolean showMenu)3201 public void topAppWindowChanged(boolean showMenu) { 3202 if (SPEW) { 3203 Log.d(TAG, (showMenu?"showing":"hiding") + " the MENU button"); 3204 } 3205 if (mNavigationBarView != null) { 3206 mNavigationBarView.setMenuVisibility(showMenu); 3207 } 3208 3209 // See above re: lights-out policy for legacy apps. 3210 if (showMenu) setLightsOn(true); 3211 } 3212 3213 @Override setImeWindowStatus(IBinder token, int vis, int backDisposition, boolean showImeSwitcher)3214 public void setImeWindowStatus(IBinder token, int vis, int backDisposition, 3215 boolean showImeSwitcher) { 3216 boolean imeShown = (vis & InputMethodService.IME_VISIBLE) != 0; 3217 int flags = mNavigationIconHints; 3218 if ((backDisposition == InputMethodService.BACK_DISPOSITION_WILL_DISMISS) || imeShown) { 3219 flags |= NAVIGATION_HINT_BACK_ALT; 3220 } else { 3221 flags &= ~NAVIGATION_HINT_BACK_ALT; 3222 } 3223 if (showImeSwitcher) { 3224 flags |= NAVIGATION_HINT_IME_SHOWN; 3225 } else { 3226 flags &= ~NAVIGATION_HINT_IME_SHOWN; 3227 } 3228 3229 setNavigationIconHints(flags); 3230 } 3231 viewInfo(View v)3232 public static String viewInfo(View v) { 3233 return "[(" + v.getLeft() + "," + v.getTop() + ")(" + v.getRight() + "," + v.getBottom() 3234 + ") " + v.getWidth() + "x" + v.getHeight() + "]"; 3235 } 3236 3237 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)3238 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 3239 synchronized (mQueueLock) { 3240 pw.println("Current Status Bar state:"); 3241 pw.println(" mExpandedVisible=" + mExpandedVisible 3242 + ", mTrackingPosition=" + mTrackingPosition); 3243 pw.println(" mTracking=" + mTracking); 3244 pw.println(" mDisplayMetrics=" + mDisplayMetrics); 3245 pw.println(" mStackScroller: " + viewInfo(mStackScroller)); 3246 pw.println(" mStackScroller: " + viewInfo(mStackScroller) 3247 + " scroll " + mStackScroller.getScrollX() 3248 + "," + mStackScroller.getScrollY()); 3249 } 3250 3251 pw.print(" mInteractingWindows="); pw.println(mInteractingWindows); 3252 pw.print(" mStatusBarWindowState="); 3253 pw.println(windowStateToString(mStatusBarWindowState)); 3254 pw.print(" mStatusBarMode="); 3255 pw.println(BarTransitions.modeToString(mStatusBarMode)); 3256 pw.print(" mDozing="); pw.println(mDozing); 3257 pw.print(" mZenMode="); 3258 pw.println(Settings.Global.zenModeToString(mZenMode)); 3259 pw.print(" mUseHeadsUp="); 3260 pw.println(mUseHeadsUp); 3261 dumpBarTransitions(pw, "mStatusBarView", mStatusBarView.getBarTransitions()); 3262 if (mNavigationBarView != null) { 3263 pw.print(" mNavigationBarWindowState="); 3264 pw.println(windowStateToString(mNavigationBarWindowState)); 3265 pw.print(" mNavigationBarMode="); 3266 pw.println(BarTransitions.modeToString(mNavigationBarMode)); 3267 dumpBarTransitions(pw, "mNavigationBarView", mNavigationBarView.getBarTransitions()); 3268 } 3269 3270 pw.print(" mNavigationBarView="); 3271 if (mNavigationBarView == null) { 3272 pw.println("null"); 3273 } else { 3274 mNavigationBarView.dump(fd, pw, args); 3275 } 3276 3277 pw.print(" mMediaSessionManager="); 3278 pw.println(mMediaSessionManager); 3279 pw.print(" mMediaNotificationKey="); 3280 pw.println(mMediaNotificationKey); 3281 pw.print(" mMediaController="); 3282 pw.print(mMediaController); 3283 if (mMediaController != null) { 3284 pw.print(" state=" + mMediaController.getPlaybackState()); 3285 } 3286 pw.println(); 3287 pw.print(" mMediaMetadata="); 3288 pw.print(mMediaMetadata); 3289 if (mMediaMetadata != null) { 3290 pw.print(" title=" + mMediaMetadata.getText(MediaMetadata.METADATA_KEY_TITLE)); 3291 } 3292 pw.println(); 3293 3294 pw.println(" Panels: "); 3295 if (mNotificationPanel != null) { 3296 pw.println(" mNotificationPanel=" + 3297 mNotificationPanel + " params=" + mNotificationPanel.getLayoutParams().debug("")); 3298 pw.print (" "); 3299 mNotificationPanel.dump(fd, pw, args); 3300 } 3301 3302 DozeLog.dump(pw); 3303 3304 if (DUMPTRUCK) { 3305 synchronized (mNotificationData) { 3306 mNotificationData.dump(pw, " "); 3307 } 3308 3309 mIconController.dump(pw); 3310 3311 if (false) { 3312 pw.println("see the logcat for a dump of the views we have created."); 3313 // must happen on ui thread 3314 mHandler.post(new Runnable() { 3315 @Override 3316 public void run() { 3317 mStatusBarView.getLocationOnScreen(mAbsPos); 3318 Log.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1] 3319 + ") " + mStatusBarView.getWidth() + "x" 3320 + getStatusBarHeight()); 3321 mStatusBarView.debug(); 3322 } 3323 }); 3324 } 3325 } 3326 3327 if (DEBUG_GESTURES) { 3328 pw.print(" status bar gestures: "); 3329 mGestureRec.dump(fd, pw, args); 3330 } 3331 if (mStatusBarWindowManager != null) { 3332 mStatusBarWindowManager.dump(fd, pw, args); 3333 } 3334 if (mNetworkController != null) { 3335 mNetworkController.dump(fd, pw, args); 3336 } 3337 if (mBluetoothController != null) { 3338 mBluetoothController.dump(fd, pw, args); 3339 } 3340 if (mHotspotController != null) { 3341 mHotspotController.dump(fd, pw, args); 3342 } 3343 if (mCastController != null) { 3344 mCastController.dump(fd, pw, args); 3345 } 3346 if (mUserSwitcherController != null) { 3347 mUserSwitcherController.dump(fd, pw, args); 3348 } 3349 if (mBatteryController != null) { 3350 mBatteryController.dump(fd, pw, args); 3351 } 3352 if (mNextAlarmController != null) { 3353 mNextAlarmController.dump(fd, pw, args); 3354 } 3355 if (mSecurityController != null) { 3356 mSecurityController.dump(fd, pw, args); 3357 } 3358 if (mHeadsUpManager != null) { 3359 mHeadsUpManager.dump(fd, pw, args); 3360 } else { 3361 pw.println(" mHeadsUpManager: null"); 3362 } 3363 if (mGroupManager != null) { 3364 mGroupManager.dump(fd, pw, args); 3365 } else { 3366 pw.println(" mGroupManager: null"); 3367 } 3368 if (KeyguardUpdateMonitor.getInstance(mContext) != null) { 3369 KeyguardUpdateMonitor.getInstance(mContext).dump(fd, pw, args); 3370 } 3371 3372 FalsingManager.getInstance(mContext).dump(pw); 3373 FalsingLog.dump(pw); 3374 3375 pw.println("SharedPreferences:"); 3376 for (Map.Entry<String, ?> entry : Prefs.getAll(mContext).entrySet()) { 3377 pw.print(" "); pw.print(entry.getKey()); pw.print("="); pw.println(entry.getValue()); 3378 } 3379 } 3380 dumpBarTransitions(PrintWriter pw, String var, BarTransitions transitions)3381 private static void dumpBarTransitions(PrintWriter pw, String var, BarTransitions transitions) { 3382 pw.print(" "); pw.print(var); pw.print(".BarTransitions.mMode="); 3383 pw.println(BarTransitions.modeToString(transitions.getMode())); 3384 } 3385 3386 @Override createAndAddWindows()3387 public void createAndAddWindows() { 3388 addStatusBarWindow(); 3389 } 3390 addStatusBarWindow()3391 private void addStatusBarWindow() { 3392 makeStatusBarView(); 3393 mStatusBarWindowManager = new StatusBarWindowManager(mContext); 3394 mRemoteInputController = new RemoteInputController(mStatusBarWindowManager, 3395 mHeadsUpManager); 3396 mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight()); 3397 } 3398 3399 // called by makeStatusbar and also by PhoneStatusBarView updateDisplaySize()3400 void updateDisplaySize() { 3401 mDisplay.getMetrics(mDisplayMetrics); 3402 mDisplay.getSize(mCurrentDisplaySize); 3403 if (DEBUG_GESTURES) { 3404 mGestureRec.tag("display", 3405 String.format("%dx%d", mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels)); 3406 } 3407 } 3408 getDisplayDensity()3409 float getDisplayDensity() { 3410 return mDisplayMetrics.density; 3411 } 3412 startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned, boolean dismissShade)3413 public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned, 3414 boolean dismissShade) { 3415 startActivityDismissingKeyguard(intent, onlyProvisioned, dismissShade, null /* callback */); 3416 } 3417 startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned, final boolean dismissShade, final Callback callback)3418 public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned, 3419 final boolean dismissShade, final Callback callback) { 3420 if (onlyProvisioned && !isDeviceProvisioned()) return; 3421 3422 final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity( 3423 mContext, intent, mCurrentUserId); 3424 final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing(); 3425 Runnable runnable = new Runnable() { 3426 @Override 3427 public void run() { 3428 mAssistManager.hideAssist(); 3429 intent.setFlags( 3430 Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); 3431 int result = ActivityManager.START_CANCELED; 3432 ActivityOptions options = new ActivityOptions(getActivityOptions()); 3433 if (intent == KeyguardBottomAreaView.INSECURE_CAMERA_INTENT) { 3434 // Normally an activity will set it's requested rotation 3435 // animation on its window. However when launching an activity 3436 // causes the orientation to change this is too late. In these cases 3437 // the default animation is used. This doesn't look good for 3438 // the camera (as it rotates the camera contents out of sync 3439 // with physical reality). So, we ask the WindowManager to 3440 // force the crossfade animation if an orientation change 3441 // happens to occur during the launch. 3442 options.setRotationAnimationHint( 3443 WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS); 3444 } 3445 try { 3446 result = ActivityManagerNative.getDefault().startActivityAsUser( 3447 null, mContext.getBasePackageName(), 3448 intent, 3449 intent.resolveTypeIfNeeded(mContext.getContentResolver()), 3450 null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, 3451 options.toBundle(), UserHandle.CURRENT.getIdentifier()); 3452 } catch (RemoteException e) { 3453 Log.w(TAG, "Unable to start activity", e); 3454 } 3455 overrideActivityPendingAppTransition( 3456 keyguardShowing && !afterKeyguardGone); 3457 if (callback != null) { 3458 callback.onActivityStarted(result); 3459 } 3460 } 3461 }; 3462 Runnable cancelRunnable = new Runnable() { 3463 @Override 3464 public void run() { 3465 if (callback != null) { 3466 callback.onActivityStarted(ActivityManager.START_CANCELED); 3467 } 3468 } 3469 }; 3470 executeRunnableDismissingKeyguard(runnable, cancelRunnable, dismissShade, 3471 afterKeyguardGone, true /* deferred */); 3472 } 3473 executeRunnableDismissingKeyguard(final Runnable runnable, final Runnable cancelAction, final boolean dismissShade, final boolean afterKeyguardGone, final boolean deferred)3474 public void executeRunnableDismissingKeyguard(final Runnable runnable, 3475 final Runnable cancelAction, 3476 final boolean dismissShade, 3477 final boolean afterKeyguardGone, 3478 final boolean deferred) { 3479 final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing(); 3480 dismissKeyguardThenExecute(new OnDismissAction() { 3481 @Override 3482 public boolean onDismiss() { 3483 AsyncTask.execute(new Runnable() { 3484 @Override 3485 public void run() { 3486 try { 3487 if (keyguardShowing && !afterKeyguardGone) { 3488 ActivityManagerNative.getDefault() 3489 .keyguardWaitingForActivityDrawn(); 3490 } 3491 if (runnable != null) { 3492 runnable.run(); 3493 } 3494 } catch (RemoteException e) { 3495 } 3496 } 3497 }); 3498 if (dismissShade) { 3499 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */, 3500 true /* delayed*/); 3501 } 3502 return deferred; 3503 } 3504 }, cancelAction, afterKeyguardGone); 3505 } 3506 3507 private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 3508 @Override 3509 public void onReceive(Context context, Intent intent) { 3510 if (DEBUG) Log.v(TAG, "onReceive: " + intent); 3511 String action = intent.getAction(); 3512 if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) { 3513 KeyboardShortcuts.dismiss(); 3514 if (mRemoteInputController != null) { 3515 mRemoteInputController.closeRemoteInputs(); 3516 } 3517 if (isCurrentProfile(getSendingUserId())) { 3518 int flags = CommandQueue.FLAG_EXCLUDE_NONE; 3519 String reason = intent.getStringExtra("reason"); 3520 if (reason != null && reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) { 3521 flags |= CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL; 3522 } 3523 animateCollapsePanels(flags); 3524 } 3525 } 3526 else if (Intent.ACTION_SCREEN_OFF.equals(action)) { 3527 notifyNavigationBarScreenOn(false); 3528 notifyHeadsUpScreenOff(); 3529 finishBarAnimations(); 3530 resetUserExpandedStates(); 3531 } 3532 else if (Intent.ACTION_SCREEN_ON.equals(action)) { 3533 notifyNavigationBarScreenOn(true); 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 resetUserExpandedStates()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 @Override dismissKeyguardThenExecute(OnDismissAction action, boolean afterKeyguardGone)3575 protected void dismissKeyguardThenExecute(OnDismissAction action, boolean afterKeyguardGone) { 3576 dismissKeyguardThenExecute(action, null /* cancelRunnable */, afterKeyguardGone); 3577 } 3578 dismissKeyguard()3579 public void dismissKeyguard() { 3580 mStatusBarKeyguardViewManager.dismiss(); 3581 } 3582 dismissKeyguardThenExecute(OnDismissAction action, Runnable cancelAction, boolean afterKeyguardGone)3583 private void dismissKeyguardThenExecute(OnDismissAction action, Runnable cancelAction, 3584 boolean afterKeyguardGone) { 3585 if (mStatusBarKeyguardViewManager.isShowing()) { 3586 mStatusBarKeyguardViewManager.dismissWithAction(action, cancelAction, 3587 afterKeyguardGone); 3588 } else { 3589 action.onDismiss(); 3590 } 3591 } 3592 3593 // SystemUIService notifies SystemBars of configuration changes, which then calls down here 3594 @Override onConfigurationChanged(Configuration newConfig)3595 protected void onConfigurationChanged(Configuration newConfig) { 3596 updateResources(); 3597 updateDisplaySize(); // populates mDisplayMetrics 3598 super.onConfigurationChanged(newConfig); // calls refreshLayout 3599 3600 if (DEBUG) { 3601 Log.v(TAG, "configuration changed: " + mContext.getResources().getConfiguration()); 3602 } 3603 3604 repositionNavigationBar(); 3605 updateRowStates(); 3606 mScreenPinningRequest.onConfigurationChanged(); 3607 mNetworkController.onConfigurationChanged(); 3608 } 3609 3610 @Override userSwitched(int newUserId)3611 public void userSwitched(int newUserId) { 3612 super.userSwitched(newUserId); 3613 if (MULTIUSER_DEBUG) mNotificationPanelDebugText.setText("USER " + newUserId); 3614 animateCollapsePanels(); 3615 updatePublicMode(); 3616 updateNotifications(); 3617 resetUserSetupObserver(); 3618 setControllerUsers(); 3619 clearCurrentMediaNotification(); 3620 mLockscreenWallpaper.setCurrentUser(newUserId); 3621 mScrimController.setCurrentUser(newUserId); 3622 updateMediaMetaData(true, false); 3623 } 3624 setControllerUsers()3625 private void setControllerUsers() { 3626 if (mZenModeController != null) { 3627 mZenModeController.setUserId(mCurrentUserId); 3628 } 3629 if (mSecurityController != null) { 3630 mSecurityController.onUserSwitched(mCurrentUserId); 3631 } 3632 } 3633 resetUserSetupObserver()3634 private void resetUserSetupObserver() { 3635 mContext.getContentResolver().unregisterContentObserver(mUserSetupObserver); 3636 mUserSetupObserver.onChange(false); 3637 mContext.getContentResolver().registerContentObserver( 3638 Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE), true, 3639 mUserSetupObserver, mCurrentUserId); 3640 } 3641 3642 /** 3643 * Reload some of our resources when the configuration changes. 3644 * 3645 * We don't reload everything when the configuration changes -- we probably 3646 * should, but getting that smooth is tough. Someday we'll fix that. In the 3647 * meantime, just update the things that we know change. 3648 */ updateResources()3649 void updateResources() { 3650 // Update the quick setting tiles 3651 if (mQSPanel != null) { 3652 mQSPanel.updateResources(); 3653 } 3654 3655 loadDimens(); 3656 3657 if (mNotificationPanel != null) { 3658 mNotificationPanel.updateResources(); 3659 } 3660 if (mBrightnessMirrorController != null) { 3661 mBrightnessMirrorController.updateResources(); 3662 } 3663 } 3664 loadDimens()3665 protected void loadDimens() { 3666 final Resources res = mContext.getResources(); 3667 3668 int oldBarHeight = mNaturalBarHeight; 3669 mNaturalBarHeight = res.getDimensionPixelSize( 3670 com.android.internal.R.dimen.status_bar_height); 3671 if (mStatusBarWindowManager != null && mNaturalBarHeight != oldBarHeight) { 3672 mStatusBarWindowManager.setBarHeight(mNaturalBarHeight); 3673 } 3674 mMaxAllowedKeyguardNotifications = res.getInteger( 3675 R.integer.keyguard_max_notification_count); 3676 3677 if (DEBUG) Log.v(TAG, "defineSlots"); 3678 } 3679 3680 // Visibility reporting 3681 3682 @Override handleVisibleToUserChanged(boolean visibleToUser)3683 protected void handleVisibleToUserChanged(boolean visibleToUser) { 3684 if (visibleToUser) { 3685 super.handleVisibleToUserChanged(visibleToUser); 3686 startNotificationLogging(); 3687 } else { 3688 stopNotificationLogging(); 3689 super.handleVisibleToUserChanged(visibleToUser); 3690 } 3691 } 3692 stopNotificationLogging()3693 private void stopNotificationLogging() { 3694 // Report all notifications as invisible and turn down the 3695 // reporter. 3696 if (!mCurrentlyVisibleNotifications.isEmpty()) { 3697 logNotificationVisibilityChanges(Collections.<NotificationVisibility>emptyList(), 3698 mCurrentlyVisibleNotifications); 3699 recycleAllVisibilityObjects(mCurrentlyVisibleNotifications); 3700 } 3701 mHandler.removeCallbacks(mVisibilityReporter); 3702 mStackScroller.setChildLocationsChangedListener(null); 3703 } 3704 startNotificationLogging()3705 private void startNotificationLogging() { 3706 mStackScroller.setChildLocationsChangedListener(mNotificationLocationsChangedListener); 3707 // Some transitions like mVisibleToUser=false -> mVisibleToUser=true don't 3708 // cause the scroller to emit child location events. Hence generate 3709 // one ourselves to guarantee that we're reporting visible 3710 // notifications. 3711 // (Note that in cases where the scroller does emit events, this 3712 // additional event doesn't break anything.) 3713 mNotificationLocationsChangedListener.onChildLocationsChanged(mStackScroller); 3714 } 3715 logNotificationVisibilityChanges( Collection<NotificationVisibility> newlyVisible, Collection<NotificationVisibility> noLongerVisible)3716 private void logNotificationVisibilityChanges( 3717 Collection<NotificationVisibility> newlyVisible, 3718 Collection<NotificationVisibility> noLongerVisible) { 3719 if (newlyVisible.isEmpty() && noLongerVisible.isEmpty()) { 3720 return; 3721 } 3722 NotificationVisibility[] newlyVisibleAr = 3723 newlyVisible.toArray(new NotificationVisibility[newlyVisible.size()]); 3724 NotificationVisibility[] noLongerVisibleAr = 3725 noLongerVisible.toArray(new NotificationVisibility[noLongerVisible.size()]); 3726 try { 3727 mBarService.onNotificationVisibilityChanged(newlyVisibleAr, noLongerVisibleAr); 3728 } catch (RemoteException e) { 3729 // Ignore. 3730 } 3731 3732 final int N = newlyVisible.size(); 3733 if (N > 0) { 3734 String[] newlyVisibleKeyAr = new String[N]; 3735 for (int i = 0; i < N; i++) { 3736 newlyVisibleKeyAr[i] = newlyVisibleAr[i].key; 3737 } 3738 3739 setNotificationsShown(newlyVisibleKeyAr); 3740 } 3741 } 3742 3743 // State logging 3744 logStateToEventlog()3745 private void logStateToEventlog() { 3746 boolean isShowing = mStatusBarKeyguardViewManager.isShowing(); 3747 boolean isOccluded = mStatusBarKeyguardViewManager.isOccluded(); 3748 boolean isBouncerShowing = mStatusBarKeyguardViewManager.isBouncerShowing(); 3749 boolean isSecure = mUnlockMethodCache.isMethodSecure(); 3750 boolean canSkipBouncer = mUnlockMethodCache.canSkipBouncer(); 3751 int stateFingerprint = getLoggingFingerprint(mState, 3752 isShowing, 3753 isOccluded, 3754 isBouncerShowing, 3755 isSecure, 3756 canSkipBouncer); 3757 if (stateFingerprint != mLastLoggedStateFingerprint) { 3758 EventLogTags.writeSysuiStatusBarState(mState, 3759 isShowing ? 1 : 0, 3760 isOccluded ? 1 : 0, 3761 isBouncerShowing ? 1 : 0, 3762 isSecure ? 1 : 0, 3763 canSkipBouncer ? 1 : 0); 3764 mLastLoggedStateFingerprint = stateFingerprint; 3765 } 3766 } 3767 3768 /** 3769 * Returns a fingerprint of fields logged to eventlog 3770 */ getLoggingFingerprint(int statusBarState, boolean keyguardShowing, boolean keyguardOccluded, boolean bouncerShowing, boolean secure, boolean currentlyInsecure)3771 private static int getLoggingFingerprint(int statusBarState, boolean keyguardShowing, 3772 boolean keyguardOccluded, boolean bouncerShowing, boolean secure, 3773 boolean currentlyInsecure) { 3774 // Reserve 8 bits for statusBarState. We'll never go higher than 3775 // that, right? Riiiight. 3776 return (statusBarState & 0xFF) 3777 | ((keyguardShowing ? 1 : 0) << 8) 3778 | ((keyguardOccluded ? 1 : 0) << 9) 3779 | ((bouncerShowing ? 1 : 0) << 10) 3780 | ((secure ? 1 : 0) << 11) 3781 | ((currentlyInsecure ? 1 : 0) << 12); 3782 } 3783 3784 // 3785 // tracing 3786 // 3787 postStartTracing()3788 void postStartTracing() { 3789 mHandler.postDelayed(mStartTracing, 3000); 3790 } 3791 vibrate()3792 void vibrate() { 3793 android.os.Vibrator vib = (android.os.Vibrator)mContext.getSystemService( 3794 Context.VIBRATOR_SERVICE); 3795 vib.vibrate(250, VIBRATION_ATTRIBUTES); 3796 } 3797 3798 Runnable mStartTracing = new Runnable() { 3799 @Override 3800 public void run() { 3801 vibrate(); 3802 SystemClock.sleep(250); 3803 Log.d(TAG, "startTracing"); 3804 android.os.Debug.startMethodTracing("/data/statusbar-traces/trace"); 3805 mHandler.postDelayed(mStopTracing, 10000); 3806 } 3807 }; 3808 3809 Runnable mStopTracing = new Runnable() { 3810 @Override 3811 public void run() { 3812 android.os.Debug.stopMethodTracing(); 3813 Log.d(TAG, "stopTracing"); 3814 vibrate(); 3815 } 3816 }; 3817 3818 @Override shouldDisableNavbarGestures()3819 public boolean shouldDisableNavbarGestures() { 3820 return !isDeviceProvisioned() || (mDisabled1 & StatusBarManager.DISABLE_SEARCH) != 0; 3821 } 3822 postQSRunnableDismissingKeyguard(final Runnable runnable)3823 public void postQSRunnableDismissingKeyguard(final Runnable runnable) { 3824 mHandler.post(new Runnable() { 3825 @Override 3826 public void run() { 3827 mLeaveOpenOnKeyguardHide = true; 3828 executeRunnableDismissingKeyguard(runnable, null, false, false, false); 3829 } 3830 }); 3831 } 3832 postStartActivityDismissingKeyguard(final PendingIntent intent)3833 public void postStartActivityDismissingKeyguard(final PendingIntent intent) { 3834 mHandler.post(new Runnable() { 3835 @Override 3836 public void run() { 3837 startPendingIntentDismissingKeyguard(intent); 3838 } 3839 }); 3840 } 3841 postStartActivityDismissingKeyguard(final Intent intent, int delay)3842 public void postStartActivityDismissingKeyguard(final Intent intent, int delay) { 3843 mHandler.postDelayed(new Runnable() { 3844 @Override 3845 public void run() { 3846 handleStartActivityDismissingKeyguard(intent, true /*onlyProvisioned*/); 3847 } 3848 }, delay); 3849 } 3850 handleStartActivityDismissingKeyguard(Intent intent, boolean onlyProvisioned)3851 private void handleStartActivityDismissingKeyguard(Intent intent, boolean onlyProvisioned) { 3852 startActivityDismissingKeyguard(intent, onlyProvisioned, true /* dismissShade */); 3853 } 3854 3855 private static class FastColorDrawable extends Drawable { 3856 private final int mColor; 3857 FastColorDrawable(int color)3858 public FastColorDrawable(int color) { 3859 mColor = 0xff000000 | color; 3860 } 3861 3862 @Override draw(Canvas canvas)3863 public void draw(Canvas canvas) { 3864 canvas.drawColor(mColor, PorterDuff.Mode.SRC); 3865 } 3866 3867 @Override setAlpha(int alpha)3868 public void setAlpha(int alpha) { 3869 } 3870 3871 @Override setColorFilter(ColorFilter colorFilter)3872 public void setColorFilter(ColorFilter colorFilter) { 3873 } 3874 3875 @Override getOpacity()3876 public int getOpacity() { 3877 return PixelFormat.OPAQUE; 3878 } 3879 3880 @Override setBounds(int left, int top, int right, int bottom)3881 public void setBounds(int left, int top, int right, int bottom) { 3882 } 3883 3884 @Override setBounds(Rect bounds)3885 public void setBounds(Rect bounds) { 3886 } 3887 } 3888 3889 @Override destroy()3890 public void destroy() { 3891 super.destroy(); 3892 if (mStatusBarWindow != null) { 3893 mWindowManager.removeViewImmediate(mStatusBarWindow); 3894 mStatusBarWindow = null; 3895 } 3896 if (mNavigationBarView != null) { 3897 mWindowManager.removeViewImmediate(mNavigationBarView); 3898 mNavigationBarView = null; 3899 } 3900 if (mHandlerThread != null) { 3901 mHandlerThread.quitSafely(); 3902 mHandlerThread = null; 3903 } 3904 mContext.unregisterReceiver(mBroadcastReceiver); 3905 mContext.unregisterReceiver(mDemoReceiver); 3906 mAssistManager.destroy(); 3907 3908 final SignalClusterView signalCluster = 3909 (SignalClusterView) mStatusBarView.findViewById(R.id.signal_cluster); 3910 final SignalClusterView signalClusterKeyguard = 3911 (SignalClusterView) mKeyguardStatusBar.findViewById(R.id.signal_cluster); 3912 final SignalClusterView signalClusterQs = 3913 (SignalClusterView) mHeader.findViewById(R.id.signal_cluster); 3914 mNetworkController.removeSignalCallback(signalCluster); 3915 mNetworkController.removeSignalCallback(signalClusterKeyguard); 3916 mNetworkController.removeSignalCallback(signalClusterQs); 3917 if (mQSPanel != null && mQSPanel.getHost() != null) { 3918 mQSPanel.getHost().destroy(); 3919 } 3920 } 3921 3922 private boolean mDemoModeAllowed; 3923 private boolean mDemoMode; 3924 3925 @Override dispatchDemoCommand(String command, Bundle args)3926 public void dispatchDemoCommand(String command, Bundle args) { 3927 if (!mDemoModeAllowed) { 3928 mDemoModeAllowed = Settings.Global.getInt(mContext.getContentResolver(), 3929 DEMO_MODE_ALLOWED, 0) != 0; 3930 } 3931 if (!mDemoModeAllowed) return; 3932 if (command.equals(COMMAND_ENTER)) { 3933 mDemoMode = true; 3934 } else if (command.equals(COMMAND_EXIT)) { 3935 mDemoMode = false; 3936 checkBarModes(); 3937 } else if (!mDemoMode) { 3938 // automatically enter demo mode on first demo command 3939 dispatchDemoCommand(COMMAND_ENTER, new Bundle()); 3940 } 3941 boolean modeChange = command.equals(COMMAND_ENTER) || command.equals(COMMAND_EXIT); 3942 if ((modeChange || command.equals(COMMAND_VOLUME)) && mVolumeComponent != null) { 3943 mVolumeComponent.dispatchDemoCommand(command, args); 3944 } 3945 if (modeChange || command.equals(COMMAND_CLOCK)) { 3946 dispatchDemoCommandToView(command, args, R.id.clock); 3947 } 3948 if (modeChange || command.equals(COMMAND_BATTERY)) { 3949 mBatteryController.dispatchDemoCommand(command, args); 3950 } 3951 if (modeChange || command.equals(COMMAND_STATUS)) { 3952 mIconController.dispatchDemoCommand(command, args); 3953 } 3954 if (mNetworkController != null && (modeChange || command.equals(COMMAND_NETWORK))) { 3955 mNetworkController.dispatchDemoCommand(command, args); 3956 } 3957 if (modeChange || command.equals(COMMAND_NOTIFICATIONS)) { 3958 View notifications = mStatusBarView == null ? null 3959 : mStatusBarView.findViewById(R.id.notification_icon_area); 3960 if (notifications != null) { 3961 String visible = args.getString("visible"); 3962 int vis = mDemoMode && "false".equals(visible) ? View.INVISIBLE : View.VISIBLE; 3963 notifications.setVisibility(vis); 3964 } 3965 } 3966 if (command.equals(COMMAND_BARS)) { 3967 String mode = args.getString("mode"); 3968 int barMode = "opaque".equals(mode) ? MODE_OPAQUE : 3969 "translucent".equals(mode) ? MODE_TRANSLUCENT : 3970 "semi-transparent".equals(mode) ? MODE_SEMI_TRANSPARENT : 3971 "transparent".equals(mode) ? MODE_TRANSPARENT : 3972 "warning".equals(mode) ? MODE_WARNING : 3973 -1; 3974 if (barMode != -1) { 3975 boolean animate = true; 3976 if (mStatusBarView != null) { 3977 mStatusBarView.getBarTransitions().transitionTo(barMode, animate); 3978 } 3979 if (mNavigationBarView != null) { 3980 mNavigationBarView.getBarTransitions().transitionTo(barMode, animate); 3981 } 3982 } 3983 } 3984 } 3985 dispatchDemoCommandToView(String command, Bundle args, int id)3986 private void dispatchDemoCommandToView(String command, Bundle args, int id) { 3987 if (mStatusBarView == null) return; 3988 View v = mStatusBarView.findViewById(id); 3989 if (v instanceof DemoMode) { 3990 ((DemoMode)v).dispatchDemoCommand(command, args); 3991 } 3992 } 3993 3994 /** 3995 * @return The {@link StatusBarState} the status bar is in. 3996 */ getBarState()3997 public int getBarState() { 3998 return mState; 3999 } 4000 4001 @Override isPanelFullyCollapsed()4002 public boolean isPanelFullyCollapsed() { 4003 return mNotificationPanel.isFullyCollapsed(); 4004 } 4005 showKeyguard()4006 public void showKeyguard() { 4007 if (mLaunchTransitionFadingAway) { 4008 mNotificationPanel.animate().cancel(); 4009 onLaunchTransitionFadingEnded(); 4010 } 4011 mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT); 4012 if (mUserSwitcherController != null && mUserSwitcherController.useFullscreenUserSwitcher()) { 4013 setBarState(StatusBarState.FULLSCREEN_USER_SWITCHER); 4014 } else { 4015 setBarState(StatusBarState.KEYGUARD); 4016 } 4017 updateKeyguardState(false /* goingToFullShade */, false /* fromShadeLocked */); 4018 if (!mDeviceInteractive) { 4019 4020 // If the screen is off already, we need to disable touch events because these might 4021 // collapse the panel after we expanded it, and thus we would end up with a blank 4022 // Keyguard. 4023 mNotificationPanel.setTouchDisabled(true); 4024 } 4025 if (mState == StatusBarState.KEYGUARD) { 4026 instantExpandNotificationsPanel(); 4027 } else if (mState == StatusBarState.FULLSCREEN_USER_SWITCHER) { 4028 instantCollapseNotificationPanel(); 4029 } 4030 mLeaveOpenOnKeyguardHide = false; 4031 if (mDraggedDownRow != null) { 4032 mDraggedDownRow.setUserLocked(false); 4033 mDraggedDownRow.notifyHeightChanged(false /* needsAnimation */); 4034 mDraggedDownRow = null; 4035 } 4036 mPendingRemoteInputView = null; 4037 mAssistManager.onLockscreenShown(); 4038 } 4039 onLaunchTransitionFadingEnded()4040 private void onLaunchTransitionFadingEnded() { 4041 mNotificationPanel.setAlpha(1.0f); 4042 mNotificationPanel.onAffordanceLaunchEnded(); 4043 releaseGestureWakeLock(); 4044 runLaunchTransitionEndRunnable(); 4045 mLaunchTransitionFadingAway = false; 4046 mScrimController.forceHideScrims(false /* hide */); 4047 updateMediaMetaData(true /* metaDataChanged */, true); 4048 } 4049 4050 @Override isCollapsing()4051 public boolean isCollapsing() { 4052 return mNotificationPanel.isCollapsing(); 4053 } 4054 4055 @Override addPostCollapseAction(Runnable r)4056 public void addPostCollapseAction(Runnable r) { 4057 mPostCollapseRunnables.add(r); 4058 } 4059 isInLaunchTransition()4060 public boolean isInLaunchTransition() { 4061 return mNotificationPanel.isLaunchTransitionRunning() 4062 || mNotificationPanel.isLaunchTransitionFinished(); 4063 } 4064 4065 /** 4066 * Fades the content of the keyguard away after the launch transition is done. 4067 * 4068 * @param beforeFading the runnable to be run when the circle is fully expanded and the fading 4069 * starts 4070 * @param endRunnable the runnable to be run when the transition is done 4071 */ fadeKeyguardAfterLaunchTransition(final Runnable beforeFading, Runnable endRunnable)4072 public void fadeKeyguardAfterLaunchTransition(final Runnable beforeFading, 4073 Runnable endRunnable) { 4074 mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT); 4075 mLaunchTransitionEndRunnable = endRunnable; 4076 Runnable hideRunnable = new Runnable() { 4077 @Override 4078 public void run() { 4079 mLaunchTransitionFadingAway = true; 4080 if (beforeFading != null) { 4081 beforeFading.run(); 4082 } 4083 mScrimController.forceHideScrims(true /* hide */); 4084 updateMediaMetaData(false, true); 4085 mNotificationPanel.setAlpha(1); 4086 mStackScroller.setParentFadingOut(true); 4087 mNotificationPanel.animate() 4088 .alpha(0) 4089 .setStartDelay(FADE_KEYGUARD_START_DELAY) 4090 .setDuration(FADE_KEYGUARD_DURATION) 4091 .withLayer() 4092 .withEndAction(new Runnable() { 4093 @Override 4094 public void run() { 4095 onLaunchTransitionFadingEnded(); 4096 } 4097 }); 4098 mIconController.appTransitionStarting(SystemClock.uptimeMillis(), 4099 StatusBarIconController.DEFAULT_TINT_ANIMATION_DURATION); 4100 } 4101 }; 4102 if (mNotificationPanel.isLaunchTransitionRunning()) { 4103 mNotificationPanel.setLaunchTransitionEndRunnable(hideRunnable); 4104 } else { 4105 hideRunnable.run(); 4106 } 4107 } 4108 4109 /** 4110 * Fades the content of the Keyguard while we are dozing and makes it invisible when finished 4111 * fading. 4112 */ fadeKeyguardWhilePulsing()4113 public void fadeKeyguardWhilePulsing() { 4114 mNotificationPanel.animate() 4115 .alpha(0f) 4116 .setStartDelay(0) 4117 .setDuration(FADE_KEYGUARD_DURATION_PULSING) 4118 .setInterpolator(ScrimController.KEYGUARD_FADE_OUT_INTERPOLATOR) 4119 .start(); 4120 } 4121 4122 /** 4123 * Starts the timeout when we try to start the affordances on Keyguard. We usually rely that 4124 * Keyguard goes away via fadeKeyguardAfterLaunchTransition, however, that might not happen 4125 * because the launched app crashed or something else went wrong. 4126 */ startLaunchTransitionTimeout()4127 public void startLaunchTransitionTimeout() { 4128 mHandler.sendEmptyMessageDelayed(MSG_LAUNCH_TRANSITION_TIMEOUT, 4129 LAUNCH_TRANSITION_TIMEOUT_MS); 4130 } 4131 onLaunchTransitionTimeout()4132 private void onLaunchTransitionTimeout() { 4133 Log.w(TAG, "Launch transition: Timeout!"); 4134 mNotificationPanel.onAffordanceLaunchEnded(); 4135 releaseGestureWakeLock(); 4136 mNotificationPanel.resetViews(); 4137 } 4138 runLaunchTransitionEndRunnable()4139 private void runLaunchTransitionEndRunnable() { 4140 if (mLaunchTransitionEndRunnable != null) { 4141 Runnable r = mLaunchTransitionEndRunnable; 4142 4143 // mLaunchTransitionEndRunnable might call showKeyguard, which would execute it again, 4144 // which would lead to infinite recursion. Protect against it. 4145 mLaunchTransitionEndRunnable = null; 4146 r.run(); 4147 } 4148 } 4149 4150 /** 4151 * @return true if we would like to stay in the shade, false if it should go away entirely 4152 */ hideKeyguard()4153 public boolean hideKeyguard() { 4154 Trace.beginSection("PhoneStatusBar#hideKeyguard"); 4155 boolean staying = mLeaveOpenOnKeyguardHide; 4156 setBarState(StatusBarState.SHADE); 4157 View viewToClick = null; 4158 if (mLeaveOpenOnKeyguardHide) { 4159 mLeaveOpenOnKeyguardHide = false; 4160 long delay = calculateGoingToFullShadeDelay(); 4161 mNotificationPanel.animateToFullShade(delay); 4162 if (mDraggedDownRow != null) { 4163 mDraggedDownRow.setUserLocked(false); 4164 mDraggedDownRow = null; 4165 } 4166 viewToClick = mPendingRemoteInputView; 4167 mPendingRemoteInputView = null; 4168 4169 // Disable layout transitions in navbar for this transition because the load is just 4170 // too heavy for the CPU and GPU on any device. 4171 if (mNavigationBarView != null) { 4172 mNavigationBarView.setLayoutTransitionsEnabled(false); 4173 mNavigationBarView.postDelayed(new Runnable() { 4174 @Override 4175 public void run() { 4176 mNavigationBarView.setLayoutTransitionsEnabled(true); 4177 } 4178 }, delay + StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE); 4179 } 4180 } else { 4181 instantCollapseNotificationPanel(); 4182 } 4183 updateKeyguardState(staying, false /* fromShadeLocked */); 4184 4185 if (viewToClick != null) { 4186 viewToClick.callOnClick(); 4187 } 4188 4189 // Keyguard state has changed, but QS is not listening anymore. Make sure to update the tile 4190 // visibilities so next time we open the panel we know the correct height already. 4191 if (mQSPanel != null) { 4192 mQSPanel.refreshAllTiles(); 4193 } 4194 mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT); 4195 releaseGestureWakeLock(); 4196 mNotificationPanel.onAffordanceLaunchEnded(); 4197 mNotificationPanel.animate().cancel(); 4198 mNotificationPanel.setAlpha(1f); 4199 Trace.endSection(); 4200 return staying; 4201 } 4202 releaseGestureWakeLock()4203 private void releaseGestureWakeLock() { 4204 if (mGestureWakeLock.isHeld()) { 4205 mGestureWakeLock.release(); 4206 } 4207 } 4208 calculateGoingToFullShadeDelay()4209 public long calculateGoingToFullShadeDelay() { 4210 return mKeyguardFadingAwayDelay + mKeyguardFadingAwayDuration; 4211 } 4212 4213 /** 4214 * Notifies the status bar that Keyguard is going away very soon. 4215 */ keyguardGoingAway()4216 public void keyguardGoingAway() { 4217 4218 // Treat Keyguard exit animation as an app transition to achieve nice transition for status 4219 // bar. 4220 mKeyguardGoingAway = true; 4221 mIconController.appTransitionPending(); 4222 } 4223 4224 /** 4225 * Notifies the status bar the Keyguard is fading away with the specified timings. 4226 * 4227 * @param startTime the start time of the animations in uptime millis 4228 * @param delay the precalculated animation delay in miliseconds 4229 * @param fadeoutDuration the duration of the exit animation, in milliseconds 4230 */ setKeyguardFadingAway(long startTime, long delay, long fadeoutDuration)4231 public void setKeyguardFadingAway(long startTime, long delay, long fadeoutDuration) { 4232 mKeyguardFadingAway = true; 4233 mKeyguardFadingAwayDelay = delay; 4234 mKeyguardFadingAwayDuration = fadeoutDuration; 4235 mWaitingForKeyguardExit = false; 4236 mIconController.appTransitionStarting( 4237 startTime + fadeoutDuration 4238 - StatusBarIconController.DEFAULT_TINT_ANIMATION_DURATION, 4239 StatusBarIconController.DEFAULT_TINT_ANIMATION_DURATION); 4240 disable(mDisabledUnmodified1, mDisabledUnmodified2, fadeoutDuration > 0 /* animate */); 4241 } 4242 isKeyguardFadingAway()4243 public boolean isKeyguardFadingAway() { 4244 return mKeyguardFadingAway; 4245 } 4246 4247 /** 4248 * Notifies that the Keyguard fading away animation is done. 4249 */ finishKeyguardFadingAway()4250 public void finishKeyguardFadingAway() { 4251 mKeyguardFadingAway = false; 4252 mKeyguardGoingAway = false; 4253 } 4254 stopWaitingForKeyguardExit()4255 public void stopWaitingForKeyguardExit() { 4256 mWaitingForKeyguardExit = false; 4257 } 4258 updatePublicMode()4259 private void updatePublicMode() { 4260 boolean isPublic = false; 4261 if (mStatusBarKeyguardViewManager.isShowing()) { 4262 for (int i = mCurrentProfiles.size() - 1; i >= 0; i--) { 4263 UserInfo userInfo = mCurrentProfiles.valueAt(i); 4264 if (mStatusBarKeyguardViewManager.isSecure(userInfo.id)) { 4265 isPublic = true; 4266 break; 4267 } 4268 } 4269 } 4270 setLockscreenPublicMode(isPublic); 4271 } 4272 updateKeyguardState(boolean goingToFullShade, boolean fromShadeLocked)4273 protected void updateKeyguardState(boolean goingToFullShade, boolean fromShadeLocked) { 4274 Trace.beginSection("PhoneStatusBar#updateKeyguardState"); 4275 if (mState == StatusBarState.KEYGUARD) { 4276 mKeyguardIndicationController.setVisible(true); 4277 mNotificationPanel.resetViews(); 4278 if (mKeyguardUserSwitcher != null) { 4279 mKeyguardUserSwitcher.setKeyguard(true, fromShadeLocked); 4280 } 4281 mStatusBarView.removePendingHideExpandedRunnables(); 4282 } else { 4283 mKeyguardIndicationController.setVisible(false); 4284 if (mKeyguardUserSwitcher != null) { 4285 mKeyguardUserSwitcher.setKeyguard(false, 4286 goingToFullShade || 4287 mState == StatusBarState.SHADE_LOCKED || 4288 fromShadeLocked); 4289 } 4290 } 4291 if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) { 4292 mScrimController.setKeyguardShowing(true); 4293 } else { 4294 mScrimController.setKeyguardShowing(false); 4295 } 4296 mIconPolicy.notifyKeyguardShowingChanged(); 4297 mNotificationPanel.setBarState(mState, mKeyguardFadingAway, goingToFullShade); 4298 updateDozingState(); 4299 updatePublicMode(); 4300 updateStackScrollerState(goingToFullShade, fromShadeLocked); 4301 updateNotifications(); 4302 checkBarModes(); 4303 updateMediaMetaData(false, mState != StatusBarState.KEYGUARD); 4304 mKeyguardMonitor.notifyKeyguardState(mStatusBarKeyguardViewManager.isShowing(), 4305 mStatusBarKeyguardViewManager.isSecure()); 4306 Trace.endSection(); 4307 } 4308 updateDozingState()4309 private void updateDozingState() { 4310 Trace.beginSection("PhoneStatusBar#updateDozingState"); 4311 boolean animate = !mDozing && mDozeScrimController.isPulsing(); 4312 mNotificationPanel.setDozing(mDozing, animate); 4313 mStackScroller.setDark(mDozing, animate, mWakeUpTouchLocation); 4314 mScrimController.setDozing(mDozing); 4315 4316 // Immediately abort the dozing from the doze scrim controller in case of wake-and-unlock 4317 // for pulsing so the Keyguard fade-out animation scrim can take over. 4318 mDozeScrimController.setDozing(mDozing && 4319 mFingerprintUnlockController.getMode() 4320 != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING, animate); 4321 Trace.endSection(); 4322 } 4323 updateStackScrollerState(boolean goingToFullShade, boolean fromShadeLocked)4324 public void updateStackScrollerState(boolean goingToFullShade, boolean fromShadeLocked) { 4325 if (mStackScroller == null) return; 4326 boolean onKeyguard = mState == StatusBarState.KEYGUARD; 4327 mStackScroller.setHideSensitive(isLockscreenPublicMode(), goingToFullShade); 4328 mStackScroller.setDimmed(onKeyguard, fromShadeLocked /* animate */); 4329 mStackScroller.setExpandingEnabled(!onKeyguard); 4330 ActivatableNotificationView activatedChild = mStackScroller.getActivatedChild(); 4331 mStackScroller.setActivatedChild(null); 4332 if (activatedChild != null) { 4333 activatedChild.makeInactive(false /* animate */); 4334 } 4335 } 4336 userActivity()4337 public void userActivity() { 4338 if (mState == StatusBarState.KEYGUARD) { 4339 mKeyguardViewMediatorCallback.userActivity(); 4340 } 4341 } 4342 interceptMediaKey(KeyEvent event)4343 public boolean interceptMediaKey(KeyEvent event) { 4344 return mState == StatusBarState.KEYGUARD 4345 && mStatusBarKeyguardViewManager.interceptMediaKey(event); 4346 } 4347 onMenuPressed()4348 public boolean onMenuPressed() { 4349 if (mDeviceInteractive && mState != StatusBarState.SHADE 4350 && mStatusBarKeyguardViewManager.shouldDismissOnMenuPressed()) { 4351 animateCollapsePanels( 4352 CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL /* flags */, true /* force */); 4353 return true; 4354 } 4355 return false; 4356 } 4357 endAffordanceLaunch()4358 public void endAffordanceLaunch() { 4359 releaseGestureWakeLock(); 4360 mNotificationPanel.onAffordanceLaunchEnded(); 4361 } 4362 onBackPressed()4363 public boolean onBackPressed() { 4364 if (mStatusBarKeyguardViewManager.onBackPressed()) { 4365 return true; 4366 } 4367 if (mNotificationPanel.isQsExpanded()) { 4368 if (mNotificationPanel.isQsDetailShowing()) { 4369 mNotificationPanel.closeQsDetail(); 4370 } else { 4371 mNotificationPanel.animateCloseQs(); 4372 } 4373 return true; 4374 } 4375 if (mState != StatusBarState.KEYGUARD && mState != StatusBarState.SHADE_LOCKED) { 4376 animateCollapsePanels(); 4377 return true; 4378 } 4379 return false; 4380 } 4381 onSpacePressed()4382 public boolean onSpacePressed() { 4383 if (mDeviceInteractive && mState != StatusBarState.SHADE) { 4384 animateCollapsePanels( 4385 CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL /* flags */, true /* force */); 4386 return true; 4387 } 4388 return false; 4389 } 4390 showBouncer()4391 private void showBouncer() { 4392 if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) { 4393 mWaitingForKeyguardExit = mStatusBarKeyguardViewManager.isShowing(); 4394 mStatusBarKeyguardViewManager.dismiss(); 4395 } 4396 } 4397 instantExpandNotificationsPanel()4398 private void instantExpandNotificationsPanel() { 4399 4400 // Make our window larger and the panel expanded. 4401 makeExpandedVisible(true); 4402 mNotificationPanel.expand(false /* animate */); 4403 } 4404 instantCollapseNotificationPanel()4405 private void instantCollapseNotificationPanel() { 4406 mNotificationPanel.instantCollapse(); 4407 } 4408 4409 @Override onActivated(ActivatableNotificationView view)4410 public void onActivated(ActivatableNotificationView view) { 4411 EventLogTags.writeSysuiLockscreenGesture( 4412 EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_TAP_NOTIFICATION_ACTIVATE, 4413 0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */); 4414 mKeyguardIndicationController.showTransientIndication(R.string.notification_tap_again); 4415 ActivatableNotificationView previousView = mStackScroller.getActivatedChild(); 4416 if (previousView != null) { 4417 previousView.makeInactive(true /* animate */); 4418 } 4419 mStackScroller.setActivatedChild(view); 4420 } 4421 getHomeButton()4422 public ButtonDispatcher getHomeButton() { 4423 return mNavigationBarView.getHomeButton(); 4424 } 4425 4426 /** 4427 * @param state The {@link StatusBarState} to set. 4428 */ setBarState(int state)4429 public void setBarState(int state) { 4430 // If we're visible and switched to SHADE_LOCKED (the user dragged 4431 // down on the lockscreen), clear notification LED, vibration, 4432 // ringing. 4433 // Other transitions are covered in handleVisibleToUserChanged(). 4434 if (state != mState && mVisible && (state == StatusBarState.SHADE_LOCKED 4435 || (state == StatusBarState.SHADE && isGoingToNotificationShade()))) { 4436 clearNotificationEffects(); 4437 } 4438 if (state == StatusBarState.KEYGUARD) { 4439 removeRemoteInputEntriesKeptUntilCollapsed(); 4440 } 4441 mState = state; 4442 mGroupManager.setStatusBarState(state); 4443 mFalsingManager.setStatusBarState(state); 4444 mStatusBarWindowManager.setStatusBarState(state); 4445 updateReportRejectedTouchVisibility(); 4446 updateDozing(); 4447 } 4448 4449 @Override onActivationReset(ActivatableNotificationView view)4450 public void onActivationReset(ActivatableNotificationView view) { 4451 if (view == mStackScroller.getActivatedChild()) { 4452 mKeyguardIndicationController.hideTransientIndication(); 4453 mStackScroller.setActivatedChild(null); 4454 } 4455 } 4456 onTrackingStarted()4457 public void onTrackingStarted() { 4458 runPostCollapseRunnables(); 4459 } 4460 onClosingFinished()4461 public void onClosingFinished() { 4462 runPostCollapseRunnables(); 4463 } 4464 onUnlockHintStarted()4465 public void onUnlockHintStarted() { 4466 mFalsingManager.onUnlockHintStarted(); 4467 mKeyguardIndicationController.showTransientIndication(R.string.keyguard_unlock); 4468 } 4469 onHintFinished()4470 public void onHintFinished() { 4471 // Delay the reset a bit so the user can read the text. 4472 mKeyguardIndicationController.hideTransientIndicationDelayed(HINT_RESET_DELAY_MS); 4473 } 4474 onCameraHintStarted()4475 public void onCameraHintStarted() { 4476 mFalsingManager.onCameraHintStarted(); 4477 mKeyguardIndicationController.showTransientIndication(R.string.camera_hint); 4478 } 4479 onVoiceAssistHintStarted()4480 public void onVoiceAssistHintStarted() { 4481 mFalsingManager.onLeftAffordanceHintStarted(); 4482 mKeyguardIndicationController.showTransientIndication(R.string.voice_hint); 4483 } 4484 onPhoneHintStarted()4485 public void onPhoneHintStarted() { 4486 mFalsingManager.onLeftAffordanceHintStarted(); 4487 mKeyguardIndicationController.showTransientIndication(R.string.phone_hint); 4488 } 4489 onTrackingStopped(boolean expand)4490 public void onTrackingStopped(boolean expand) { 4491 if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) { 4492 if (!expand && !mUnlockMethodCache.canSkipBouncer()) { 4493 showBouncer(); 4494 } 4495 } 4496 } 4497 4498 @Override getMaxKeyguardNotifications(boolean recompute)4499 protected int getMaxKeyguardNotifications(boolean recompute) { 4500 if (recompute) { 4501 mMaxKeyguardNotifications = Math.max(1, 4502 mNotificationPanel.computeMaxKeyguardNotifications( 4503 mMaxAllowedKeyguardNotifications)); 4504 return mMaxKeyguardNotifications; 4505 } 4506 return mMaxKeyguardNotifications; 4507 } 4508 getMaxKeyguardNotifications()4509 public int getMaxKeyguardNotifications() { 4510 return getMaxKeyguardNotifications(false /* recompute */); 4511 } 4512 getNavigationBarView()4513 public NavigationBarView getNavigationBarView() { 4514 return mNavigationBarView; 4515 } 4516 4517 // ---------------------- DragDownHelper.OnDragDownListener ------------------------------------ 4518 4519 4520 /* Only ever called as a consequence of a lockscreen expansion gesture. */ 4521 @Override onDraggedDown(View startingChild, int dragLengthY)4522 public boolean onDraggedDown(View startingChild, int dragLengthY) { 4523 if (hasActiveNotifications()) { 4524 EventLogTags.writeSysuiLockscreenGesture( 4525 EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_SWIPE_DOWN_FULL_SHADE, 4526 (int) (dragLengthY / mDisplayMetrics.density), 4527 0 /* velocityDp - N/A */); 4528 4529 // We have notifications, go to locked shade. 4530 goToLockedShade(startingChild); 4531 if (startingChild instanceof ExpandableNotificationRow) { 4532 ExpandableNotificationRow row = (ExpandableNotificationRow) startingChild; 4533 row.onExpandedByGesture(true /* drag down is always an open */); 4534 } 4535 return true; 4536 } else { 4537 4538 // No notifications - abort gesture. 4539 return false; 4540 } 4541 } 4542 4543 @Override onDragDownReset()4544 public void onDragDownReset() { 4545 mStackScroller.setDimmed(true /* dimmed */, true /* animated */); 4546 mStackScroller.resetScrollPosition(); 4547 } 4548 4549 @Override onCrossedThreshold(boolean above)4550 public void onCrossedThreshold(boolean above) { 4551 mStackScroller.setDimmed(!above /* dimmed */, true /* animate */); 4552 } 4553 4554 @Override onTouchSlopExceeded()4555 public void onTouchSlopExceeded() { 4556 mStackScroller.removeLongPressCallback(); 4557 } 4558 4559 @Override setEmptyDragAmount(float amount)4560 public void setEmptyDragAmount(float amount) { 4561 mNotificationPanel.setEmptyDragAmount(amount); 4562 } 4563 4564 /** 4565 * If secure with redaction: Show bouncer, go to unlocked shade. 4566 * 4567 * <p>If secure without redaction or no security: Go to {@link StatusBarState#SHADE_LOCKED}.</p> 4568 * 4569 * @param expandView The view to expand after going to the shade. 4570 */ goToLockedShade(View expandView)4571 public void goToLockedShade(View expandView) { 4572 ExpandableNotificationRow row = null; 4573 if (expandView instanceof ExpandableNotificationRow) { 4574 row = (ExpandableNotificationRow) expandView; 4575 row.setUserExpanded(true /* userExpanded */, true /* allowChildExpansion */); 4576 // Indicate that the group expansion is changing at this time -- this way the group 4577 // and children backgrounds / divider animations will look correct. 4578 row.setGroupExpansionChanging(true); 4579 } 4580 boolean fullShadeNeedsBouncer = !userAllowsPrivateNotificationsInPublic(mCurrentUserId) 4581 || !mShowLockscreenNotifications || mFalsingManager.shouldEnforceBouncer(); 4582 if (isLockscreenPublicMode() && fullShadeNeedsBouncer) { 4583 mLeaveOpenOnKeyguardHide = true; 4584 showBouncer(); 4585 mDraggedDownRow = row; 4586 mPendingRemoteInputView = null; 4587 } else { 4588 mNotificationPanel.animateToFullShade(0 /* delay */); 4589 setBarState(StatusBarState.SHADE_LOCKED); 4590 updateKeyguardState(false /* goingToFullShade */, false /* fromShadeLocked */); 4591 } 4592 } 4593 4594 @Override onLockedNotificationImportanceChange(OnDismissAction dismissAction)4595 public void onLockedNotificationImportanceChange(OnDismissAction dismissAction) { 4596 mLeaveOpenOnKeyguardHide = true; 4597 dismissKeyguardThenExecute(dismissAction, true /* afterKeyguardGone */); 4598 } 4599 4600 @Override onLockedRemoteInput(ExpandableNotificationRow row, View clicked)4601 protected void onLockedRemoteInput(ExpandableNotificationRow row, View clicked) { 4602 mLeaveOpenOnKeyguardHide = true; 4603 showBouncer(); 4604 mPendingRemoteInputView = clicked; 4605 } 4606 4607 @Override startWorkChallengeIfNecessary(int userId, IntentSender intendSender, String notificationKey)4608 protected boolean startWorkChallengeIfNecessary(int userId, IntentSender intendSender, 4609 String notificationKey) { 4610 // Clear pending remote view, as we do not want to trigger pending remote input view when 4611 // it's called by other code 4612 mPendingWorkRemoteInputView = null; 4613 return super.startWorkChallengeIfNecessary(userId, intendSender, notificationKey); 4614 } 4615 4616 @Override onLockedWorkRemoteInput(int userId, ExpandableNotificationRow row, View clicked)4617 protected void onLockedWorkRemoteInput(int userId, ExpandableNotificationRow row, 4618 View clicked) { 4619 // Collapse notification and show work challenge 4620 animateCollapsePanels(); 4621 startWorkChallengeIfNecessary(userId, null, null); 4622 // Add pending remote input view after starting work challenge, as starting work challenge 4623 // will clear all previous pending review view 4624 mPendingWorkRemoteInputView = clicked; 4625 } 4626 4627 @Override onWorkChallengeUnlocked()4628 protected void onWorkChallengeUnlocked() { 4629 if (mPendingWorkRemoteInputView != null) { 4630 final View pendingWorkRemoteInputView = mPendingWorkRemoteInputView; 4631 // Expand notification panel and the notification row, then click on remote input view 4632 final Runnable clickPendingViewRunnable = new Runnable() { 4633 @Override 4634 public void run() { 4635 if (mPendingWorkRemoteInputView != null) { 4636 final View pendingWorkRemoteInputView = mPendingWorkRemoteInputView; 4637 ViewParent p = pendingWorkRemoteInputView.getParent(); 4638 while (p != null) { 4639 if (p instanceof ExpandableNotificationRow) { 4640 final ExpandableNotificationRow row = (ExpandableNotificationRow) p; 4641 ViewParent viewParent = row.getParent(); 4642 if (viewParent instanceof NotificationStackScrollLayout) { 4643 final NotificationStackScrollLayout scrollLayout = 4644 (NotificationStackScrollLayout) viewParent; 4645 row.makeActionsVisibile(); 4646 row.post(new Runnable() { 4647 @Override 4648 public void run() { 4649 final Runnable finishScrollingCallback = new Runnable() 4650 { 4651 @Override 4652 public void run() { 4653 mPendingWorkRemoteInputView.callOnClick(); 4654 mPendingWorkRemoteInputView = null; 4655 scrollLayout.setFinishScrollingCallback(null); 4656 } 4657 }; 4658 if (scrollLayout.scrollTo(row)) { 4659 // It scrolls! So call it when it's finished. 4660 scrollLayout.setFinishScrollingCallback( 4661 finishScrollingCallback); 4662 } else { 4663 // It does not scroll, so call it now! 4664 finishScrollingCallback.run(); 4665 } 4666 } 4667 }); 4668 } 4669 break; 4670 } 4671 p = p.getParent(); 4672 } 4673 } 4674 } 4675 }; 4676 mNotificationPanel.getViewTreeObserver().addOnGlobalLayoutListener( 4677 new ViewTreeObserver.OnGlobalLayoutListener() { 4678 @Override 4679 public void onGlobalLayout() { 4680 if (mNotificationPanel.mStatusBar.getStatusBarWindow() 4681 .getHeight() != mNotificationPanel.mStatusBar 4682 .getStatusBarHeight()) { 4683 mNotificationPanel.getViewTreeObserver() 4684 .removeOnGlobalLayoutListener(this); 4685 mNotificationPanel.post(clickPendingViewRunnable); 4686 } 4687 } 4688 }); 4689 instantExpandNotificationsPanel(); 4690 } 4691 } 4692 4693 @Override onExpandClicked(Entry clickedEntry, boolean nowExpanded)4694 public void onExpandClicked(Entry clickedEntry, boolean nowExpanded) { 4695 mHeadsUpManager.setExpanded(clickedEntry, nowExpanded); 4696 if (mState == StatusBarState.KEYGUARD && nowExpanded) { 4697 goToLockedShade(clickedEntry.row); 4698 } 4699 } 4700 4701 /** 4702 * Goes back to the keyguard after hanging around in {@link StatusBarState#SHADE_LOCKED}. 4703 */ goToKeyguard()4704 public void goToKeyguard() { 4705 if (mState == StatusBarState.SHADE_LOCKED) { 4706 mStackScroller.onGoToKeyguard(); 4707 setBarState(StatusBarState.KEYGUARD); 4708 updateKeyguardState(false /* goingToFullShade */, true /* fromShadeLocked*/); 4709 } 4710 } 4711 getKeyguardFadingAwayDelay()4712 public long getKeyguardFadingAwayDelay() { 4713 return mKeyguardFadingAwayDelay; 4714 } 4715 getKeyguardFadingAwayDuration()4716 public long getKeyguardFadingAwayDuration() { 4717 return mKeyguardFadingAwayDuration; 4718 } 4719 4720 @Override setBouncerShowing(boolean bouncerShowing)4721 public void setBouncerShowing(boolean bouncerShowing) { 4722 super.setBouncerShowing(bouncerShowing); 4723 mStatusBarView.setBouncerShowing(bouncerShowing); 4724 disable(mDisabledUnmodified1, mDisabledUnmodified2, true /* animate */); 4725 } 4726 onStartedGoingToSleep()4727 public void onStartedGoingToSleep() { 4728 mStartedGoingToSleep = true; 4729 } 4730 onFinishedGoingToSleep()4731 public void onFinishedGoingToSleep() { 4732 mNotificationPanel.onAffordanceLaunchEnded(); 4733 releaseGestureWakeLock(); 4734 mLaunchCameraOnScreenTurningOn = false; 4735 mStartedGoingToSleep = false; 4736 mDeviceInteractive = false; 4737 mWakeUpComingFromTouch = false; 4738 mWakeUpTouchLocation = null; 4739 mStackScroller.setAnimationsEnabled(false); 4740 updateVisibleToUser(); 4741 if (mLaunchCameraOnFinishedGoingToSleep) { 4742 mLaunchCameraOnFinishedGoingToSleep = false; 4743 4744 // This gets executed before we will show Keyguard, so post it in order that the state 4745 // is correct. 4746 mHandler.post(new Runnable() { 4747 @Override 4748 public void run() { 4749 onCameraLaunchGestureDetected(mLastCameraLaunchSource); 4750 } 4751 }); 4752 } 4753 } 4754 onStartedWakingUp()4755 public void onStartedWakingUp() { 4756 mDeviceInteractive = true; 4757 mStackScroller.setAnimationsEnabled(true); 4758 mNotificationPanel.setTouchDisabled(false); 4759 updateVisibleToUser(); 4760 } 4761 onScreenTurningOn()4762 public void onScreenTurningOn() { 4763 mScreenTurningOn = true; 4764 mFalsingManager.onScreenTurningOn(); 4765 mNotificationPanel.onScreenTurningOn(); 4766 if (mLaunchCameraOnScreenTurningOn) { 4767 mNotificationPanel.launchCamera(false, mLastCameraLaunchSource); 4768 mLaunchCameraOnScreenTurningOn = false; 4769 } 4770 } 4771 vibrateForCameraGesture()4772 private void vibrateForCameraGesture() { 4773 // Make sure to pass -1 for repeat so VibratorService doesn't stop us when going to sleep. 4774 mVibrator.vibrate(new long[]{0, 400}, -1 /* repeat */); 4775 } 4776 onScreenTurnedOn()4777 public void onScreenTurnedOn() { 4778 mScreenTurningOn = false; 4779 mDozeScrimController.onScreenTurnedOn(); 4780 } 4781 4782 /** 4783 * Handles long press for back button. This exits screen pinning. 4784 */ handleLongPressBack()4785 private boolean handleLongPressBack() { 4786 try { 4787 IActivityManager activityManager = ActivityManagerNative.getDefault(); 4788 if (activityManager.isInLockTaskMode()) { 4789 activityManager.stopSystemLockTaskMode(); 4790 4791 // When exiting refresh disabled flags. 4792 mNavigationBarView.setDisabledFlags(mDisabled1, true); 4793 return true; 4794 } 4795 } catch (RemoteException e) { 4796 Log.d(TAG, "Unable to reach activity manager", e); 4797 } 4798 return false; 4799 } 4800 updateRecentsVisibility(boolean visible)4801 public void updateRecentsVisibility(boolean visible) { 4802 // Update the recents visibility flag 4803 if (visible) { 4804 mSystemUiVisibility |= View.RECENT_APPS_VISIBLE; 4805 } else { 4806 mSystemUiVisibility &= ~View.RECENT_APPS_VISIBLE; 4807 } 4808 notifyUiVisibilityChanged(mSystemUiVisibility); 4809 } 4810 4811 @Override showScreenPinningRequest(int taskId)4812 public void showScreenPinningRequest(int taskId) { 4813 if (mKeyguardMonitor.isShowing()) { 4814 // Don't allow apps to trigger this from keyguard. 4815 return; 4816 } 4817 // Show screen pinning request, since this comes from an app, show 'no thanks', button. 4818 showScreenPinningRequest(taskId, true); 4819 } 4820 showScreenPinningRequest(int taskId, boolean allowCancel)4821 public void showScreenPinningRequest(int taskId, boolean allowCancel) { 4822 mScreenPinningRequest.showPrompt(taskId, allowCancel); 4823 } 4824 hasActiveNotifications()4825 public boolean hasActiveNotifications() { 4826 return !mNotificationData.getActiveNotifications().isEmpty(); 4827 } 4828 wakeUpIfDozing(long time, MotionEvent event)4829 public void wakeUpIfDozing(long time, MotionEvent event) { 4830 if (mDozing && mDozeScrimController.isPulsing()) { 4831 PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 4832 pm.wakeUp(time, "com.android.systemui:NODOZE"); 4833 mWakeUpComingFromTouch = true; 4834 mWakeUpTouchLocation = new PointF(event.getX(), event.getY()); 4835 mNotificationPanel.setTouchDisabled(false); 4836 mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested(); 4837 mFalsingManager.onScreenOnFromTouch(); 4838 } 4839 } 4840 4841 @Override appTransitionPending()4842 public void appTransitionPending() { 4843 4844 // Use own timings when Keyguard is going away, see keyguardGoingAway and 4845 // setKeyguardFadingAway 4846 if (!mKeyguardFadingAway) { 4847 mIconController.appTransitionPending(); 4848 } 4849 } 4850 4851 @Override appTransitionCancelled()4852 public void appTransitionCancelled() { 4853 mIconController.appTransitionCancelled(); 4854 EventBus.getDefault().send(new AppTransitionFinishedEvent()); 4855 } 4856 4857 @Override appTransitionStarting(long startTime, long duration)4858 public void appTransitionStarting(long startTime, long duration) { 4859 4860 // Use own timings when Keyguard is going away, see keyguardGoingAway and 4861 // setKeyguardFadingAway. 4862 if (!mKeyguardGoingAway) { 4863 mIconController.appTransitionStarting(startTime, duration); 4864 } 4865 if (mIconPolicy != null) { 4866 mIconPolicy.appTransitionStarting(startTime, duration); 4867 } 4868 } 4869 4870 @Override appTransitionFinished()4871 public void appTransitionFinished() { 4872 EventBus.getDefault().send(new AppTransitionFinishedEvent()); 4873 } 4874 4875 @Override onCameraLaunchGestureDetected(int source)4876 public void onCameraLaunchGestureDetected(int source) { 4877 mLastCameraLaunchSource = source; 4878 if (mStartedGoingToSleep) { 4879 mLaunchCameraOnFinishedGoingToSleep = true; 4880 return; 4881 } 4882 if (!mNotificationPanel.canCameraGestureBeLaunched( 4883 mStatusBarKeyguardViewManager.isShowing() && mExpandedVisible)) { 4884 return; 4885 } 4886 if (!mDeviceInteractive) { 4887 PowerManager pm = mContext.getSystemService(PowerManager.class); 4888 pm.wakeUp(SystemClock.uptimeMillis(), "com.android.systemui:CAMERA_GESTURE"); 4889 mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested(); 4890 } 4891 vibrateForCameraGesture(); 4892 if (!mStatusBarKeyguardViewManager.isShowing()) { 4893 startActivity(KeyguardBottomAreaView.INSECURE_CAMERA_INTENT, 4894 true /* dismissShade */); 4895 } else { 4896 if (!mDeviceInteractive) { 4897 // Avoid flickering of the scrim when we instant launch the camera and the bouncer 4898 // comes on. 4899 mScrimController.dontAnimateBouncerChangesUntilNextFrame(); 4900 mGestureWakeLock.acquire(LAUNCH_TRANSITION_TIMEOUT_MS + 1000L); 4901 } 4902 if (mScreenTurningOn || mStatusBarKeyguardViewManager.isScreenTurnedOn()) { 4903 mNotificationPanel.launchCamera(mDeviceInteractive /* animate */, source); 4904 } else { 4905 // We need to defer the camera launch until the screen comes on, since otherwise 4906 // we will dismiss us too early since we are waiting on an activity to be drawn and 4907 // incorrectly get notified because of the screen on event (which resumes and pauses 4908 // some activities) 4909 mLaunchCameraOnScreenTurningOn = true; 4910 } 4911 } 4912 } 4913 4914 @Override showTvPictureInPictureMenu()4915 public void showTvPictureInPictureMenu() { 4916 // no-op. 4917 } 4918 notifyFpAuthModeChanged()4919 public void notifyFpAuthModeChanged() { 4920 updateDozing(); 4921 } 4922 updateDozing()4923 private void updateDozing() { 4924 Trace.beginSection("PhoneStatusBar#updateDozing"); 4925 // When in wake-and-unlock while pulsing, keep dozing state until fully unlocked. 4926 mDozing = mDozingRequested && mState == StatusBarState.KEYGUARD 4927 || mFingerprintUnlockController.getMode() 4928 == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING; 4929 updateDozingState(); 4930 Trace.endSection(); 4931 } 4932 4933 private final class ShadeUpdates { 4934 private final ArraySet<String> mVisibleNotifications = new ArraySet<String>(); 4935 private final ArraySet<String> mNewVisibleNotifications = new ArraySet<String>(); 4936 check()4937 public void check() { 4938 mNewVisibleNotifications.clear(); 4939 ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications(); 4940 for (int i = 0; i < activeNotifications.size(); i++) { 4941 final Entry entry = activeNotifications.get(i); 4942 final boolean visible = entry.row != null 4943 && entry.row.getVisibility() == View.VISIBLE; 4944 if (visible) { 4945 mNewVisibleNotifications.add(entry.key + entry.notification.getPostTime()); 4946 } 4947 } 4948 final boolean updates = !mVisibleNotifications.containsAll(mNewVisibleNotifications); 4949 mVisibleNotifications.clear(); 4950 mVisibleNotifications.addAll(mNewVisibleNotifications); 4951 4952 // We have new notifications 4953 if (updates && mDozeServiceHost != null) { 4954 mDozeServiceHost.fireNewNotifications(); 4955 } 4956 } 4957 } 4958 4959 private final class DozeServiceHost extends KeyguardUpdateMonitorCallback implements DozeHost { 4960 // Amount of time to allow to update the time shown on the screen before releasing 4961 // the wakelock. This timeout is design to compensate for the fact that we don't 4962 // currently have a way to know when time display contents have actually been 4963 // refreshed once we've finished rendering a new frame. 4964 private static final long PROCESSING_TIME = 500; 4965 4966 private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>(); 4967 private final H mHandler = new H(); 4968 4969 // Keeps the last reported state by fireNotificationLight. 4970 private boolean mNotificationLightOn; 4971 4972 @Override toString()4973 public String toString() { 4974 return "PSB.DozeServiceHost[mCallbacks=" + mCallbacks.size() + "]"; 4975 } 4976 firePowerSaveChanged(boolean active)4977 public void firePowerSaveChanged(boolean active) { 4978 for (Callback callback : mCallbacks) { 4979 callback.onPowerSaveChanged(active); 4980 } 4981 } 4982 fireBuzzBeepBlinked()4983 public void fireBuzzBeepBlinked() { 4984 for (Callback callback : mCallbacks) { 4985 callback.onBuzzBeepBlinked(); 4986 } 4987 } 4988 fireNotificationLight(boolean on)4989 public void fireNotificationLight(boolean on) { 4990 mNotificationLightOn = on; 4991 for (Callback callback : mCallbacks) { 4992 callback.onNotificationLight(on); 4993 } 4994 } 4995 fireNewNotifications()4996 public void fireNewNotifications() { 4997 for (Callback callback : mCallbacks) { 4998 callback.onNewNotifications(); 4999 } 5000 } 5001 5002 @Override addCallback(@onNull Callback callback)5003 public void addCallback(@NonNull Callback callback) { 5004 mCallbacks.add(callback); 5005 } 5006 5007 @Override removeCallback(@onNull Callback callback)5008 public void removeCallback(@NonNull Callback callback) { 5009 mCallbacks.remove(callback); 5010 } 5011 5012 @Override startDozing(@onNull Runnable ready)5013 public void startDozing(@NonNull Runnable ready) { 5014 mHandler.obtainMessage(H.MSG_START_DOZING, ready).sendToTarget(); 5015 } 5016 5017 @Override pulseWhileDozing(@onNull PulseCallback callback, int reason)5018 public void pulseWhileDozing(@NonNull PulseCallback callback, int reason) { 5019 mHandler.obtainMessage(H.MSG_PULSE_WHILE_DOZING, reason, 0, callback).sendToTarget(); 5020 } 5021 5022 @Override stopDozing()5023 public void stopDozing() { 5024 mHandler.obtainMessage(H.MSG_STOP_DOZING).sendToTarget(); 5025 } 5026 5027 @Override isPowerSaveActive()5028 public boolean isPowerSaveActive() { 5029 return mBatteryController != null && mBatteryController.isPowerSave(); 5030 } 5031 5032 @Override isPulsingBlocked()5033 public boolean isPulsingBlocked() { 5034 return mFingerprintUnlockController.getMode() 5035 == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK; 5036 } 5037 5038 @Override isNotificationLightOn()5039 public boolean isNotificationLightOn() { 5040 return mNotificationLightOn; 5041 } 5042 handleStartDozing(@onNull Runnable ready)5043 private void handleStartDozing(@NonNull Runnable ready) { 5044 if (!mDozingRequested) { 5045 mDozingRequested = true; 5046 DozeLog.traceDozing(mContext, mDozing); 5047 updateDozing(); 5048 } 5049 ready.run(); 5050 } 5051 handlePulseWhileDozing(@onNull PulseCallback callback, int reason)5052 private void handlePulseWhileDozing(@NonNull PulseCallback callback, int reason) { 5053 mDozeScrimController.pulse(new PulseCallback() { 5054 5055 @Override 5056 public void onPulseStarted() { 5057 callback.onPulseStarted(); 5058 mStackScroller.setPulsing(true); 5059 } 5060 5061 @Override 5062 public void onPulseFinished() { 5063 callback.onPulseFinished(); 5064 mStackScroller.setPulsing(false); 5065 } 5066 }, reason); 5067 } 5068 handleStopDozing()5069 private void handleStopDozing() { 5070 if (mDozingRequested) { 5071 mDozingRequested = false; 5072 DozeLog.traceDozing(mContext, mDozing); 5073 updateDozing(); 5074 } 5075 } 5076 5077 private final class H extends Handler { 5078 private static final int MSG_START_DOZING = 1; 5079 private static final int MSG_PULSE_WHILE_DOZING = 2; 5080 private static final int MSG_STOP_DOZING = 3; 5081 5082 @Override handleMessage(Message msg)5083 public void handleMessage(Message msg) { 5084 switch (msg.what) { 5085 case MSG_START_DOZING: 5086 handleStartDozing((Runnable) msg.obj); 5087 break; 5088 case MSG_PULSE_WHILE_DOZING: 5089 handlePulseWhileDozing((PulseCallback) msg.obj, msg.arg1); 5090 break; 5091 case MSG_STOP_DOZING: 5092 handleStopDozing(); 5093 break; 5094 } 5095 } 5096 } 5097 } 5098 } 5099