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