PhoneStatusBar.java revision dfafca76919808db583fbe53765b6358ee955122
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 final int toRemoveCount = toRemove.size(); 1563 for (int i = 0; i < toRemoveCount; i++) { 1564 mNotificationIcons.removeView(toRemove.get(i)); 1565 } 1566 1567 for (int i=0; i<toShow.size(); i++) { 1568 View v = toShow.get(i); 1569 if (v.getParent() == null) { 1570 mNotificationIcons.addView(v, i, params); 1571 } 1572 } 1573 1574 // Resort notification icons 1575 final int childCount = mNotificationIcons.getChildCount(); 1576 for (int i = 0; i < childCount; i++) { 1577 View actual = mNotificationIcons.getChildAt(i); 1578 StatusBarIconView expected = toShow.get(i); 1579 if (actual == expected) { 1580 continue; 1581 } 1582 mNotificationIcons.removeView(expected); 1583 mNotificationIcons.addView(expected, i); 1584 } 1585 } 1586 1587 @Override 1588 protected void updateRowStates() { 1589 super.updateRowStates(); 1590 mNotificationPanel.notifyVisibleChildrenChanged(); 1591 } 1592 1593 protected void updateCarrierLabelVisibility(boolean force) { 1594 // TODO: Handle this for the notification stack scroller as well 1595 if (!mShowCarrierInPanel) return; 1596 // The idea here is to only show the carrier label when there is enough room to see it, 1597 // i.e. when there aren't enough notifications to fill the panel. 1598 if (SPEW) { 1599 Log.d(TAG, String.format("stackScrollerh=%d scrollh=%d carrierh=%d", 1600 mStackScroller.getHeight(), mStackScroller.getHeight(), 1601 mCarrierLabelHeight)); 1602 } 1603 1604 // Emergency calls only is shown in the expanded header now. 1605 final boolean emergencyCallsShownElsewhere = true; 1606 final boolean makeVisible = 1607 !(emergencyCallsShownElsewhere && mNetworkController.isEmergencyOnly()) 1608 && mStackScroller.getHeight() < (mNotificationPanel.getHeight() 1609 - mCarrierLabelHeight - mStatusBarHeaderHeight) 1610 && mStackScroller.getVisibility() == View.VISIBLE 1611 && mState != StatusBarState.KEYGUARD; 1612 1613 if (force || mCarrierLabelVisible != makeVisible) { 1614 mCarrierLabelVisible = makeVisible; 1615 if (DEBUG) { 1616 Log.d(TAG, "making carrier label " + (makeVisible?"visible":"invisible")); 1617 } 1618 mCarrierLabel.animate().cancel(); 1619 if (makeVisible) { 1620 mCarrierLabel.setVisibility(View.VISIBLE); 1621 } 1622 mCarrierLabel.animate() 1623 .alpha(makeVisible ? 1f : 0f) 1624 //.setStartDelay(makeVisible ? 500 : 0) 1625 //.setDuration(makeVisible ? 750 : 100) 1626 .setDuration(150) 1627 .setListener(makeVisible ? null : new AnimatorListenerAdapter() { 1628 @Override 1629 public void onAnimationEnd(Animator animation) { 1630 if (!mCarrierLabelVisible) { // race 1631 mCarrierLabel.setVisibility(View.INVISIBLE); 1632 mCarrierLabel.setAlpha(0f); 1633 } 1634 } 1635 }) 1636 .start(); 1637 } 1638 } 1639 1640 @Override 1641 protected void setAreThereNotifications() { 1642 1643 if (SPEW) { 1644 final boolean clearable = hasActiveNotifications() && 1645 mNotificationData.hasActiveClearableNotifications(); 1646 Log.d(TAG, "setAreThereNotifications: N=" + 1647 mNotificationData.getActiveNotifications().size() + " any=" + 1648 hasActiveNotifications() + " clearable=" + clearable); 1649 } 1650 1651 final View nlo = mStatusBarView.findViewById(R.id.notification_lights_out); 1652 final boolean showDot = hasActiveNotifications() && !areLightsOn(); 1653 if (showDot != (nlo.getAlpha() == 1.0f)) { 1654 if (showDot) { 1655 nlo.setAlpha(0f); 1656 nlo.setVisibility(View.VISIBLE); 1657 } 1658 nlo.animate() 1659 .alpha(showDot?1:0) 1660 .setDuration(showDot?750:250) 1661 .setInterpolator(new AccelerateInterpolator(2.0f)) 1662 .setListener(showDot ? null : new AnimatorListenerAdapter() { 1663 @Override 1664 public void onAnimationEnd(Animator _a) { 1665 nlo.setVisibility(View.GONE); 1666 } 1667 }) 1668 .start(); 1669 } 1670 1671 findAndUpdateMediaNotifications(); 1672 1673 updateCarrierLabelVisibility(false); 1674 } 1675 1676 public void findAndUpdateMediaNotifications() { 1677 boolean metaDataChanged = false; 1678 1679 synchronized (mNotificationData) { 1680 ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications(); 1681 final int N = activeNotifications.size(); 1682 Entry mediaNotification = null; 1683 MediaController controller = null; 1684 for (int i = 0; i < N; i++) { 1685 final Entry entry = activeNotifications.get(i); 1686 if (isMediaNotification(entry)) { 1687 final MediaSession.Token token = entry.notification.getNotification().extras 1688 .getParcelable(Notification.EXTRA_MEDIA_SESSION); 1689 if (token != null) { 1690 controller = new MediaController(mContext, token); 1691 if (controller != null) { 1692 // we've got a live one, here 1693 mediaNotification = entry; 1694 } 1695 } 1696 } 1697 } 1698 1699 if (mediaNotification == null) { 1700 // Still nothing? OK, let's just look for live media sessions and see if they match 1701 // one of our notifications. This will catch apps that aren't (yet!) using media 1702 // notifications. 1703 1704 if (mMediaSessionManager != null) { 1705 final List<MediaController> sessions 1706 = mMediaSessionManager.getActiveSessionsForUser( 1707 null, 1708 UserHandle.USER_ALL); 1709 1710 for (MediaController aController : sessions) { 1711 if (aController == null) continue; 1712 final PlaybackState state = aController.getPlaybackState(); 1713 if (state == null) continue; 1714 switch (state.getState()) { 1715 case PlaybackState.STATE_STOPPED: 1716 case PlaybackState.STATE_ERROR: 1717 continue; 1718 default: 1719 // now to see if we have one like this 1720 final String pkg = aController.getPackageName(); 1721 1722 for (int i = 0; i < N; i++) { 1723 final Entry entry = activeNotifications.get(i); 1724 if (entry.notification.getPackageName().equals(pkg)) { 1725 if (DEBUG_MEDIA) { 1726 Log.v(TAG, "DEBUG_MEDIA: found controller matching " 1727 + entry.notification.getKey()); 1728 } 1729 controller = aController; 1730 mediaNotification = entry; 1731 break; 1732 } 1733 } 1734 } 1735 } 1736 } 1737 } 1738 1739 if (controller != mMediaController) { 1740 // We have a new media session 1741 1742 if (mMediaController != null) { 1743 // something old was playing 1744 Log.v(TAG, "DEBUG_MEDIA: Disconnecting from old controller: " 1745 + mMediaController); 1746 mMediaController.unregisterCallback(mMediaListener); 1747 } 1748 mMediaController = controller; 1749 1750 if (mMediaController != null) { 1751 mMediaController.registerCallback(mMediaListener); 1752 mMediaMetadata = mMediaController.getMetadata(); 1753 if (DEBUG_MEDIA) { 1754 Log.v(TAG, "DEBUG_MEDIA: insert listener, receive metadata: " 1755 + mMediaMetadata); 1756 } 1757 1758 final String notificationKey = mediaNotification == null 1759 ? null 1760 : mediaNotification.notification.getKey(); 1761 1762 if (notificationKey == null || !notificationKey.equals(mMediaNotificationKey)) { 1763 // we have a new notification! 1764 if (DEBUG_MEDIA) { 1765 Log.v(TAG, "DEBUG_MEDIA: Found new media notification: key=" 1766 + notificationKey + " controller=" + controller); 1767 } 1768 mMediaNotificationKey = notificationKey; 1769 } 1770 } else { 1771 mMediaMetadata = null; 1772 mMediaNotificationKey = null; 1773 } 1774 1775 metaDataChanged = true; 1776 } else { 1777 // Media session unchanged 1778 1779 if (DEBUG_MEDIA) { 1780 Log.v(TAG, "DEBUG_MEDIA: Continuing media notification: key=" + mMediaNotificationKey); 1781 } 1782 } 1783 } 1784 1785 updateMediaMetaData(metaDataChanged); 1786 } 1787 1788 /** 1789 * Hide the album artwork that is fading out and release its bitmap. 1790 */ 1791 private Runnable mHideBackdropFront = new Runnable() { 1792 @Override 1793 public void run() { 1794 if (DEBUG_MEDIA) { 1795 Log.v(TAG, "DEBUG_MEDIA: removing fade layer"); 1796 } 1797 mBackdropFront.setVisibility(View.INVISIBLE); 1798 mBackdropFront.animate().cancel(); 1799 mBackdropFront.setImageDrawable(null); 1800 } 1801 }; 1802 1803 /** 1804 * Refresh or remove lockscreen artwork from media metadata. 1805 */ 1806 public void updateMediaMetaData(boolean metaDataChanged) { 1807 if (!SHOW_LOCKSCREEN_MEDIA_ARTWORK) return; 1808 1809 if (mBackdrop == null) return; // called too early 1810 1811 if (DEBUG_MEDIA) { 1812 Log.v(TAG, "DEBUG_MEDIA: updating album art for notification " + mMediaNotificationKey 1813 + " metadata=" + mMediaMetadata 1814 + " metaDataChanged=" + metaDataChanged 1815 + " state=" + mState); 1816 } 1817 1818 Bitmap artworkBitmap = null; 1819 if (mMediaMetadata != null) { 1820 artworkBitmap = mMediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ART); 1821 if (artworkBitmap == null) { 1822 artworkBitmap = mMediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART); 1823 // might still be null 1824 } 1825 } 1826 1827 final boolean hasArtwork = artworkBitmap != null; 1828 1829 if ((hasArtwork || DEBUG_MEDIA_FAKE_ARTWORK) 1830 && (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)) { 1831 // time to show some art! 1832 if (mBackdrop.getVisibility() != View.VISIBLE) { 1833 mBackdrop.setVisibility(View.VISIBLE); 1834 mBackdrop.animate().alpha(1f); 1835 metaDataChanged = true; 1836 if (DEBUG_MEDIA) { 1837 Log.v(TAG, "DEBUG_MEDIA: Fading in album artwork"); 1838 } 1839 } 1840 if (metaDataChanged) { 1841 if (mBackdropBack.getDrawable() != null) { 1842 mBackdropFront.setImageDrawable(mBackdropBack.getDrawable()); 1843 mBackdropFront.setAlpha(1f); 1844 mBackdropFront.setVisibility(View.VISIBLE); 1845 } else { 1846 mBackdropFront.setVisibility(View.INVISIBLE); 1847 } 1848 1849 if (DEBUG_MEDIA_FAKE_ARTWORK) { 1850 final int c = 0xFF000000 | (int)(Math.random() * 0xFFFFFF); 1851 Log.v(TAG, String.format("DEBUG_MEDIA: setting new color: 0x%08x", c)); 1852 mBackdropBack.setBackgroundColor(0xFFFFFFFF); 1853 mBackdropBack.setImageDrawable(new ColorDrawable(c)); 1854 } else { 1855 mBackdropBack.setImageBitmap(artworkBitmap); 1856 } 1857 1858 if (mBackdropFront.getVisibility() == View.VISIBLE) { 1859 if (DEBUG_MEDIA) { 1860 Log.v(TAG, "DEBUG_MEDIA: Crossfading album artwork from " 1861 + mBackdropFront.getDrawable() 1862 + " to " 1863 + mBackdropBack.getDrawable()); 1864 } 1865 mBackdropFront.animate() 1866 .setDuration(250) 1867 .alpha(0f).withEndAction(mHideBackdropFront); 1868 } 1869 } 1870 } else { 1871 // need to hide the album art, either because we are unlocked or because 1872 // the metadata isn't there to support it 1873 if (mBackdrop.getVisibility() != View.GONE) { 1874 if (DEBUG_MEDIA) { 1875 Log.v(TAG, "DEBUG_MEDIA: Fading out album artwork"); 1876 } 1877 mBackdrop.animate() 1878 .alpha(0f) 1879 .setInterpolator(mBackdropInterpolator) 1880 .setDuration(300) 1881 .setStartDelay(0) 1882 .withEndAction(new Runnable() { 1883 @Override 1884 public void run() { 1885 mBackdrop.setVisibility(View.GONE); 1886 mBackdropFront.animate().cancel(); 1887 mBackdropBack.animate().cancel(); 1888 mHandler.post(mHideBackdropFront); 1889 } 1890 }); 1891 if (mKeyguardFadingAway) { 1892 mBackdrop.animate() 1893 1894 // Make it disappear faster, as the focus should be on the activity behind. 1895 .setDuration(mKeyguardFadingAwayDuration / 2) 1896 .setStartDelay(mKeyguardFadingAwayDelay) 1897 .setInterpolator(mLinearInterpolator) 1898 .start(); 1899 } 1900 } 1901 } 1902 } 1903 1904 public void showClock(boolean show) { 1905 if (mStatusBarView == null) return; 1906 View clock = mStatusBarView.findViewById(R.id.clock); 1907 if (clock != null) { 1908 clock.setVisibility(show ? View.VISIBLE : View.GONE); 1909 } 1910 } 1911 1912 private int adjustDisableFlags(int state) { 1913 if (!mLaunchTransitionFadingAway 1914 && (mExpandedVisible || mBouncerShowing || mWaitingForKeyguardExit)) { 1915 state |= StatusBarManager.DISABLE_NOTIFICATION_ICONS; 1916 state |= StatusBarManager.DISABLE_SYSTEM_INFO; 1917 } 1918 return state; 1919 } 1920 1921 /** 1922 * State is one or more of the DISABLE constants from StatusBarManager. 1923 */ 1924 public void disable(int state, boolean animate) { 1925 mDisabledUnmodified = state; 1926 state = adjustDisableFlags(state); 1927 final int old = mDisabled; 1928 final int diff = state ^ old; 1929 mDisabled = state; 1930 1931 if (DEBUG) { 1932 Log.d(TAG, String.format("disable: 0x%08x -> 0x%08x (diff: 0x%08x)", 1933 old, state, diff)); 1934 } 1935 1936 StringBuilder flagdbg = new StringBuilder(); 1937 flagdbg.append("disable: < "); 1938 flagdbg.append(((state & StatusBarManager.DISABLE_EXPAND) != 0) ? "EXPAND" : "expand"); 1939 flagdbg.append(((diff & StatusBarManager.DISABLE_EXPAND) != 0) ? "* " : " "); 1940 flagdbg.append(((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) ? "ICONS" : "icons"); 1941 flagdbg.append(((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) ? "* " : " "); 1942 flagdbg.append(((state & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) ? "ALERTS" : "alerts"); 1943 flagdbg.append(((diff & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) ? "* " : " "); 1944 flagdbg.append(((state & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) ? "SYSTEM_INFO" : "system_info"); 1945 flagdbg.append(((diff & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) ? "* " : " "); 1946 flagdbg.append(((state & StatusBarManager.DISABLE_BACK) != 0) ? "BACK" : "back"); 1947 flagdbg.append(((diff & StatusBarManager.DISABLE_BACK) != 0) ? "* " : " "); 1948 flagdbg.append(((state & StatusBarManager.DISABLE_HOME) != 0) ? "HOME" : "home"); 1949 flagdbg.append(((diff & StatusBarManager.DISABLE_HOME) != 0) ? "* " : " "); 1950 flagdbg.append(((state & StatusBarManager.DISABLE_RECENT) != 0) ? "RECENT" : "recent"); 1951 flagdbg.append(((diff & StatusBarManager.DISABLE_RECENT) != 0) ? "* " : " "); 1952 flagdbg.append(((state & StatusBarManager.DISABLE_CLOCK) != 0) ? "CLOCK" : "clock"); 1953 flagdbg.append(((diff & StatusBarManager.DISABLE_CLOCK) != 0) ? "* " : " "); 1954 flagdbg.append(((state & StatusBarManager.DISABLE_SEARCH) != 0) ? "SEARCH" : "search"); 1955 flagdbg.append(((diff & StatusBarManager.DISABLE_SEARCH) != 0) ? "* " : " "); 1956 flagdbg.append(">"); 1957 Log.d(TAG, flagdbg.toString()); 1958 1959 if ((diff & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) { 1960 mSystemIconArea.animate().cancel(); 1961 if ((state & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) { 1962 animateStatusBarHide(mSystemIconArea, animate); 1963 } else { 1964 animateStatusBarShow(mSystemIconArea, animate); 1965 } 1966 } 1967 1968 if ((diff & StatusBarManager.DISABLE_CLOCK) != 0) { 1969 boolean show = (state & StatusBarManager.DISABLE_CLOCK) == 0; 1970 showClock(show); 1971 } 1972 if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) { 1973 if ((state & StatusBarManager.DISABLE_EXPAND) != 0) { 1974 animateCollapsePanels(); 1975 } 1976 } 1977 1978 if ((diff & (StatusBarManager.DISABLE_HOME 1979 | StatusBarManager.DISABLE_RECENT 1980 | StatusBarManager.DISABLE_BACK 1981 | StatusBarManager.DISABLE_SEARCH)) != 0) { 1982 // the nav bar will take care of these 1983 if (mNavigationBarView != null) mNavigationBarView.setDisabledFlags(state); 1984 1985 if ((state & StatusBarManager.DISABLE_RECENT) != 0) { 1986 // close recents if it's visible 1987 mHandler.removeMessages(MSG_HIDE_RECENT_APPS); 1988 mHandler.sendEmptyMessage(MSG_HIDE_RECENT_APPS); 1989 } 1990 } 1991 1992 if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) { 1993 if ((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) { 1994 if (mTicking) { 1995 haltTicker(); 1996 } 1997 animateStatusBarHide(mNotificationIconArea, animate); 1998 } else { 1999 animateStatusBarShow(mNotificationIconArea, animate); 2000 } 2001 } 2002 2003 if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) { 2004 mDisableNotificationAlerts = 2005 (state & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0; 2006 mHeadsUpObserver.onChange(true); 2007 } 2008 } 2009 2010 /** 2011 * Animates {@code v}, a view that is part of the status bar, out. 2012 */ 2013 private void animateStatusBarHide(final View v, boolean animate) { 2014 v.animate().cancel(); 2015 if (!animate) { 2016 v.setAlpha(0f); 2017 v.setVisibility(View.INVISIBLE); 2018 return; 2019 } 2020 v.animate() 2021 .alpha(0f) 2022 .setDuration(160) 2023 .setStartDelay(0) 2024 .setInterpolator(ALPHA_OUT) 2025 .withEndAction(new Runnable() { 2026 @Override 2027 public void run() { 2028 v.setVisibility(View.INVISIBLE); 2029 } 2030 }); 2031 } 2032 2033 /** 2034 * Animates {@code v}, a view that is part of the status bar, in. 2035 */ 2036 private void animateStatusBarShow(View v, boolean animate) { 2037 v.animate().cancel(); 2038 v.setVisibility(View.VISIBLE); 2039 if (!animate) { 2040 v.setAlpha(1f); 2041 return; 2042 } 2043 v.animate() 2044 .alpha(1f) 2045 .setDuration(320) 2046 .setInterpolator(ALPHA_IN) 2047 .setStartDelay(50) 2048 2049 // We need to clean up any pending end action from animateStatusBarHide if we call 2050 // both hide and show in the same frame before the animation actually gets started. 2051 // cancel() doesn't really remove the end action. 2052 .withEndAction(null); 2053 2054 // Synchronize the motion with the Keyguard fading if necessary. 2055 if (mKeyguardFadingAway) { 2056 v.animate() 2057 .setDuration(mKeyguardFadingAwayDuration) 2058 .setInterpolator(mLinearOutSlowIn) 2059 .setStartDelay(mKeyguardFadingAwayDelay) 2060 .start(); 2061 } 2062 } 2063 2064 @Override 2065 protected BaseStatusBar.H createHandler() { 2066 return new PhoneStatusBar.H(); 2067 } 2068 2069 @Override 2070 public void startActivity(Intent intent, boolean dismissShade, boolean afterKeyguardGone) { 2071 startActivityDismissingKeyguard(intent, false, dismissShade, afterKeyguardGone); 2072 } 2073 2074 public ScrimController getScrimController() { 2075 return mScrimController; 2076 } 2077 2078 public void setQsExpanded(boolean expanded) { 2079 mStatusBarWindowManager.setQsExpanded(expanded); 2080 } 2081 2082 public boolean isGoingToNotificationShade() { 2083 return mLeaveOpenOnKeyguardHide; 2084 } 2085 2086 public boolean isQsExpanded() { 2087 return mNotificationPanel.isQsExpanded(); 2088 } 2089 2090 public boolean isFalsingThresholdNeeded() { 2091 boolean onKeyguard = getBarState() == StatusBarState.KEYGUARD; 2092 boolean isMethodInSecure = mUnlockMethodCache.isMethodInsecure(); 2093 return onKeyguard && isMethodInSecure; 2094 } 2095 2096 @Override // NotificationData.Environment 2097 public String getCurrentMediaNotificationKey() { 2098 return mMediaNotificationKey; 2099 } 2100 2101 /** 2102 * All changes to the status bar and notifications funnel through here and are batched. 2103 */ 2104 private class H extends BaseStatusBar.H { 2105 public void handleMessage(Message m) { 2106 super.handleMessage(m); 2107 switch (m.what) { 2108 case MSG_OPEN_NOTIFICATION_PANEL: 2109 animateExpandNotificationsPanel(); 2110 break; 2111 case MSG_OPEN_SETTINGS_PANEL: 2112 animateExpandSettingsPanel(); 2113 break; 2114 case MSG_CLOSE_PANELS: 2115 animateCollapsePanels(); 2116 break; 2117 case MSG_SHOW_HEADS_UP: 2118 setHeadsUpVisibility(true); 2119 break; 2120 case MSG_DECAY_HEADS_UP: 2121 mHeadsUpNotificationView.release(); 2122 setHeadsUpVisibility(false); 2123 break; 2124 case MSG_HIDE_HEADS_UP: 2125 mHeadsUpNotificationView.release(); 2126 setHeadsUpVisibility(false); 2127 break; 2128 case MSG_ESCALATE_HEADS_UP: 2129 escalateHeadsUp(); 2130 setHeadsUpVisibility(false); 2131 break; 2132 } 2133 } 2134 } 2135 2136 /** if the interrupting notification had a fullscreen intent, fire it now. */ 2137 private void escalateHeadsUp() { 2138 if (mHeadsUpNotificationView.getEntry() != null) { 2139 final StatusBarNotification sbn = mHeadsUpNotificationView.getEntry().notification; 2140 mHeadsUpNotificationView.release(); 2141 final Notification notification = sbn.getNotification(); 2142 if (notification.fullScreenIntent != null) { 2143 if (DEBUG) 2144 Log.d(TAG, "converting a heads up to fullScreen"); 2145 try { 2146 notification.fullScreenIntent.send(); 2147 } catch (PendingIntent.CanceledException e) { 2148 } 2149 } 2150 } 2151 } 2152 2153 View.OnFocusChangeListener mFocusChangeListener = new View.OnFocusChangeListener() { 2154 public void onFocusChange(View v, boolean hasFocus) { 2155 // Because 'v' is a ViewGroup, all its children will be (un)selected 2156 // too, which allows marqueeing to work. 2157 v.setSelected(hasFocus); 2158 } 2159 }; 2160 2161 boolean panelsEnabled() { 2162 return (mDisabled & StatusBarManager.DISABLE_EXPAND) == 0; 2163 } 2164 2165 void makeExpandedVisible(boolean force) { 2166 if (SPEW) Log.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible); 2167 if (!force && (mExpandedVisible || !panelsEnabled())) { 2168 return; 2169 } 2170 2171 mExpandedVisible = true; 2172 if (mNavigationBarView != null) 2173 mNavigationBarView.setSlippery(true); 2174 2175 updateCarrierLabelVisibility(true); 2176 2177 updateExpandedViewPos(EXPANDED_LEAVE_ALONE); 2178 2179 // Expand the window to encompass the full screen in anticipation of the drag. 2180 // This is only possible to do atomically because the status bar is at the top of the screen! 2181 mStatusBarWindowManager.setStatusBarExpanded(true); 2182 mStatusBarView.setFocusable(false); 2183 2184 visibilityChanged(true); 2185 mWaitingForKeyguardExit = false; 2186 disable(mDisabledUnmodified, !force /* animate */); 2187 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true); 2188 } 2189 2190 public void animateCollapsePanels() { 2191 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE); 2192 } 2193 2194 private final Runnable mAnimateCollapsePanels = new Runnable() { 2195 @Override 2196 public void run() { 2197 animateCollapsePanels(); 2198 } 2199 }; 2200 2201 public void postAnimateCollapsePanels() { 2202 mHandler.post(mAnimateCollapsePanels); 2203 } 2204 2205 public void animateCollapsePanels(int flags) { 2206 animateCollapsePanels(flags, false /* force */); 2207 } 2208 2209 public void animateCollapsePanels(int flags, boolean force) { 2210 if (!force && 2211 (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)) { 2212 runPostCollapseRunnables(); 2213 return; 2214 } 2215 if (SPEW) { 2216 Log.d(TAG, "animateCollapse():" 2217 + " mExpandedVisible=" + mExpandedVisible 2218 + " flags=" + flags); 2219 } 2220 2221 if ((flags & CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL) == 0) { 2222 if (!mHandler.hasMessages(MSG_HIDE_RECENT_APPS)) { 2223 mHandler.removeMessages(MSG_HIDE_RECENT_APPS); 2224 mHandler.sendEmptyMessage(MSG_HIDE_RECENT_APPS); 2225 } 2226 } 2227 2228 if ((flags & CommandQueue.FLAG_EXCLUDE_SEARCH_PANEL) == 0) { 2229 mHandler.removeMessages(MSG_CLOSE_SEARCH_PANEL); 2230 mHandler.sendEmptyMessage(MSG_CLOSE_SEARCH_PANEL); 2231 } 2232 2233 if (mStatusBarWindow != null) { 2234 // release focus immediately to kick off focus change transition 2235 mStatusBarWindowManager.setStatusBarFocusable(false); 2236 2237 mStatusBarWindow.cancelExpandHelper(); 2238 mStatusBarView.collapseAllPanels(true); 2239 } 2240 } 2241 2242 private void runPostCollapseRunnables() { 2243 int size = mPostCollapseRunnables.size(); 2244 for (int i = 0; i < size; i++) { 2245 mPostCollapseRunnables.get(i).run(); 2246 } 2247 mPostCollapseRunnables.clear(); 2248 } 2249 2250 public ViewPropertyAnimator setVisibilityWhenDone( 2251 final ViewPropertyAnimator a, final View v, final int vis) { 2252 a.setListener(new AnimatorListenerAdapter() { 2253 @Override 2254 public void onAnimationEnd(Animator animation) { 2255 v.setVisibility(vis); 2256 a.setListener(null); // oneshot 2257 } 2258 }); 2259 return a; 2260 } 2261 2262 public Animator setVisibilityWhenDone( 2263 final Animator a, final View v, final int vis) { 2264 a.addListener(new AnimatorListenerAdapter() { 2265 @Override 2266 public void onAnimationEnd(Animator animation) { 2267 v.setVisibility(vis); 2268 } 2269 }); 2270 return a; 2271 } 2272 2273 public Animator interpolator(TimeInterpolator ti, Animator a) { 2274 a.setInterpolator(ti); 2275 return a; 2276 } 2277 2278 public Animator startDelay(int d, Animator a) { 2279 a.setStartDelay(d); 2280 return a; 2281 } 2282 2283 public Animator start(Animator a) { 2284 a.start(); 2285 return a; 2286 } 2287 2288 final TimeInterpolator mAccelerateInterpolator = new AccelerateInterpolator(); 2289 final TimeInterpolator mDecelerateInterpolator = new DecelerateInterpolator(); 2290 final int FLIP_DURATION_OUT = 125; 2291 final int FLIP_DURATION_IN = 225; 2292 final int FLIP_DURATION = (FLIP_DURATION_IN + FLIP_DURATION_OUT); 2293 2294 Animator mScrollViewAnim, mClearButtonAnim; 2295 2296 @Override 2297 public void animateExpandNotificationsPanel() { 2298 if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible); 2299 if (!panelsEnabled()) { 2300 return ; 2301 } 2302 2303 mNotificationPanel.expand(); 2304 2305 if (false) postStartTracing(); 2306 } 2307 2308 @Override 2309 public void animateExpandSettingsPanel() { 2310 if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible); 2311 if (!panelsEnabled()) { 2312 return; 2313 } 2314 2315 // Settings are not available in setup 2316 if (!mUserSetup) return; 2317 2318 mNotificationPanel.expand(); 2319 mNotificationPanel.openQs(); 2320 2321 if (false) postStartTracing(); 2322 } 2323 2324 public void animateCollapseQuickSettings() { 2325 mStatusBarView.collapseAllPanels(true); 2326 } 2327 2328 void makeExpandedInvisible() { 2329 if (SPEW) Log.d(TAG, "makeExpandedInvisible: mExpandedVisible=" + mExpandedVisible 2330 + " mExpandedVisible=" + mExpandedVisible); 2331 2332 if (!mExpandedVisible || mStatusBarWindow == null) { 2333 return; 2334 } 2335 2336 // Ensure the panel is fully collapsed (just in case; bug 6765842, 7260868) 2337 mStatusBarView.collapseAllPanels(/*animate=*/ false); 2338 2339 // reset things to their proper state 2340 if (mScrollViewAnim != null) mScrollViewAnim.cancel(); 2341 if (mClearButtonAnim != null) mClearButtonAnim.cancel(); 2342 2343 mStackScroller.setVisibility(View.VISIBLE); 2344 mNotificationPanel.setVisibility(View.GONE); 2345 2346 setAreThereNotifications(); // show the clear button 2347 2348 mNotificationPanel.closeQs(); 2349 2350 mExpandedVisible = false; 2351 if (mNavigationBarView != null) 2352 mNavigationBarView.setSlippery(false); 2353 visibilityChanged(false); 2354 2355 // Shrink the window to the size of the status bar only 2356 mStatusBarWindowManager.setStatusBarExpanded(false); 2357 mStatusBarView.setFocusable(true); 2358 2359 // Close any "App info" popups that might have snuck on-screen 2360 dismissPopups(); 2361 2362 runPostCollapseRunnables(); 2363 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false); 2364 showBouncer(); 2365 disable(mDisabledUnmodified, true /* animate */); 2366 } 2367 2368 public boolean interceptTouchEvent(MotionEvent event) { 2369 if (DEBUG_GESTURES) { 2370 if (event.getActionMasked() != MotionEvent.ACTION_MOVE) { 2371 EventLog.writeEvent(EventLogTags.SYSUI_STATUSBAR_TOUCH, 2372 event.getActionMasked(), (int) event.getX(), (int) event.getY(), mDisabled); 2373 } 2374 2375 } 2376 2377 if (SPEW) { 2378 Log.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled=" 2379 + mDisabled + " mTracking=" + mTracking); 2380 } else if (CHATTY) { 2381 if (event.getAction() != MotionEvent.ACTION_MOVE) { 2382 Log.d(TAG, String.format( 2383 "panel: %s at (%f, %f) mDisabled=0x%08x", 2384 MotionEvent.actionToString(event.getAction()), 2385 event.getRawX(), event.getRawY(), mDisabled)); 2386 } 2387 } 2388 2389 if (DEBUG_GESTURES) { 2390 mGestureRec.add(event); 2391 } 2392 2393 if (mStatusBarWindowState == WINDOW_STATE_SHOWING) { 2394 final boolean upOrCancel = 2395 event.getAction() == MotionEvent.ACTION_UP || 2396 event.getAction() == MotionEvent.ACTION_CANCEL; 2397 if (upOrCancel && !mExpandedVisible) { 2398 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false); 2399 } else { 2400 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true); 2401 } 2402 } 2403 return false; 2404 } 2405 2406 public GestureRecorder getGestureRecorder() { 2407 return mGestureRec; 2408 } 2409 2410 private void setNavigationIconHints(int hints) { 2411 if (hints == mNavigationIconHints) return; 2412 2413 mNavigationIconHints = hints; 2414 2415 if (mNavigationBarView != null) { 2416 mNavigationBarView.setNavigationIconHints(hints); 2417 } 2418 checkBarModes(); 2419 } 2420 2421 @Override // CommandQueue 2422 public void setWindowState(int window, int state) { 2423 boolean showing = state == WINDOW_STATE_SHOWING; 2424 if (mStatusBarWindow != null 2425 && window == StatusBarManager.WINDOW_STATUS_BAR 2426 && mStatusBarWindowState != state) { 2427 mStatusBarWindowState = state; 2428 if (DEBUG_WINDOW_STATE) Log.d(TAG, "Status bar " + windowStateToString(state)); 2429 if (!showing) { 2430 mStatusBarView.collapseAllPanels(false); 2431 } 2432 } 2433 if (mNavigationBarView != null 2434 && window == StatusBarManager.WINDOW_NAVIGATION_BAR 2435 && mNavigationBarWindowState != state) { 2436 mNavigationBarWindowState = state; 2437 if (DEBUG_WINDOW_STATE) Log.d(TAG, "Navigation bar " + windowStateToString(state)); 2438 } 2439 } 2440 2441 @Override // CommandQueue 2442 public void buzzBeepBlinked() { 2443 if (mDozeServiceHost != null) { 2444 mDozeServiceHost.fireBuzzBeepBlinked(); 2445 } 2446 } 2447 2448 @Override 2449 public void notificationLightOff() { 2450 if (mDozeServiceHost != null) { 2451 mDozeServiceHost.fireNotificationLight(false); 2452 } 2453 } 2454 2455 @Override 2456 public void notificationLightPulse(int argb, int onMillis, int offMillis) { 2457 if (mDozeServiceHost != null) { 2458 mDozeServiceHost.fireNotificationLight(true); 2459 } 2460 } 2461 2462 @Override // CommandQueue 2463 public void setSystemUiVisibility(int vis, int mask) { 2464 final int oldVal = mSystemUiVisibility; 2465 final int newVal = (oldVal&~mask) | (vis&mask); 2466 final int diff = newVal ^ oldVal; 2467 if (DEBUG) Log.d(TAG, String.format( 2468 "setSystemUiVisibility vis=%s mask=%s oldVal=%s newVal=%s diff=%s", 2469 Integer.toHexString(vis), Integer.toHexString(mask), 2470 Integer.toHexString(oldVal), Integer.toHexString(newVal), 2471 Integer.toHexString(diff))); 2472 if (diff != 0) { 2473 // we never set the recents bit via this method, so save the prior state to prevent 2474 // clobbering the bit below 2475 final boolean wasRecentsVisible = (mSystemUiVisibility & View.RECENT_APPS_VISIBLE) > 0; 2476 2477 mSystemUiVisibility = newVal; 2478 2479 // update low profile 2480 if ((diff & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0) { 2481 final boolean lightsOut = (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0; 2482 if (lightsOut) { 2483 animateCollapsePanels(); 2484 if (mTicking) { 2485 haltTicker(); 2486 } 2487 } 2488 2489 setAreThereNotifications(); 2490 } 2491 2492 // update status bar mode 2493 final int sbMode = computeBarMode(oldVal, newVal, mStatusBarView.getBarTransitions(), 2494 View.STATUS_BAR_TRANSIENT, View.STATUS_BAR_TRANSLUCENT); 2495 2496 // update navigation bar mode 2497 final int nbMode = mNavigationBarView == null ? -1 : computeBarMode( 2498 oldVal, newVal, mNavigationBarView.getBarTransitions(), 2499 View.NAVIGATION_BAR_TRANSIENT, View.NAVIGATION_BAR_TRANSLUCENT); 2500 final boolean sbModeChanged = sbMode != -1; 2501 final boolean nbModeChanged = nbMode != -1; 2502 boolean checkBarModes = false; 2503 if (sbModeChanged && sbMode != mStatusBarMode) { 2504 mStatusBarMode = sbMode; 2505 checkBarModes = true; 2506 } 2507 if (nbModeChanged && nbMode != mNavigationBarMode) { 2508 mNavigationBarMode = nbMode; 2509 checkBarModes = true; 2510 } 2511 if (checkBarModes) { 2512 checkBarModes(); 2513 } 2514 if (sbModeChanged || nbModeChanged) { 2515 // update transient bar autohide 2516 if (mStatusBarMode == MODE_SEMI_TRANSPARENT || mNavigationBarMode == MODE_SEMI_TRANSPARENT) { 2517 scheduleAutohide(); 2518 } else { 2519 cancelAutohide(); 2520 } 2521 } 2522 2523 // ready to unhide 2524 if ((vis & View.STATUS_BAR_UNHIDE) != 0) { 2525 mSystemUiVisibility &= ~View.STATUS_BAR_UNHIDE; 2526 } 2527 if ((vis & View.NAVIGATION_BAR_UNHIDE) != 0) { 2528 mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE; 2529 } 2530 2531 // restore the recents bit 2532 if (wasRecentsVisible) { 2533 mSystemUiVisibility |= View.RECENT_APPS_VISIBLE; 2534 } 2535 2536 // send updated sysui visibility to window manager 2537 notifyUiVisibilityChanged(mSystemUiVisibility); 2538 } 2539 } 2540 2541 private int computeBarMode(int oldVis, int newVis, BarTransitions transitions, 2542 int transientFlag, int translucentFlag) { 2543 final int oldMode = barMode(oldVis, transientFlag, translucentFlag); 2544 final int newMode = barMode(newVis, transientFlag, translucentFlag); 2545 if (oldMode == newMode) { 2546 return -1; // no mode change 2547 } 2548 return newMode; 2549 } 2550 2551 private int barMode(int vis, int transientFlag, int translucentFlag) { 2552 return (vis & transientFlag) != 0 ? MODE_SEMI_TRANSPARENT 2553 : (vis & translucentFlag) != 0 ? MODE_TRANSLUCENT 2554 : (vis & View.SYSTEM_UI_TRANSPARENT) != 0 ? MODE_TRANSPARENT 2555 : (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0 ? MODE_LIGHTS_OUT 2556 : MODE_OPAQUE; 2557 } 2558 2559 private void checkBarModes() { 2560 if (mDemoMode) return; 2561 checkBarMode(mStatusBarMode, mStatusBarWindowState, mStatusBarView.getBarTransitions()); 2562 if (mNavigationBarView != null) { 2563 checkBarMode(mNavigationBarMode, 2564 mNavigationBarWindowState, mNavigationBarView.getBarTransitions()); 2565 } 2566 } 2567 2568 private void checkBarMode(int mode, int windowState, BarTransitions transitions) { 2569 final boolean powerSave = mBatteryController.isPowerSave(); 2570 final boolean anim = (mScreenOn == null || mScreenOn) && windowState != WINDOW_STATE_HIDDEN 2571 && !powerSave; 2572 if (powerSave && getBarState() == StatusBarState.SHADE) { 2573 mode = MODE_WARNING; 2574 } 2575 transitions.transitionTo(mode, anim); 2576 } 2577 2578 private void finishBarAnimations() { 2579 mStatusBarView.getBarTransitions().finishAnimations(); 2580 if (mNavigationBarView != null) { 2581 mNavigationBarView.getBarTransitions().finishAnimations(); 2582 } 2583 } 2584 2585 private final Runnable mCheckBarModes = new Runnable() { 2586 @Override 2587 public void run() { 2588 checkBarModes(); 2589 } 2590 }; 2591 2592 @Override 2593 public void setInteracting(int barWindow, boolean interacting) { 2594 mInteractingWindows = interacting 2595 ? (mInteractingWindows | barWindow) 2596 : (mInteractingWindows & ~barWindow); 2597 if (mInteractingWindows != 0) { 2598 suspendAutohide(); 2599 } else { 2600 resumeSuspendedAutohide(); 2601 } 2602 checkBarModes(); 2603 } 2604 2605 private void resumeSuspendedAutohide() { 2606 if (mAutohideSuspended) { 2607 scheduleAutohide(); 2608 mHandler.postDelayed(mCheckBarModes, 500); // longer than home -> launcher 2609 } 2610 } 2611 2612 private void suspendAutohide() { 2613 mHandler.removeCallbacks(mAutohide); 2614 mHandler.removeCallbacks(mCheckBarModes); 2615 mAutohideSuspended = (mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0; 2616 } 2617 2618 private void cancelAutohide() { 2619 mAutohideSuspended = false; 2620 mHandler.removeCallbacks(mAutohide); 2621 } 2622 2623 private void scheduleAutohide() { 2624 cancelAutohide(); 2625 mHandler.postDelayed(mAutohide, AUTOHIDE_TIMEOUT_MS); 2626 } 2627 2628 private void checkUserAutohide(View v, MotionEvent event) { 2629 if ((mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0 // a transient bar is revealed 2630 && event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar 2631 && event.getX() == 0 && event.getY() == 0 // a touch outside both bars 2632 ) { 2633 userAutohide(); 2634 } 2635 } 2636 2637 private void userAutohide() { 2638 cancelAutohide(); 2639 mHandler.postDelayed(mAutohide, 350); // longer than app gesture -> flag clear 2640 } 2641 2642 private boolean areLightsOn() { 2643 return 0 == (mSystemUiVisibility & View.SYSTEM_UI_FLAG_LOW_PROFILE); 2644 } 2645 2646 public void setLightsOn(boolean on) { 2647 Log.v(TAG, "setLightsOn(" + on + ")"); 2648 if (on) { 2649 setSystemUiVisibility(0, View.SYSTEM_UI_FLAG_LOW_PROFILE); 2650 } else { 2651 setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE, View.SYSTEM_UI_FLAG_LOW_PROFILE); 2652 } 2653 } 2654 2655 private void notifyUiVisibilityChanged(int vis) { 2656 try { 2657 mWindowManagerService.statusBarVisibilityChanged(vis); 2658 } catch (RemoteException ex) { 2659 } 2660 } 2661 2662 public void topAppWindowChanged(boolean showMenu) { 2663 if (DEBUG) { 2664 Log.d(TAG, (showMenu?"showing":"hiding") + " the MENU button"); 2665 } 2666 if (mNavigationBarView != null) { 2667 mNavigationBarView.setMenuVisibility(showMenu); 2668 } 2669 2670 // See above re: lights-out policy for legacy apps. 2671 if (showMenu) setLightsOn(true); 2672 } 2673 2674 @Override 2675 public void setImeWindowStatus(IBinder token, int vis, int backDisposition, 2676 boolean showImeSwitcher) { 2677 boolean imeShown = (vis & InputMethodService.IME_VISIBLE) != 0; 2678 int flags = mNavigationIconHints; 2679 if ((backDisposition == InputMethodService.BACK_DISPOSITION_WILL_DISMISS) || imeShown) { 2680 flags |= NAVIGATION_HINT_BACK_ALT; 2681 } else { 2682 flags &= ~NAVIGATION_HINT_BACK_ALT; 2683 } 2684 if (showImeSwitcher) { 2685 flags |= NAVIGATION_HINT_IME_SHOWN; 2686 } else { 2687 flags &= ~NAVIGATION_HINT_IME_SHOWN; 2688 } 2689 2690 setNavigationIconHints(flags); 2691 } 2692 2693 @Override 2694 protected void tick(StatusBarNotification n, boolean firstTime) { 2695 if (!mTickerEnabled) return; 2696 2697 // no ticking in lights-out mode 2698 if (!areLightsOn()) return; 2699 2700 // no ticking in Setup 2701 if (!isDeviceProvisioned()) return; 2702 2703 // not for you 2704 if (!isNotificationForCurrentProfiles(n)) return; 2705 2706 // Show the ticker if one is requested. Also don't do this 2707 // until status bar window is attached to the window manager, 2708 // because... well, what's the point otherwise? And trying to 2709 // run a ticker without being attached will crash! 2710 if (n.getNotification().tickerText != null && mStatusBarWindow != null 2711 && mStatusBarWindow.getWindowToken() != null) { 2712 if (0 == (mDisabled & (StatusBarManager.DISABLE_NOTIFICATION_ICONS 2713 | StatusBarManager.DISABLE_NOTIFICATION_TICKER))) { 2714 mTicker.addEntry(n); 2715 } 2716 } 2717 } 2718 2719 private class MyTicker extends Ticker { 2720 MyTicker(Context context, View sb) { 2721 super(context, sb); 2722 if (!mTickerEnabled) { 2723 Log.w(TAG, "MyTicker instantiated with mTickerEnabled=false", new Throwable()); 2724 } 2725 } 2726 2727 @Override 2728 public void tickerStarting() { 2729 if (!mTickerEnabled) return; 2730 mTicking = true; 2731 mStatusBarContents.setVisibility(View.GONE); 2732 mTickerView.setVisibility(View.VISIBLE); 2733 mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_up_in, null)); 2734 mStatusBarContents.startAnimation(loadAnim(com.android.internal.R.anim.push_up_out, null)); 2735 } 2736 2737 @Override 2738 public void tickerDone() { 2739 if (!mTickerEnabled) return; 2740 mStatusBarContents.setVisibility(View.VISIBLE); 2741 mTickerView.setVisibility(View.GONE); 2742 mStatusBarContents.startAnimation(loadAnim(com.android.internal.R.anim.push_down_in, null)); 2743 mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_down_out, 2744 mTickingDoneListener)); 2745 } 2746 2747 public void tickerHalting() { 2748 if (!mTickerEnabled) return; 2749 if (mStatusBarContents.getVisibility() != View.VISIBLE) { 2750 mStatusBarContents.setVisibility(View.VISIBLE); 2751 mStatusBarContents 2752 .startAnimation(loadAnim(com.android.internal.R.anim.fade_in, null)); 2753 } 2754 mTickerView.setVisibility(View.GONE); 2755 // we do not animate the ticker away at this point, just get rid of it (b/6992707) 2756 } 2757 } 2758 2759 Animation.AnimationListener mTickingDoneListener = new Animation.AnimationListener() {; 2760 public void onAnimationEnd(Animation animation) { 2761 mTicking = false; 2762 } 2763 public void onAnimationRepeat(Animation animation) { 2764 } 2765 public void onAnimationStart(Animation animation) { 2766 } 2767 }; 2768 2769 private Animation loadAnim(int id, Animation.AnimationListener listener) { 2770 Animation anim = AnimationUtils.loadAnimation(mContext, id); 2771 if (listener != null) { 2772 anim.setAnimationListener(listener); 2773 } 2774 return anim; 2775 } 2776 2777 public static String viewInfo(View v) { 2778 return "[(" + v.getLeft() + "," + v.getTop() + ")(" + v.getRight() + "," + v.getBottom() 2779 + ") " + v.getWidth() + "x" + v.getHeight() + "]"; 2780 } 2781 2782 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2783 synchronized (mQueueLock) { 2784 pw.println("Current Status Bar state:"); 2785 pw.println(" mExpandedVisible=" + mExpandedVisible 2786 + ", mTrackingPosition=" + mTrackingPosition); 2787 pw.println(" mTickerEnabled=" + mTickerEnabled); 2788 if (mTickerEnabled) { 2789 pw.println(" mTicking=" + mTicking); 2790 pw.println(" mTickerView: " + viewInfo(mTickerView)); 2791 } 2792 pw.println(" mTracking=" + mTracking); 2793 pw.println(" mDisplayMetrics=" + mDisplayMetrics); 2794 pw.println(" mStackScroller: " + viewInfo(mStackScroller)); 2795 pw.println(" mStackScroller: " + viewInfo(mStackScroller) 2796 + " scroll " + mStackScroller.getScrollX() 2797 + "," + mStackScroller.getScrollY()); 2798 } 2799 2800 pw.print(" mInteractingWindows="); pw.println(mInteractingWindows); 2801 pw.print(" mStatusBarWindowState="); 2802 pw.println(windowStateToString(mStatusBarWindowState)); 2803 pw.print(" mStatusBarMode="); 2804 pw.println(BarTransitions.modeToString(mStatusBarMode)); 2805 pw.print(" mDozing="); pw.println(mDozing); 2806 pw.print(" mZenMode="); 2807 pw.println(Settings.Global.zenModeToString(mZenMode)); 2808 pw.print(" mUseHeadsUp="); 2809 pw.println(mUseHeadsUp); 2810 pw.print(" interrupting package: "); 2811 pw.println(hunStateToString(mHeadsUpNotificationView.getEntry())); 2812 dumpBarTransitions(pw, "mStatusBarView", mStatusBarView.getBarTransitions()); 2813 if (mNavigationBarView != null) { 2814 pw.print(" mNavigationBarWindowState="); 2815 pw.println(windowStateToString(mNavigationBarWindowState)); 2816 pw.print(" mNavigationBarMode="); 2817 pw.println(BarTransitions.modeToString(mNavigationBarMode)); 2818 dumpBarTransitions(pw, "mNavigationBarView", mNavigationBarView.getBarTransitions()); 2819 } 2820 2821 pw.print(" mNavigationBarView="); 2822 if (mNavigationBarView == null) { 2823 pw.println("null"); 2824 } else { 2825 mNavigationBarView.dump(fd, pw, args); 2826 } 2827 2828 pw.print(" mMediaSessionManager="); 2829 pw.println(mMediaSessionManager); 2830 pw.print(" mMediaNotificationKey="); 2831 pw.println(mMediaNotificationKey); 2832 pw.print(" mMediaController="); 2833 pw.print(mMediaController); 2834 if (mMediaController != null) { 2835 pw.print(" state=" + mMediaController.getPlaybackState()); 2836 } 2837 pw.println(); 2838 pw.print(" mMediaMetadata="); 2839 pw.print(mMediaMetadata); 2840 if (mMediaMetadata != null) { 2841 pw.print(" title=" + mMediaMetadata.getText(MediaMetadata.METADATA_KEY_TITLE)); 2842 } 2843 pw.println(); 2844 2845 pw.println(" Panels: "); 2846 if (mNotificationPanel != null) { 2847 pw.println(" mNotificationPanel=" + 2848 mNotificationPanel + " params=" + mNotificationPanel.getLayoutParams().debug("")); 2849 pw.print (" "); 2850 mNotificationPanel.dump(fd, pw, args); 2851 } 2852 2853 if (DUMPTRUCK) { 2854 synchronized (mNotificationData) { 2855 mNotificationData.dump(pw, " "); 2856 } 2857 2858 int N = mStatusIcons.getChildCount(); 2859 pw.println(" system icons: " + N); 2860 for (int i=0; i<N; i++) { 2861 StatusBarIconView ic = (StatusBarIconView) mStatusIcons.getChildAt(i); 2862 pw.println(" [" + i + "] icon=" + ic); 2863 } 2864 2865 if (false) { 2866 pw.println("see the logcat for a dump of the views we have created."); 2867 // must happen on ui thread 2868 mHandler.post(new Runnable() { 2869 public void run() { 2870 mStatusBarView.getLocationOnScreen(mAbsPos); 2871 Log.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1] 2872 + ") " + mStatusBarView.getWidth() + "x" 2873 + getStatusBarHeight()); 2874 mStatusBarView.debug(); 2875 } 2876 }); 2877 } 2878 } 2879 2880 if (DEBUG_GESTURES) { 2881 pw.print(" status bar gestures: "); 2882 mGestureRec.dump(fd, pw, args); 2883 } 2884 2885 if (mNetworkController != null) { 2886 mNetworkController.dump(fd, pw, args); 2887 } 2888 if (mBluetoothController != null) { 2889 mBluetoothController.dump(fd, pw, args); 2890 } 2891 if (mCastController != null) { 2892 mCastController.dump(fd, pw, args); 2893 } 2894 if (mUserSwitcherController != null) { 2895 mUserSwitcherController.dump(fd, pw, args); 2896 } 2897 if (mBatteryController != null) { 2898 mBatteryController.dump(fd, pw, args); 2899 } 2900 if (mNextAlarmController != null) { 2901 mNextAlarmController.dump(fd, pw, args); 2902 } 2903 if (mSecurityController != null) { 2904 mSecurityController.dump(fd, pw, args); 2905 } 2906 } 2907 2908 private String hunStateToString(Entry entry) { 2909 if (entry == null) return "null"; 2910 if (entry.notification == null) return "corrupt"; 2911 return entry.notification.getPackageName(); 2912 } 2913 2914 private static void dumpBarTransitions(PrintWriter pw, String var, BarTransitions transitions) { 2915 pw.print(" "); pw.print(var); pw.print(".BarTransitions.mMode="); 2916 pw.println(BarTransitions.modeToString(transitions.getMode())); 2917 } 2918 2919 @Override 2920 public void createAndAddWindows() { 2921 addStatusBarWindow(); 2922 } 2923 2924 private void addStatusBarWindow() { 2925 makeStatusBarView(); 2926 mStatusBarWindowManager = new StatusBarWindowManager(mContext); 2927 mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight()); 2928 } 2929 2930 static final float saturate(float a) { 2931 return a < 0f ? 0f : (a > 1f ? 1f : a); 2932 } 2933 2934 @Override 2935 public void updateExpandedViewPos(int thingy) { 2936 if (SPEW) Log.v(TAG, "updateExpandedViewPos"); 2937 2938 // on larger devices, the notification panel is propped open a bit 2939 mNotificationPanel.setMinimumHeight( 2940 (int)(mNotificationPanelMinHeightFrac * mCurrentDisplaySize.y)); 2941 2942 FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mNotificationPanel.getLayoutParams(); 2943 lp.gravity = mNotificationPanelGravity; 2944 mNotificationPanel.setLayoutParams(lp); 2945 2946 updateCarrierLabelVisibility(false); 2947 } 2948 2949 // called by makeStatusbar and also by PhoneStatusBarView 2950 void updateDisplaySize() { 2951 mDisplay.getMetrics(mDisplayMetrics); 2952 mDisplay.getSize(mCurrentDisplaySize); 2953 if (DEBUG_GESTURES) { 2954 mGestureRec.tag("display", 2955 String.format("%dx%d", mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels)); 2956 } 2957 } 2958 2959 public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned, 2960 final boolean dismissShade, final boolean afterKeyguardGone) { 2961 if (onlyProvisioned && !isDeviceProvisioned()) return; 2962 2963 final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing(); 2964 dismissKeyguardThenExecute(new OnDismissAction() { 2965 @Override 2966 public boolean onDismiss() { 2967 AsyncTask.execute(new Runnable() { 2968 public void run() { 2969 try { 2970 if (keyguardShowing && !afterKeyguardGone) { 2971 ActivityManagerNative.getDefault() 2972 .keyguardWaitingForActivityDrawn(); 2973 } 2974 intent.setFlags( 2975 Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); 2976 mContext.startActivityAsUser( 2977 intent, new UserHandle(UserHandle.USER_CURRENT)); 2978 overrideActivityPendingAppTransition( 2979 keyguardShowing && !afterKeyguardGone); 2980 } catch (RemoteException e) { 2981 } 2982 } 2983 }); 2984 if (dismissShade) { 2985 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */); 2986 } 2987 return true; 2988 } 2989 }, afterKeyguardGone); 2990 } 2991 2992 private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 2993 public void onReceive(Context context, Intent intent) { 2994 if (DEBUG) Log.v(TAG, "onReceive: " + intent); 2995 String action = intent.getAction(); 2996 if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) { 2997 int flags = CommandQueue.FLAG_EXCLUDE_NONE; 2998 String reason = intent.getStringExtra("reason"); 2999 if (reason != null && reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) { 3000 flags |= CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL; 3001 } 3002 animateCollapsePanels(flags); 3003 } 3004 else if (Intent.ACTION_SCREEN_OFF.equals(action)) { 3005 mScreenOn = false; 3006 notifyNavigationBarScreenOn(false); 3007 notifyHeadsUpScreenOn(false); 3008 finishBarAnimations(); 3009 stopNotificationLogging(); 3010 resetUserExpandedStates(); 3011 } 3012 else if (Intent.ACTION_SCREEN_ON.equals(action)) { 3013 mScreenOn = true; 3014 // work around problem where mDisplay.getRotation() is not stable while screen is off (bug 7086018) 3015 repositionNavigationBar(); 3016 notifyNavigationBarScreenOn(true); 3017 startNotificationLoggingIfScreenOnAndVisible(); 3018 } 3019 else if (ACTION_DEMO.equals(action)) { 3020 Bundle bundle = intent.getExtras(); 3021 if (bundle != null) { 3022 String command = bundle.getString("command", "").trim().toLowerCase(); 3023 if (command.length() > 0) { 3024 try { 3025 dispatchDemoCommand(command, bundle); 3026 } catch (Throwable t) { 3027 Log.w(TAG, "Error running demo command, intent=" + intent, t); 3028 } 3029 } 3030 } 3031 } else if ("fake_artwork".equals(action)) { 3032 if (DEBUG_MEDIA_FAKE_ARTWORK) { 3033 updateMediaMetaData(true); 3034 } 3035 } 3036 } 3037 }; 3038 3039 private void resetUserExpandedStates() { 3040 ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications(); 3041 final int notificationCount = activeNotifications.size(); 3042 for (int i = 0; i < notificationCount; i++) { 3043 NotificationData.Entry entry = activeNotifications.get(i); 3044 if (entry.row != null) { 3045 entry.row.resetUserExpansion(); 3046 } 3047 } 3048 } 3049 3050 @Override 3051 protected void dismissKeyguardThenExecute(final OnDismissAction action, 3052 boolean afterKeyguardGone) { 3053 if (mStatusBarKeyguardViewManager.isShowing()) { 3054 if (UnlockMethodCache.getInstance(mContext).isMethodInsecure() 3055 && mNotificationPanel.isLaunchTransitionRunning() && !afterKeyguardGone) { 3056 action.onDismiss(); 3057 mNotificationPanel.setLaunchTransitionEndRunnable(new Runnable() { 3058 @Override 3059 public void run() { 3060 mStatusBarKeyguardViewManager.dismiss(); 3061 } 3062 }); 3063 } else { 3064 mStatusBarKeyguardViewManager.dismissWithAction(action, afterKeyguardGone); 3065 } 3066 } else { 3067 action.onDismiss(); 3068 } 3069 } 3070 3071 // SystemUIService notifies SystemBars of configuration changes, which then calls down here 3072 @Override 3073 protected void onConfigurationChanged(Configuration newConfig) { 3074 super.onConfigurationChanged(newConfig); // calls refreshLayout 3075 3076 if (DEBUG) { 3077 Log.v(TAG, "configuration changed: " + mContext.getResources().getConfiguration()); 3078 } 3079 updateDisplaySize(); // populates mDisplayMetrics 3080 3081 updateResources(); 3082 updateClockSize(); 3083 repositionNavigationBar(); 3084 updateExpandedViewPos(EXPANDED_LEAVE_ALONE); 3085 updateShowSearchHoldoff(); 3086 updateRowStates(); 3087 } 3088 3089 @Override 3090 public void userSwitched(int newUserId) { 3091 if (MULTIUSER_DEBUG) mNotificationPanelDebugText.setText("USER " + newUserId); 3092 animateCollapsePanels(); 3093 updateNotifications(); 3094 resetUserSetupObserver(); 3095 setControllerUsers(); 3096 } 3097 3098 private void setControllerUsers() { 3099 if (mZenModeController != null) { 3100 mZenModeController.setUserId(mCurrentUserId); 3101 } 3102 } 3103 3104 private void resetUserSetupObserver() { 3105 mContext.getContentResolver().unregisterContentObserver(mUserSetupObserver); 3106 mUserSetupObserver.onChange(false); 3107 mContext.getContentResolver().registerContentObserver( 3108 Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE), true, 3109 mUserSetupObserver, 3110 mCurrentUserId); 3111 } 3112 3113 private void setHeadsUpVisibility(boolean vis) { 3114 if (!ENABLE_HEADS_UP) return; 3115 if (DEBUG) Log.v(TAG, (vis ? "showing" : "hiding") + " heads up window"); 3116 EventLog.writeEvent(EventLogTags.SYSUI_HEADS_UP_STATUS, 3117 vis ? mHeadsUpNotificationView.getKey() : "", 3118 vis ? 1 : 0); 3119 mHeadsUpNotificationView.setVisibility(vis ? View.VISIBLE : View.GONE); 3120 } 3121 3122 public void onHeadsUpDismissed() { 3123 mHeadsUpNotificationView.dismiss(); 3124 } 3125 3126 /** 3127 * Reload some of our resources when the configuration changes. 3128 * 3129 * We don't reload everything when the configuration changes -- we probably 3130 * should, but getting that smooth is tough. Someday we'll fix that. In the 3131 * meantime, just update the things that we know change. 3132 */ 3133 void updateResources() { 3134 // Update the quick setting tiles 3135 if (mQSPanel != null) { 3136 mQSPanel.updateResources(); 3137 } 3138 3139 loadDimens(); 3140 mLinearOutSlowIn = AnimationUtils.loadInterpolator( 3141 mContext, android.R.interpolator.linear_out_slow_in); 3142 3143 if (mNotificationPanel != null) { 3144 mNotificationPanel.updateResources(); 3145 } 3146 if (mHeadsUpNotificationView != null) { 3147 mHeadsUpNotificationView.updateResources(); 3148 } 3149 if (mBrightnessMirrorController != null) { 3150 mBrightnessMirrorController.updateResources(); 3151 } 3152 } 3153 3154 private void updateClockSize() { 3155 if (mStatusBarView == null) return; 3156 TextView clock = (TextView) mStatusBarView.findViewById(R.id.clock); 3157 if (clock != null) { 3158 FontSizeUtils.updateFontSize(clock, R.dimen.status_bar_clock_size); 3159 } 3160 } 3161 protected void loadDimens() { 3162 final Resources res = mContext.getResources(); 3163 3164 mNaturalBarHeight = res.getDimensionPixelSize( 3165 com.android.internal.R.dimen.status_bar_height); 3166 3167 int newIconSize = res.getDimensionPixelSize( 3168 com.android.internal.R.dimen.status_bar_icon_size); 3169 int newIconHPadding = res.getDimensionPixelSize( 3170 R.dimen.status_bar_icon_padding); 3171 3172 if (newIconHPadding != mIconHPadding || newIconSize != mIconSize) { 3173// Log.d(TAG, "size=" + newIconSize + " padding=" + newIconHPadding); 3174 mIconHPadding = newIconHPadding; 3175 mIconSize = newIconSize; 3176 //reloadAllNotificationIcons(); // reload the tray 3177 } 3178 3179 mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore); 3180 3181 mNotificationPanelGravity = res.getInteger(R.integer.notification_panel_layout_gravity); 3182 if (mNotificationPanelGravity <= 0) { 3183 mNotificationPanelGravity = Gravity.START | Gravity.TOP; 3184 } 3185 3186 mCarrierLabelHeight = res.getDimensionPixelSize(R.dimen.carrier_label_height); 3187 mStatusBarHeaderHeight = res.getDimensionPixelSize(R.dimen.status_bar_header_height); 3188 3189 mNotificationPanelMinHeightFrac = res.getFraction(R.dimen.notification_panel_min_height_frac, 1, 1); 3190 if (mNotificationPanelMinHeightFrac < 0f || mNotificationPanelMinHeightFrac > 1f) { 3191 mNotificationPanelMinHeightFrac = 0f; 3192 } 3193 3194 mHeadsUpNotificationDecay = res.getInteger(R.integer.heads_up_notification_decay); 3195 mRowMinHeight = res.getDimensionPixelSize(R.dimen.notification_min_height); 3196 mRowMaxHeight = res.getDimensionPixelSize(R.dimen.notification_max_height); 3197 3198 mKeyguardMaxNotificationCount = res.getInteger(R.integer.keyguard_max_notification_count); 3199 3200 if (DEBUG) Log.v(TAG, "updateResources"); 3201 } 3202 3203 // Visibility reporting 3204 3205 @Override 3206 protected void visibilityChanged(boolean visible) { 3207 mVisible = visible; 3208 if (visible) { 3209 startNotificationLoggingIfScreenOnAndVisible(); 3210 } else { 3211 stopNotificationLogging(); 3212 } 3213 super.visibilityChanged(visible); 3214 } 3215 3216 private void stopNotificationLogging() { 3217 // Report all notifications as invisible and turn down the 3218 // reporter. 3219 if (!mCurrentlyVisibleNotifications.isEmpty()) { 3220 logNotificationVisibilityChanges( 3221 Collections.<String>emptyList(), mCurrentlyVisibleNotifications); 3222 mCurrentlyVisibleNotifications.clear(); 3223 } 3224 mHandler.removeCallbacks(mVisibilityReporter); 3225 mStackScroller.setChildLocationsChangedListener(null); 3226 } 3227 3228 private void startNotificationLoggingIfScreenOnAndVisible() { 3229 if (mVisible && mScreenOn) { 3230 mStackScroller.setChildLocationsChangedListener(mNotificationLocationsChangedListener); 3231 // Some transitions like mScreenOn=false -> mScreenOn=true don't 3232 // cause the scroller to emit child location events. Hence generate 3233 // one ourselves to guarantee that we're reporting visible 3234 // notifications. 3235 // (Note that in cases where the scroller does emit events, this 3236 // additional event doesn't break anything.) 3237 mNotificationLocationsChangedListener.onChildLocationsChanged(mStackScroller); 3238 } 3239 } 3240 3241 private void logNotificationVisibilityChanges( 3242 Collection<String> newlyVisible, Collection<String> noLongerVisible) { 3243 if (newlyVisible.isEmpty() && noLongerVisible.isEmpty()) { 3244 return; 3245 } 3246 String[] newlyVisibleAr = newlyVisible.toArray(new String[newlyVisible.size()]); 3247 String[] noLongerVisibleAr = noLongerVisible.toArray(new String[noLongerVisible.size()]); 3248 try { 3249 mBarService.onNotificationVisibilityChanged(newlyVisibleAr, noLongerVisibleAr); 3250 } catch (RemoteException e) { 3251 // Ignore. 3252 } 3253 } 3254 3255 // 3256 // tracing 3257 // 3258 3259 void postStartTracing() { 3260 mHandler.postDelayed(mStartTracing, 3000); 3261 } 3262 3263 void vibrate() { 3264 android.os.Vibrator vib = (android.os.Vibrator)mContext.getSystemService( 3265 Context.VIBRATOR_SERVICE); 3266 vib.vibrate(250, VIBRATION_ATTRIBUTES); 3267 } 3268 3269 Runnable mStartTracing = new Runnable() { 3270 public void run() { 3271 vibrate(); 3272 SystemClock.sleep(250); 3273 Log.d(TAG, "startTracing"); 3274 android.os.Debug.startMethodTracing("/data/statusbar-traces/trace"); 3275 mHandler.postDelayed(mStopTracing, 10000); 3276 } 3277 }; 3278 3279 Runnable mStopTracing = new Runnable() { 3280 public void run() { 3281 android.os.Debug.stopMethodTracing(); 3282 Log.d(TAG, "stopTracing"); 3283 vibrate(); 3284 } 3285 }; 3286 3287 @Override 3288 protected void haltTicker() { 3289 if (mTickerEnabled) { 3290 mTicker.halt(); 3291 } 3292 } 3293 3294 @Override 3295 protected boolean shouldDisableNavbarGestures() { 3296 return !isDeviceProvisioned() 3297 || mExpandedVisible 3298 || (mDisabled & StatusBarManager.DISABLE_SEARCH) != 0; 3299 } 3300 3301 public void postStartSettingsActivity(final Intent intent, int delay) { 3302 mHandler.postDelayed(new Runnable() { 3303 @Override 3304 public void run() { 3305 handleStartSettingsActivity(intent, true /*onlyProvisioned*/); 3306 } 3307 }, delay); 3308 } 3309 3310 private void handleStartSettingsActivity(Intent intent, boolean onlyProvisioned) { 3311 startActivityDismissingKeyguard(intent, onlyProvisioned, true /* dismissShade */, 3312 false /* afterKeyguardGone */); 3313 } 3314 3315 private static class FastColorDrawable extends Drawable { 3316 private final int mColor; 3317 3318 public FastColorDrawable(int color) { 3319 mColor = 0xff000000 | color; 3320 } 3321 3322 @Override 3323 public void draw(Canvas canvas) { 3324 canvas.drawColor(mColor, PorterDuff.Mode.SRC); 3325 } 3326 3327 @Override 3328 public void setAlpha(int alpha) { 3329 } 3330 3331 @Override 3332 public void setColorFilter(ColorFilter cf) { 3333 } 3334 3335 @Override 3336 public int getOpacity() { 3337 return PixelFormat.OPAQUE; 3338 } 3339 3340 @Override 3341 public void setBounds(int left, int top, int right, int bottom) { 3342 } 3343 3344 @Override 3345 public void setBounds(Rect bounds) { 3346 } 3347 } 3348 3349 @Override 3350 public void destroy() { 3351 super.destroy(); 3352 if (mStatusBarWindow != null) { 3353 mWindowManager.removeViewImmediate(mStatusBarWindow); 3354 mStatusBarWindow = null; 3355 } 3356 if (mNavigationBarView != null) { 3357 mWindowManager.removeViewImmediate(mNavigationBarView); 3358 mNavigationBarView = null; 3359 } 3360 mContext.unregisterReceiver(mBroadcastReceiver); 3361 } 3362 3363 private boolean mDemoModeAllowed; 3364 private boolean mDemoMode; 3365 private DemoStatusIcons mDemoStatusIcons; 3366 3367 @Override 3368 public void dispatchDemoCommand(String command, Bundle args) { 3369 if (!mDemoModeAllowed) { 3370 mDemoModeAllowed = Settings.Global.getInt(mContext.getContentResolver(), 3371 "sysui_demo_allowed", 0) != 0; 3372 } 3373 if (!mDemoModeAllowed) return; 3374 if (command.equals(COMMAND_ENTER)) { 3375 mDemoMode = true; 3376 } else if (command.equals(COMMAND_EXIT)) { 3377 mDemoMode = false; 3378 checkBarModes(); 3379 } else if (!mDemoMode) { 3380 // automatically enter demo mode on first demo command 3381 dispatchDemoCommand(COMMAND_ENTER, new Bundle()); 3382 } 3383 boolean modeChange = command.equals(COMMAND_ENTER) || command.equals(COMMAND_EXIT); 3384 if (modeChange || command.equals(COMMAND_CLOCK)) { 3385 dispatchDemoCommandToView(command, args, R.id.clock); 3386 } 3387 if (modeChange || command.equals(COMMAND_BATTERY)) { 3388 dispatchDemoCommandToView(command, args, R.id.battery); 3389 } 3390 if (modeChange || command.equals(COMMAND_STATUS)) { 3391 if (mDemoStatusIcons == null) { 3392 mDemoStatusIcons = new DemoStatusIcons(mStatusIcons, mIconSize); 3393 } 3394 mDemoStatusIcons.dispatchDemoCommand(command, args); 3395 } 3396 if (mNetworkController != null && (modeChange || command.equals(COMMAND_NETWORK))) { 3397 mNetworkController.dispatchDemoCommand(command, args); 3398 } 3399 if (modeChange || command.equals(COMMAND_NOTIFICATIONS)) { 3400 View notifications = mStatusBarView == null ? null 3401 : mStatusBarView.findViewById(R.id.notification_icon_area); 3402 if (notifications != null) { 3403 String visible = args.getString("visible"); 3404 int vis = mDemoMode && "false".equals(visible) ? View.INVISIBLE : View.VISIBLE; 3405 notifications.setVisibility(vis); 3406 } 3407 } 3408 if (command.equals(COMMAND_BARS)) { 3409 String mode = args.getString("mode"); 3410 int barMode = "opaque".equals(mode) ? MODE_OPAQUE : 3411 "translucent".equals(mode) ? MODE_TRANSLUCENT : 3412 "semi-transparent".equals(mode) ? MODE_SEMI_TRANSPARENT : 3413 "transparent".equals(mode) ? MODE_TRANSPARENT : 3414 "warning".equals(mode) ? MODE_WARNING : 3415 -1; 3416 if (barMode != -1) { 3417 boolean animate = true; 3418 if (mStatusBarView != null) { 3419 mStatusBarView.getBarTransitions().transitionTo(barMode, animate); 3420 } 3421 if (mNavigationBarView != null) { 3422 mNavigationBarView.getBarTransitions().transitionTo(barMode, animate); 3423 } 3424 } 3425 } 3426 } 3427 3428 private void dispatchDemoCommandToView(String command, Bundle args, int id) { 3429 if (mStatusBarView == null) return; 3430 View v = mStatusBarView.findViewById(id); 3431 if (v instanceof DemoMode) { 3432 ((DemoMode)v).dispatchDemoCommand(command, args); 3433 } 3434 } 3435 3436 /** 3437 * @return The {@link StatusBarState} the status bar is in. 3438 */ 3439 public int getBarState() { 3440 return mState; 3441 } 3442 3443 public void showKeyguard() { 3444 setBarState(StatusBarState.KEYGUARD); 3445 updateKeyguardState(false /* goingToFullShade */, false /* fromShadeLocked */); 3446 instantExpandNotificationsPanel(); 3447 mLeaveOpenOnKeyguardHide = false; 3448 if (mDraggedDownRow != null) { 3449 mDraggedDownRow.setUserLocked(false); 3450 mDraggedDownRow.notifyHeightChanged(); 3451 mDraggedDownRow = null; 3452 } 3453 } 3454 3455 public boolean isCollapsing() { 3456 return mNotificationPanel.isCollapsing(); 3457 } 3458 3459 public void addPostCollapseAction(Runnable r) { 3460 mPostCollapseRunnables.add(r); 3461 } 3462 3463 public boolean isInLaunchTransition() { 3464 return mNotificationPanel.isLaunchTransitionRunning() 3465 || mNotificationPanel.isLaunchTransitionFinished(); 3466 } 3467 3468 /** 3469 * Fades the content of the keyguard away after the launch transition is done. 3470 * 3471 * @param beforeFading the runnable to be run when the circle is fully expanded and the fading 3472 * starts 3473 * @param endRunnable the runnable to be run when the transition is done 3474 */ 3475 public void fadeKeyguardAfterLaunchTransition(final Runnable beforeFading, 3476 final Runnable endRunnable) { 3477 Runnable hideRunnable = new Runnable() { 3478 @Override 3479 public void run() { 3480 mLaunchTransitionFadingAway = true; 3481 if (beforeFading != null) { 3482 beforeFading.run(); 3483 } 3484 mNotificationPanel.setAlpha(1); 3485 mNotificationPanel.animate() 3486 .alpha(0) 3487 .setStartDelay(FADE_KEYGUARD_START_DELAY) 3488 .setDuration(FADE_KEYGUARD_DURATION) 3489 .withLayer() 3490 .withEndAction(new Runnable() { 3491 @Override 3492 public void run() { 3493 mNotificationPanel.setAlpha(1); 3494 if (endRunnable != null) { 3495 endRunnable.run(); 3496 } 3497 mLaunchTransitionFadingAway = false; 3498 } 3499 }); 3500 } 3501 }; 3502 if (mNotificationPanel.isLaunchTransitionRunning()) { 3503 mNotificationPanel.setLaunchTransitionEndRunnable(hideRunnable); 3504 } else { 3505 hideRunnable.run(); 3506 } 3507 } 3508 3509 /** 3510 * @return true if we would like to stay in the shade, false if it should go away entirely 3511 */ 3512 public boolean hideKeyguard() { 3513 boolean staying = mLeaveOpenOnKeyguardHide; 3514 setBarState(StatusBarState.SHADE); 3515 if (mLeaveOpenOnKeyguardHide) { 3516 mLeaveOpenOnKeyguardHide = false; 3517 mNotificationPanel.animateToFullShade(calculateGoingToFullShadeDelay()); 3518 if (mDraggedDownRow != null) { 3519 mDraggedDownRow.setUserLocked(false); 3520 mDraggedDownRow = null; 3521 } 3522 } else { 3523 instantCollapseNotificationPanel(); 3524 } 3525 updateKeyguardState(staying, false /* fromShadeLocked */); 3526 return staying; 3527 } 3528 3529 public long calculateGoingToFullShadeDelay() { 3530 return mKeyguardFadingAwayDelay + mKeyguardFadingAwayDuration; 3531 } 3532 3533 /** 3534 * Notifies the status bar the Keyguard is fading away with the specified timings. 3535 * 3536 * @param delay the animation delay in miliseconds 3537 * @param fadeoutDuration the duration of the exit animation, in milliseconds 3538 */ 3539 public void setKeyguardFadingAway(long delay, long fadeoutDuration) { 3540 mKeyguardFadingAway = true; 3541 mKeyguardFadingAwayDelay = delay; 3542 mKeyguardFadingAwayDuration = fadeoutDuration; 3543 mWaitingForKeyguardExit = false; 3544 disable(mDisabledUnmodified, true /* animate */); 3545 } 3546 3547 /** 3548 * Notifies that the Keyguard fading away animation is done. 3549 */ 3550 public void finishKeyguardFadingAway() { 3551 mKeyguardFadingAway = false; 3552 } 3553 3554 private void updatePublicMode() { 3555 setLockscreenPublicMode( 3556 (mStatusBarKeyguardViewManager.isShowing() || 3557 mStatusBarKeyguardViewManager.isOccluded()) 3558 && mStatusBarKeyguardViewManager.isSecure()); 3559 } 3560 3561 private void updateKeyguardState(boolean goingToFullShade, boolean fromShadeLocked) { 3562 if (mState == StatusBarState.KEYGUARD) { 3563 mKeyguardIndicationController.setVisible(true); 3564 mNotificationPanel.resetViews(); 3565 mKeyguardUserSwitcher.setKeyguard(true, fromShadeLocked); 3566 } else { 3567 mKeyguardIndicationController.setVisible(false); 3568 mKeyguardUserSwitcher.setKeyguard(false, 3569 goingToFullShade || mState == StatusBarState.SHADE_LOCKED || fromShadeLocked); 3570 } 3571 if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) { 3572 mScrimController.setKeyguardShowing(true); 3573 } else { 3574 mScrimController.setKeyguardShowing(false); 3575 } 3576 mNotificationPanel.setBarState(mState, mKeyguardFadingAway, goingToFullShade); 3577 updateDozingState(); 3578 updatePublicMode(); 3579 updateStackScrollerState(goingToFullShade); 3580 updateNotifications(); 3581 checkBarModes(); 3582 updateCarrierLabelVisibility(false); 3583 updateMediaMetaData(false); 3584 mKeyguardMonitor.notifyKeyguardState(mStatusBarKeyguardViewManager.isShowing(), 3585 mStatusBarKeyguardViewManager.isSecure()); 3586 } 3587 3588 private void updateDozingState() { 3589 if (mState != StatusBarState.KEYGUARD) { 3590 return; 3591 } 3592 mNotificationPanel.setDozing(mDozing); 3593 if (mDozing) { 3594 mKeyguardBottomArea.setVisibility(View.INVISIBLE); 3595 mStackScroller.setDark(true, false /*animate*/); 3596 } else { 3597 mKeyguardBottomArea.setVisibility(View.VISIBLE); 3598 mStackScroller.setDark(false, false /*animate*/); 3599 } 3600 mScrimController.setDozing(mDozing); 3601 } 3602 3603 public void updateStackScrollerState(boolean goingToFullShade) { 3604 if (mStackScroller == null) return; 3605 boolean onKeyguard = mState == StatusBarState.KEYGUARD; 3606 mStackScroller.setHideSensitive(isLockscreenPublicMode(), goingToFullShade); 3607 mStackScroller.setDimmed(onKeyguard, false /* animate */); 3608 mStackScroller.setExpandingEnabled(!onKeyguard); 3609 ActivatableNotificationView activatedChild = mStackScroller.getActivatedChild(); 3610 mStackScroller.setActivatedChild(null); 3611 if (activatedChild != null) { 3612 activatedChild.makeInactive(false /* animate */); 3613 } 3614 } 3615 3616 public void userActivity() { 3617 if (mState == StatusBarState.KEYGUARD) { 3618 mKeyguardViewMediatorCallback.userActivity(); 3619 } 3620 } 3621 3622 public boolean interceptMediaKey(KeyEvent event) { 3623 return mState == StatusBarState.KEYGUARD 3624 && mStatusBarKeyguardViewManager.interceptMediaKey(event); 3625 } 3626 3627 public boolean onMenuPressed() { 3628 return mState == StatusBarState.KEYGUARD && mStatusBarKeyguardViewManager.onMenuPressed(); 3629 } 3630 3631 public boolean onBackPressed() { 3632 if (mStatusBarKeyguardViewManager.onBackPressed()) { 3633 return true; 3634 } 3635 if (mNotificationPanel.isQsExpanded()) { 3636 if (mNotificationPanel.isQsDetailShowing()) { 3637 mNotificationPanel.closeQsDetail(); 3638 } else { 3639 mNotificationPanel.animateCloseQs(); 3640 } 3641 return true; 3642 } 3643 if (mState != StatusBarState.KEYGUARD && mState != StatusBarState.SHADE_LOCKED) { 3644 animateCollapsePanels(); 3645 return true; 3646 } 3647 return false; 3648 } 3649 3650 public boolean onSpacePressed() { 3651 if (mScreenOn != null && mScreenOn 3652 && (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)) { 3653 animateCollapsePanels(0 /* flags */, true /* force */); 3654 return true; 3655 } 3656 return false; 3657 } 3658 3659 private void showBouncer() { 3660 if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) { 3661 mWaitingForKeyguardExit = mStatusBarKeyguardViewManager.isShowing(); 3662 mStatusBarKeyguardViewManager.dismiss(); 3663 } 3664 } 3665 3666 private void instantExpandNotificationsPanel() { 3667 3668 // Make our window larger and the panel expanded. 3669 makeExpandedVisible(true); 3670 mNotificationPanel.instantExpand(); 3671 } 3672 3673 private void instantCollapseNotificationPanel() { 3674 mNotificationPanel.setExpandedFraction(0); 3675 } 3676 3677 @Override 3678 public void onActivated(ActivatableNotificationView view) { 3679 mKeyguardIndicationController.showTransientIndication(R.string.notification_tap_again); 3680 ActivatableNotificationView previousView = mStackScroller.getActivatedChild(); 3681 if (previousView != null) { 3682 previousView.makeInactive(true /* animate */); 3683 } 3684 mStackScroller.setActivatedChild(view); 3685 } 3686 3687 /** 3688 * @param state The {@link StatusBarState} to set. 3689 */ 3690 public void setBarState(int state) { 3691 mState = state; 3692 mStatusBarWindowManager.setStatusBarState(state); 3693 } 3694 3695 @Override 3696 public void onActivationReset(ActivatableNotificationView view) { 3697 if (view == mStackScroller.getActivatedChild()) { 3698 mKeyguardIndicationController.hideTransientIndication(); 3699 mStackScroller.setActivatedChild(null); 3700 } 3701 } 3702 3703 public void onTrackingStarted() { 3704 runPostCollapseRunnables(); 3705 } 3706 3707 public void onUnlockHintStarted() { 3708 mKeyguardIndicationController.showTransientIndication(R.string.keyguard_unlock); 3709 } 3710 3711 public void onHintFinished() { 3712 // Delay the reset a bit so the user can read the text. 3713 mKeyguardIndicationController.hideTransientIndicationDelayed(HINT_RESET_DELAY_MS); 3714 } 3715 3716 public void onCameraHintStarted() { 3717 mKeyguardIndicationController.showTransientIndication(R.string.camera_hint); 3718 } 3719 3720 public void onPhoneHintStarted() { 3721 mKeyguardIndicationController.showTransientIndication(R.string.phone_hint); 3722 } 3723 3724 public void onTrackingStopped(boolean expand) { 3725 if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) { 3726 if (!expand && !mUnlockMethodCache.isMethodInsecure()) { 3727 showBouncer(); 3728 } 3729 } 3730 } 3731 3732 @Override 3733 protected int getMaxKeyguardNotifications() { 3734 return mKeyguardMaxNotificationCount; 3735 } 3736 3737 public NavigationBarView getNavigationBarView() { 3738 return mNavigationBarView; 3739 } 3740 3741 // ---------------------- DragDownHelper.OnDragDownListener ------------------------------------ 3742 3743 @Override 3744 public boolean onDraggedDown(View startingChild) { 3745 if (hasActiveNotifications()) { 3746 3747 // We have notifications, go to locked shade. 3748 goToLockedShade(startingChild); 3749 return true; 3750 } else { 3751 3752 // No notifications - abort gesture. 3753 return false; 3754 } 3755 } 3756 3757 @Override 3758 public void onDragDownReset() { 3759 mStackScroller.setDimmed(true /* dimmed */, true /* animated */); 3760 } 3761 3762 @Override 3763 public void onThresholdReached() { 3764 mStackScroller.setDimmed(false /* dimmed */, true /* animate */); 3765 } 3766 3767 @Override 3768 public void onTouchSlopExceeded() { 3769 mStackScroller.removeLongPressCallback(); 3770 } 3771 3772 @Override 3773 public void setEmptyDragAmount(float amount) { 3774 mNotificationPanel.setEmptyDragAmount(amount); 3775 } 3776 3777 /** 3778 * If secure with redaction: Show bouncer, go to unlocked shade. 3779 * 3780 * <p>If secure without redaction or no security: Go to {@link StatusBarState#SHADE_LOCKED}.</p> 3781 * 3782 * @param expandView The view to expand after going to the shade. 3783 */ 3784 public void goToLockedShade(View expandView) { 3785 ExpandableNotificationRow row = null; 3786 if (expandView instanceof ExpandableNotificationRow) { 3787 row = (ExpandableNotificationRow) expandView; 3788 row.setUserExpanded(true); 3789 } 3790 boolean fullShadeNeedsBouncer = !userAllowsPrivateNotificationsInPublic(mCurrentUserId) 3791 || !mShowLockscreenNotifications; 3792 if (isLockscreenPublicMode() && fullShadeNeedsBouncer) { 3793 mLeaveOpenOnKeyguardHide = true; 3794 showBouncer(); 3795 mDraggedDownRow = row; 3796 } else { 3797 mNotificationPanel.animateToFullShade(0 /* delay */); 3798 setBarState(StatusBarState.SHADE_LOCKED); 3799 updateKeyguardState(false /* goingToFullShade */, false /* fromShadeLocked */); 3800 if (row != null) { 3801 row.setUserLocked(false); 3802 } 3803 } 3804 } 3805 3806 /** 3807 * Goes back to the keyguard after hanging around in {@link StatusBarState#SHADE_LOCKED}. 3808 */ 3809 public void goToKeyguard() { 3810 if (mState == StatusBarState.SHADE_LOCKED) { 3811 mStackScroller.onGoToKeyguard(); 3812 setBarState(StatusBarState.KEYGUARD); 3813 updateKeyguardState(false /* goingToFullShade */, true /* fromShadeLocked*/); 3814 } 3815 } 3816 3817 /** 3818 * @return a ViewGroup that spans the entire panel which contains the quick settings 3819 */ 3820 public ViewGroup getQuickSettingsOverlayParent() { 3821 return mNotificationPanel; 3822 } 3823 3824 public long getKeyguardFadingAwayDelay() { 3825 return mKeyguardFadingAwayDelay; 3826 } 3827 3828 public long getKeyguardFadingAwayDuration() { 3829 return mKeyguardFadingAwayDuration; 3830 } 3831 3832 public LinearLayout getSystemIcons() { 3833 return mSystemIcons; 3834 } 3835 3836 public LinearLayout getSystemIconArea() { 3837 return mSystemIconArea; 3838 } 3839 3840 @Override 3841 public void setBouncerShowing(boolean bouncerShowing) { 3842 super.setBouncerShowing(bouncerShowing); 3843 disable(mDisabledUnmodified, true /* animate */); 3844 } 3845 3846 public void onScreenTurnedOff() { 3847 mStackScroller.setAnimationsEnabled(false); 3848 } 3849 3850 public void onScreenTurnedOn() { 3851 mStackScroller.setAnimationsEnabled(true); 3852 mNotificationPanel.onScreenTurnedOn(); 3853 } 3854 3855 /** 3856 * This handles long-press of both back and recents. They are 3857 * handled together to capture them both being long-pressed 3858 * at the same time to exit screen pinning (lock task). 3859 * 3860 * When accessibility mode is on, only a long-press from recents 3861 * is required to exit. 3862 * 3863 * In all other circumstances we try to pass through long-press events 3864 * for Back, so that apps can still use it. Which can be from two things. 3865 * 1) Not currently in screen pinning (lock task). 3866 * 2) Back is long-pressed without recents. 3867 */ 3868 private void handleLongPressBackRecents(View v) { 3869 try { 3870 boolean sendBackLongPress = false; 3871 IActivityManager activityManager = ActivityManagerNative.getDefault(); 3872 if (mAccessibilityManager == null) { 3873 mAccessibilityManager = (AccessibilityManager) 3874 mContext.getSystemService(Context.ACCESSIBILITY_SERVICE); 3875 } 3876 boolean isAccessiblityEnabled = mAccessibilityManager.isEnabled(); 3877 if (activityManager.isInLockTaskMode() && !isAccessiblityEnabled) { 3878 long time = System.currentTimeMillis(); 3879 // If we recently long-pressed the other button then they were 3880 // long-pressed 'together' 3881 if ((time - mLastLockToAppLongPress) < LOCK_TO_APP_GESTURE_TOLERENCE) { 3882 activityManager.stopLockTaskModeOnCurrent(); 3883 } else if ((v.getId() == R.id.back) 3884 && !mNavigationBarView.getRecentsButton().isPressed()) { 3885 // If we aren't pressing recents right now then they presses 3886 // won't be together, so send the standard long-press action. 3887 sendBackLongPress = true; 3888 } 3889 mLastLockToAppLongPress = time; 3890 } else { 3891 // If this is back still need to handle sending the long-press event. 3892 if (v.getId() == R.id.back) { 3893 sendBackLongPress = true; 3894 } else if (isAccessiblityEnabled && activityManager.isInLockTaskMode()) { 3895 // When in accessibility mode a long press that is recents (not back) 3896 // should stop lock task. 3897 activityManager.stopLockTaskModeOnCurrent(); 3898 } 3899 } 3900 if (sendBackLongPress) { 3901 KeyButtonView keyButtonView = (KeyButtonView) v; 3902 keyButtonView.sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.FLAG_LONG_PRESS); 3903 keyButtonView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); 3904 } 3905 } catch (RemoteException e) { 3906 Log.d(TAG, "Unable to reach activity manager", e); 3907 } 3908 } 3909 3910 // Recents 3911 3912 @Override 3913 protected void showRecents(boolean triggeredFromAltTab) { 3914 // Set the recents visibility flag 3915 mSystemUiVisibility |= View.RECENT_APPS_VISIBLE; 3916 notifyUiVisibilityChanged(mSystemUiVisibility); 3917 super.showRecents(triggeredFromAltTab); 3918 } 3919 3920 @Override 3921 protected void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) { 3922 // Unset the recents visibility flag 3923 mSystemUiVisibility &= ~View.RECENT_APPS_VISIBLE; 3924 notifyUiVisibilityChanged(mSystemUiVisibility); 3925 super.hideRecents(triggeredFromAltTab, triggeredFromHomeKey); 3926 } 3927 3928 @Override 3929 protected void toggleRecents() { 3930 // Toggle the recents visibility flag 3931 mSystemUiVisibility ^= View.RECENT_APPS_VISIBLE; 3932 notifyUiVisibilityChanged(mSystemUiVisibility); 3933 super.toggleRecents(); 3934 } 3935 3936 @Override 3937 public void onVisibilityChanged(boolean visible) { 3938 // Update the recents visibility flag 3939 if (visible) { 3940 mSystemUiVisibility |= View.RECENT_APPS_VISIBLE; 3941 } else { 3942 mSystemUiVisibility &= ~View.RECENT_APPS_VISIBLE; 3943 } 3944 notifyUiVisibilityChanged(mSystemUiVisibility); 3945 } 3946 3947 public boolean hasActiveNotifications() { 3948 return !mNotificationData.getActiveNotifications().isEmpty(); 3949 } 3950 3951 private final class ShadeUpdates { 3952 private final ArraySet<String> mVisibleNotifications = new ArraySet<String>(); 3953 private final ArraySet<String> mNewVisibleNotifications = new ArraySet<String>(); 3954 3955 public void check() { 3956 mNewVisibleNotifications.clear(); 3957 ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications(); 3958 for (int i = 0; i < activeNotifications.size(); i++) { 3959 final Entry entry = activeNotifications.get(i); 3960 final boolean visible = entry.row != null 3961 && entry.row.getVisibility() == View.VISIBLE; 3962 if (visible) { 3963 mNewVisibleNotifications.add(entry.key + entry.notification.getPostTime()); 3964 } 3965 } 3966 final boolean updates = !mVisibleNotifications.containsAll(mNewVisibleNotifications); 3967 mVisibleNotifications.clear(); 3968 mVisibleNotifications.addAll(mNewVisibleNotifications); 3969 3970 // We have new notifications 3971 if (updates && mDozeServiceHost != null) { 3972 mDozeServiceHost.fireNewNotifications(); 3973 } 3974 } 3975 } 3976 3977 private final class DozeServiceHost implements DozeService.Host { 3978 // Amount of time to allow to update the time shown on the screen before releasing 3979 // the wakelock. This timeout is design to compensate for the fact that we don't 3980 // currently have a way to know when time display contents have actually been 3981 // refreshed once we've finished rendering a new frame. 3982 private static final long PROCESSING_TIME = 500; 3983 3984 private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>(); 3985 private final H mHandler = new H(); 3986 3987 private DozeService mCurrentDozeService; 3988 3989 @Override 3990 public String toString() { 3991 return "PSB.DozeServiceHost[mCallbacks=" + mCallbacks.size() + " mCurrentDozeService=" 3992 + mCurrentDozeService + "]"; 3993 } 3994 3995 public void firePowerSaveChanged(boolean active) { 3996 for (Callback callback : mCallbacks) { 3997 callback.onPowerSaveChanged(active); 3998 } 3999 } 4000 4001 public void fireBuzzBeepBlinked() { 4002 for (Callback callback : mCallbacks) { 4003 callback.onBuzzBeepBlinked(); 4004 } 4005 } 4006 4007 public void fireNotificationLight(boolean on) { 4008 for (Callback callback : mCallbacks) { 4009 callback.onNotificationLight(on); 4010 } 4011 } 4012 4013 public void fireNewNotifications() { 4014 for (Callback callback : mCallbacks) { 4015 callback.onNewNotifications(); 4016 } 4017 } 4018 4019 @Override 4020 public void addCallback(Callback callback) { 4021 mCallbacks.add(callback); 4022 } 4023 4024 @Override 4025 public void removeCallback(Callback callback) { 4026 mCallbacks.remove(callback); 4027 } 4028 4029 @Override 4030 public void requestDoze(DozeService dozeService) { 4031 if (dozeService == null) return; 4032 dozeService.stayAwake(PROCESSING_TIME); 4033 mHandler.obtainMessage(H.REQUEST_DOZE, dozeService).sendToTarget(); 4034 } 4035 4036 @Override 4037 public void requestPulse(int pulses, boolean delayed, DozeService dozeService) { 4038 if (dozeService == null) return; 4039 dozeService.stayAwake(PROCESSING_TIME); 4040 mHandler.obtainMessage(H.REQUEST_PULSE, pulses, delayed ? 1 : 0, dozeService) 4041 .sendToTarget(); 4042 } 4043 4044 @Override 4045 public void dozingStopped(DozeService dozeService) { 4046 if (dozeService == null) return; 4047 dozeService.stayAwake(PROCESSING_TIME); 4048 mHandler.obtainMessage(H.DOZING_STOPPED, dozeService).sendToTarget(); 4049 } 4050 4051 @Override 4052 public boolean isPowerSaveActive() { 4053 return mBatteryController != null && mBatteryController.isPowerSave(); 4054 } 4055 4056 private void handleRequestDoze(DozeService dozeService) { 4057 mCurrentDozeService = dozeService; 4058 if (!mDozing) { 4059 mDozing = true; 4060 updateDozingState(); 4061 } 4062 mCurrentDozeService.startDozing(); 4063 } 4064 4065 private void handleRequestPulse(int pulses, boolean delayed, DozeService dozeService) { 4066 if (!dozeService.equals(mCurrentDozeService)) return; 4067 final long stayAwake = mScrimController.pulse(pulses, delayed); 4068 mCurrentDozeService.stayAwake(stayAwake); 4069 } 4070 4071 private void handleDozingStopped(DozeService dozeService) { 4072 if (dozeService.equals(mCurrentDozeService)) { 4073 mCurrentDozeService = null; 4074 } 4075 if (mDozing) { 4076 mDozing = false; 4077 updateDozingState(); 4078 } 4079 } 4080 4081 private final class H extends Handler { 4082 private static final int REQUEST_DOZE = 1; 4083 private static final int REQUEST_PULSE = 2; 4084 private static final int DOZING_STOPPED = 3; 4085 4086 @Override 4087 public void handleMessage(Message msg) { 4088 if (msg.what == REQUEST_DOZE) { 4089 handleRequestDoze((DozeService) msg.obj); 4090 } else if (msg.what == REQUEST_PULSE) { 4091 handleRequestPulse(msg.arg1, msg.arg2 != 0, (DozeService) msg.obj); 4092 } else if (msg.what == DOZING_STOPPED) { 4093 handleDozingStopped((DozeService) msg.obj); 4094 } 4095 } 4096 } 4097 } 4098} 4099