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