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