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