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