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