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