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