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