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