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