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