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