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