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