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