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