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