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