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