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