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