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