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