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