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