PhoneStatusBar.java revision d42a6cfe2bf632222617450a1ed340268e82f06c
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.keyguard.KeyguardHostView.OnDismissAction; 26import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT; 27import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE; 28import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT; 29import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSLUCENT; 30import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT; 31 32import android.animation.Animator; 33import android.animation.AnimatorListenerAdapter; 34import android.animation.TimeInterpolator; 35import android.animation.ValueAnimator; 36import android.app.ActivityManager; 37import android.app.ActivityManagerNative; 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.Canvas; 49import android.graphics.ColorFilter; 50import android.graphics.PixelFormat; 51import android.graphics.Point; 52import android.graphics.PorterDuff; 53import android.graphics.Rect; 54import android.graphics.drawable.Drawable; 55import android.inputmethodservice.InputMethodService; 56import android.media.AudioManager; 57import android.os.Bundle; 58import android.os.Handler; 59import android.os.IBinder; 60import android.os.Message; 61import android.os.PowerManager; 62import android.os.RemoteException; 63import android.os.SystemClock; 64import android.os.UserHandle; 65import android.provider.Settings; 66import android.provider.Settings.Global; 67import android.service.notification.NotificationListenerService.RankingMap; 68import android.service.notification.StatusBarNotification; 69import android.util.ArraySet; 70import android.util.DisplayMetrics; 71import android.util.EventLog; 72import android.util.Log; 73import android.view.Display; 74import android.view.Gravity; 75import android.view.KeyEvent; 76import android.view.LayoutInflater; 77import android.view.MotionEvent; 78import android.view.VelocityTracker; 79import android.view.View; 80import android.view.ViewAnimationUtils; 81import android.view.ViewGroup; 82import android.view.ViewGroup.LayoutParams; 83import android.view.ViewPropertyAnimator; 84import android.view.ViewStub; 85import android.view.ViewTreeObserver; 86import android.view.WindowManager; 87import android.view.animation.AccelerateInterpolator; 88import android.view.animation.Animation; 89import android.view.animation.AnimationUtils; 90import android.view.animation.DecelerateInterpolator; 91import android.view.animation.Interpolator; 92import android.view.animation.PathInterpolator; 93import android.widget.FrameLayout; 94import android.widget.LinearLayout; 95import android.widget.TextView; 96 97import com.android.internal.statusbar.StatusBarIcon; 98import com.android.keyguard.ViewMediatorCallback; 99import com.android.systemui.DemoMode; 100import com.android.systemui.EventLogTags; 101import com.android.systemui.R; 102import com.android.systemui.keyguard.KeyguardViewMediator; 103import com.android.systemui.qs.CircularClipper; 104import com.android.systemui.qs.QSPanel; 105import com.android.systemui.qs.QSTile; 106import com.android.systemui.statusbar.ActivatableNotificationView; 107import com.android.systemui.statusbar.BaseStatusBar; 108import com.android.systemui.statusbar.CommandQueue; 109import com.android.systemui.statusbar.DragDownHelper; 110import com.android.systemui.statusbar.ExpandableNotificationRow; 111import com.android.systemui.statusbar.GestureRecorder; 112import com.android.systemui.statusbar.InterceptedNotifications; 113import com.android.systemui.statusbar.KeyguardIndicationController; 114import com.android.systemui.statusbar.NotificationData; 115import com.android.systemui.statusbar.NotificationData.Entry; 116import com.android.systemui.statusbar.NotificationOverflowContainer; 117import com.android.systemui.statusbar.SignalClusterView; 118import com.android.systemui.statusbar.SpeedBumpView; 119import com.android.systemui.statusbar.StatusBarIconView; 120import com.android.systemui.statusbar.StatusBarState; 121import com.android.systemui.statusbar.policy.BatteryController; 122import com.android.systemui.statusbar.policy.BluetoothControllerImpl; 123import com.android.systemui.statusbar.policy.CastControllerImpl; 124import com.android.systemui.statusbar.policy.DateView; 125import com.android.systemui.statusbar.policy.HeadsUpNotificationView; 126import com.android.systemui.statusbar.policy.UserInfoController; 127import com.android.systemui.statusbar.policy.LocationControllerImpl; 128import com.android.systemui.statusbar.policy.NetworkControllerImpl; 129import com.android.systemui.statusbar.policy.RotationLockControllerImpl; 130import com.android.systemui.statusbar.policy.ZenModeController; 131import com.android.systemui.statusbar.stack.NotificationStackScrollLayout; 132import com.android.systemui.statusbar.stack.NotificationStackScrollLayout.OnChildLocationsChangedListener; 133import com.android.systemui.statusbar.stack.StackScrollState.ViewState; 134import com.android.systemui.volume.VolumeComponent; 135 136import java.io.FileDescriptor; 137import java.io.PrintWriter; 138import java.util.ArrayList; 139import java.util.Collection; 140import java.util.Collections; 141 142public class PhoneStatusBar extends BaseStatusBar implements DemoMode, 143 DragDownHelper.OnDragDownListener, ActivityStarter { 144 static final String TAG = "PhoneStatusBar"; 145 public static final boolean DEBUG = BaseStatusBar.DEBUG; 146 public static final boolean SPEW = false; 147 public static final boolean DUMPTRUCK = true; // extra dumpsys info 148 public static final boolean DEBUG_GESTURES = false; 149 150 public static final boolean DEBUG_WINDOW_STATE = false; 151 152 public static final boolean SETTINGS_DRAG_SHORTCUT = true; 153 154 // additional instrumentation for testing purposes; intended to be left on during development 155 public static final boolean CHATTY = DEBUG; 156 157 public static final String ACTION_STATUSBAR_START 158 = "com.android.internal.policy.statusbar.START"; 159 160 private static final int MSG_OPEN_NOTIFICATION_PANEL = 1000; 161 private static final int MSG_CLOSE_PANELS = 1001; 162 private static final int MSG_OPEN_SETTINGS_PANEL = 1002; 163 // 1020-1030 reserved for BaseStatusBar 164 165 private static final boolean CLOSE_PANEL_WHEN_EMPTIED = true; 166 167 private static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10; // see NotificationManagerService 168 private static final int HIDE_ICONS_BELOW_SCORE = Notification.PRIORITY_LOW * NOTIFICATION_PRIORITY_MULTIPLIER; 169 170 /** 171 * Default value of {@link android.provider.Settings.Global#LOCK_SCREEN_SHOW_NOTIFICATIONS}. 172 */ 173 private static final boolean ALLOW_NOTIFICATIONS_DEFAULT = false; 174 175 private static final int STATUS_OR_NAV_TRANSIENT = 176 View.STATUS_BAR_TRANSIENT | View.NAVIGATION_BAR_TRANSIENT; 177 private static final long AUTOHIDE_TIMEOUT_MS = 3000; 178 179 /** The minimum delay in ms between reports of notification visibility. */ 180 private static final int VISIBILITY_REPORT_MIN_DELAY_MS = 500; 181 182 /** 183 * The delay to reset the hint text when the hint animation is finished running. 184 */ 185 private static final int HINT_RESET_DELAY_MS = 1200; 186 187 // fling gesture tuning parameters, scaled to display density 188 private float mSelfExpandVelocityPx; // classic value: 2000px/s 189 private float mSelfCollapseVelocityPx; // classic value: 2000px/s (will be negated to collapse "up") 190 private float mFlingExpandMinVelocityPx; // classic value: 200px/s 191 private float mFlingCollapseMinVelocityPx; // classic value: 200px/s 192 private float mCollapseMinDisplayFraction; // classic value: 0.08 (25px/min(320px,480px) on G1) 193 private float mExpandMinDisplayFraction; // classic value: 0.5 (drag open halfway to expand) 194 private float mFlingGestureMaxXVelocityPx; // classic value: 150px/s 195 196 private float mExpandAccelPx; // classic value: 2000px/s/s 197 private float mCollapseAccelPx; // classic value: 2000px/s/s (will be negated to collapse "up") 198 199 private float mFlingGestureMaxOutputVelocityPx; // how fast can it really go? (should be a little 200 // faster than mSelfCollapseVelocityPx) 201 202 PhoneStatusBarPolicy mIconPolicy; 203 204 // These are no longer handled by the policy, because we need custom strategies for them 205 BluetoothControllerImpl mBluetoothController; 206 BatteryController mBatteryController; 207 LocationControllerImpl mLocationController; 208 NetworkControllerImpl mNetworkController; 209 RotationLockControllerImpl mRotationLockController; 210 UserInfoController mUserInfoController; 211 ZenModeController mZenModeController; 212 CastControllerImpl mCastController; 213 VolumeComponent mVolumeComponent; 214 215 int mNaturalBarHeight = -1; 216 int mIconSize = -1; 217 int mIconHPadding = -1; 218 Display mDisplay; 219 Point mCurrentDisplaySize = new Point(); 220 221 StatusBarWindowView mStatusBarWindow; 222 PhoneStatusBarView mStatusBarView; 223 private int mStatusBarWindowState = WINDOW_STATE_SHOWING; 224 private StatusBarWindowManager mStatusBarWindowManager; 225 private UnlockMethodCache mUnlockMethodCache; 226 227 int mPixelFormat; 228 Object mQueueLock = new Object(); 229 230 // viewgroup containing the normal contents of the statusbar 231 LinearLayout mStatusBarContents; 232 233 // right-hand icons 234 LinearLayout mSystemIconArea; 235 LinearLayout mSystemIcons; 236 237 // left-hand icons 238 LinearLayout mStatusIcons; 239 // the icons themselves 240 IconMerger mNotificationIcons; 241 // [+> 242 View mMoreIcon; 243 244 // expanded notifications 245 NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window 246 View mExpandedContents; 247 int mNotificationPanelGravity; 248 int mNotificationPanelMarginBottomPx; 249 float mNotificationPanelMinHeightFrac; 250 TextView mNotificationPanelDebugText; 251 252 // settings 253 View mFlipSettingsView; 254 private QSPanel mQSPanel; 255 256 // top bar 257 StatusBarHeaderView mHeader; 258 View mKeyguardStatusView; 259 KeyguardBottomAreaView mKeyguardBottomArea; 260 boolean mLeaveOpenOnKeyguardHide; 261 KeyguardIndicationController mKeyguardIndicationController; 262 263 int mKeyguardMaxNotificationCount; 264 View mDateTimeView; 265 266 // carrier/wifi label 267 private TextView mCarrierLabel; 268 private boolean mCarrierLabelVisible = false; 269 private int mCarrierLabelHeight; 270 private int mStatusBarHeaderHeight; 271 272 private boolean mShowCarrierInPanel = false; 273 274 // position 275 int[] mPositionTmp = new int[2]; 276 boolean mExpandedVisible; 277 278 // the date view 279 DateView mDateView; 280 281 // on-screen navigation buttons 282 private NavigationBarView mNavigationBarView = null; 283 private int mNavigationBarWindowState = WINDOW_STATE_SHOWING; 284 285 // the tracker view 286 int mTrackingPosition; // the position of the top of the tracking view. 287 288 // ticker 289 private boolean mTickerEnabled; 290 private Ticker mTicker; 291 private View mTickerView; 292 private boolean mTicking; 293 294 // Tracking finger for opening/closing. 295 int mEdgeBorder; // corresponds to R.dimen.status_bar_edge_ignore 296 boolean mTracking; 297 VelocityTracker mVelocityTracker; 298 299 int[] mAbsPos = new int[2]; 300 Runnable mPostCollapseCleanup = null; 301 302 // for disabling the status bar 303 int mDisabled = 0; 304 305 // tracking calls to View.setSystemUiVisibility() 306 int mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE; 307 308 DisplayMetrics mDisplayMetrics = new DisplayMetrics(); 309 310 // XXX: gesture research 311 private final GestureRecorder mGestureRec = DEBUG_GESTURES 312 ? new GestureRecorder("/sdcard/statusbar_gestures.dat") 313 : null; 314 315 private int mNavigationIconHints = 0; 316 private final Animator.AnimatorListener mMakeIconsInvisible = new AnimatorListenerAdapter() { 317 @Override 318 public void onAnimationEnd(Animator animation) { 319 // double-check to avoid races 320 if (mStatusBarContents.getAlpha() == 0) { 321 if (DEBUG) Log.d(TAG, "makeIconsInvisible"); 322 mStatusBarContents.setVisibility(View.INVISIBLE); 323 } 324 } 325 }; 326 327 // ensure quick settings is disabled until the current user makes it through the setup wizard 328 private boolean mUserSetup = false; 329 private ContentObserver mUserSetupObserver = new ContentObserver(new Handler()) { 330 @Override 331 public void onChange(boolean selfChange) { 332 final boolean userSetup = 0 != Settings.Secure.getIntForUser( 333 mContext.getContentResolver(), 334 Settings.Secure.USER_SETUP_COMPLETE, 335 0 /*default */, 336 mCurrentUserId); 337 if (MULTIUSER_DEBUG) Log.d(TAG, String.format("User setup changed: " + 338 "selfChange=%s userSetup=%s mUserSetup=%s", 339 selfChange, userSetup, mUserSetup)); 340 341 if (userSetup != mUserSetup) { 342 mUserSetup = userSetup; 343 if (mNotificationPanel != null) { 344 mNotificationPanel.setQsExpansionEnabled(isDeviceProvisioned() && userSetup); 345 } 346 if (!mUserSetup && mStatusBarView != null) 347 animateCollapseQuickSettings(); 348 } 349 } 350 }; 351 352 final private ContentObserver mHeadsUpObserver = new ContentObserver(mHandler) { 353 @Override 354 public void onChange(boolean selfChange) { 355 boolean wasUsing = mUseHeadsUp; 356 mUseHeadsUp = ENABLE_HEADS_UP && Settings.Global.HEADS_UP_OFF != Settings.Global.getInt( 357 mContext.getContentResolver(), Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED, 358 Settings.Global.HEADS_UP_OFF); 359 mHeadsUpTicker = mUseHeadsUp && 0 != Settings.Global.getInt( 360 mContext.getContentResolver(), SETTING_HEADS_UP_TICKER, 0); 361 Log.d(TAG, "heads up is " + (mUseHeadsUp ? "enabled" : "disabled")); 362 if (wasUsing != mUseHeadsUp) { 363 if (!mUseHeadsUp) { 364 Log.d(TAG, "dismissing any existing heads up notification on disable event"); 365 setHeadsUpVisibility(false); 366 mHeadsUpNotificationView.release(); 367 removeHeadsUpView(); 368 } else { 369 addHeadsUpView(); 370 } 371 } 372 } 373 }; 374 375 private int mInteractingWindows; 376 private boolean mAutohideSuspended; 377 private int mStatusBarMode; 378 private int mNavigationBarMode; 379 private Boolean mScreenOn; 380 381 private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; 382 private ViewMediatorCallback mKeyguardViewMediatorCallback; 383 private ScrimController mScrimController; 384 385 private final Runnable mAutohide = new Runnable() { 386 @Override 387 public void run() { 388 int requested = mSystemUiVisibility & ~STATUS_OR_NAV_TRANSIENT; 389 if (mSystemUiVisibility != requested) { 390 notifyUiVisibilityChanged(requested); 391 } 392 }}; 393 394 private Runnable mOnFlipRunnable; 395 private InterceptedNotifications mIntercepted; 396 private VelocityTracker mSettingsTracker; 397 private float mSettingsDownY; 398 private boolean mSettingsStarted; 399 private boolean mSettingsCancelled; 400 private boolean mSettingsClosing; 401 private boolean mVisible; 402 403 private Interpolator mAlphaOut = new PathInterpolator(0f, 0.4f, 1f, 1f); 404 private Interpolator mAlphaIn = new PathInterpolator(0f, 0f, 0.8f, 1f); 405 406 private final OnChildLocationsChangedListener mOnChildLocationsChangedListener = 407 new OnChildLocationsChangedListener() { 408 @Override 409 public void onChildLocationsChanged(NotificationStackScrollLayout stackScrollLayout) { 410 userActivity(); 411 } 412 }; 413 414 private int mDisabledUnmodified; 415 416 public void setOnFlipRunnable(Runnable onFlipRunnable) { 417 mOnFlipRunnable = onFlipRunnable; 418 } 419 420 /** Keys of notifications currently visible to the user. */ 421 private final ArraySet<String> mCurrentlyVisibleNotifications = new ArraySet<String>(); 422 private long mLastVisibilityReportUptimeMs; 423 424 private static final int VISIBLE_LOCATIONS = ViewState.LOCATION_FIRST_CARD 425 | ViewState.LOCATION_TOP_STACK_PEEKING 426 | ViewState.LOCATION_MAIN_AREA 427 | ViewState.LOCATION_BOTTOM_STACK_PEEKING; 428 429 private final OnChildLocationsChangedListener mNotificationLocationsChangedListener = 430 new OnChildLocationsChangedListener() { 431 @Override 432 public void onChildLocationsChanged( 433 NotificationStackScrollLayout stackScrollLayout) { 434 if (mHandler.hasCallbacks(mVisibilityReporter)) { 435 // Visibilities will be reported when the existing 436 // callback is executed. 437 return; 438 } 439 // Calculate when we're allowed to run the visibility 440 // reporter. Note that this timestamp might already have 441 // passed. That's OK, the callback will just be executed 442 // ASAP. 443 long nextReportUptimeMs = 444 mLastVisibilityReportUptimeMs + VISIBILITY_REPORT_MIN_DELAY_MS; 445 mHandler.postAtTime(mVisibilityReporter, nextReportUptimeMs); 446 } 447 }; 448 449 // Tracks notifications currently visible in mNotificationStackScroller and 450 // emits visibility events via NoMan on changes. 451 private final Runnable mVisibilityReporter = new Runnable() { 452 private final ArrayList<String> mTmpNewlyVisibleNotifications = new ArrayList<String>(); 453 private final ArrayList<String> mTmpCurrentlyVisibleNotifications = new ArrayList<String>(); 454 455 @Override 456 public void run() { 457 mLastVisibilityReportUptimeMs = SystemClock.uptimeMillis(); 458 459 // 1. Loop over mNotificationData entries: 460 // A. Keep list of visible notifications. 461 // B. Keep list of previously hidden, now visible notifications. 462 // 2. Compute no-longer visible notifications by removing currently 463 // visible notifications from the set of previously visible 464 // notifications. 465 // 3. Report newly visible and no-longer visible notifications. 466 // 4. Keep currently visible notifications for next report. 467 int N = mNotificationData.size(); 468 for (int i = 0; i < N; i++) { 469 Entry entry = mNotificationData.get(i); 470 String key = entry.notification.getKey(); 471 boolean previouslyVisible = mCurrentlyVisibleNotifications.contains(key); 472 boolean currentlyVisible = 473 (mStackScroller.getChildLocation(entry.row) & VISIBLE_LOCATIONS) != 0; 474 if (currentlyVisible) { 475 // Build new set of visible notifications. 476 mTmpCurrentlyVisibleNotifications.add(key); 477 } 478 if (!previouslyVisible && currentlyVisible) { 479 mTmpNewlyVisibleNotifications.add(key); 480 } 481 } 482 ArraySet<String> noLongerVisibleNotifications = mCurrentlyVisibleNotifications; 483 noLongerVisibleNotifications.removeAll(mTmpCurrentlyVisibleNotifications); 484 485 logNotificationVisibilityChanges( 486 mTmpNewlyVisibleNotifications, noLongerVisibleNotifications); 487 488 mCurrentlyVisibleNotifications.clear(); 489 mCurrentlyVisibleNotifications.addAll(mTmpCurrentlyVisibleNotifications); 490 491 mTmpNewlyVisibleNotifications.clear(); 492 mTmpCurrentlyVisibleNotifications.clear(); 493 } 494 }; 495 496 private final View.OnClickListener mOverflowClickListener = new View.OnClickListener() { 497 @Override 498 public void onClick(View v) { 499 goToLockedShade(null); 500 } 501 }; 502 503 @Override 504 public void setZenMode(int mode) { 505 super.setZenMode(mode); 506 if (!isDeviceProvisioned()) return; 507 final boolean zen = mode != Settings.Global.ZEN_MODE_OFF; 508 if (!zen) { 509 mIntercepted.releaseIntercepted(); 510 } 511 if (mIconPolicy != null) { 512 mIconPolicy.setZenMode(zen); 513 } 514 } 515 516 @Override 517 protected void setShowLockscreenNotifications(boolean show) { 518 super.setShowLockscreenNotifications(show); 519 updateStackScrollerState(); 520 } 521 522 @Override 523 public void start() { 524 mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE)) 525 .getDefaultDisplay(); 526 updateDisplaySize(); 527 mIntercepted = new InterceptedNotifications(mContext, this); 528 super.start(); // calls createAndAddWindows() 529 530 addNavigationBar(); 531 532 // Lastly, call to the icon policy to install/update all the icons. 533 mIconPolicy = new PhoneStatusBarPolicy(mContext); 534 mSettingsObserver.onChange(false); // set up 535 536 mHeadsUpObserver.onChange(true); // set up 537 if (ENABLE_HEADS_UP) { 538 mContext.getContentResolver().registerContentObserver( 539 Settings.Global.getUriFor(Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED), true, 540 mHeadsUpObserver); 541 mContext.getContentResolver().registerContentObserver( 542 Settings.Global.getUriFor(SETTING_HEADS_UP_TICKER), true, 543 mHeadsUpObserver); 544 } 545 mUnlockMethodCache = UnlockMethodCache.getInstance(mContext); 546 startKeyguard(); 547 } 548 549 // ================================================================================ 550 // Constructing the view 551 // ================================================================================ 552 protected PhoneStatusBarView makeStatusBarView() { 553 final Context context = mContext; 554 555 Resources res = context.getResources(); 556 557 updateDisplaySize(); // populates mDisplayMetrics 558 loadDimens(); 559 560 mIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size); 561 562 mStatusBarWindow = (StatusBarWindowView) View.inflate(context, 563 R.layout.super_status_bar, null); 564 mStatusBarWindow.mService = this; 565 mStatusBarWindow.setOnTouchListener(new View.OnTouchListener() { 566 @Override 567 public boolean onTouch(View v, MotionEvent event) { 568 checkUserAutohide(v, event); 569 if (event.getAction() == MotionEvent.ACTION_DOWN) { 570 if (mExpandedVisible) { 571 animateCollapsePanels(); 572 } 573 } 574 return mStatusBarWindow.onTouchEvent(event); 575 }}); 576 577 mStatusBarView = (PhoneStatusBarView) mStatusBarWindow.findViewById(R.id.status_bar); 578 mStatusBarView.setBar(this); 579 580 PanelHolder holder = (PanelHolder) mStatusBarWindow.findViewById(R.id.panel_holder); 581 mStatusBarView.setPanelHolder(holder); 582 583 mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById( 584 R.id.notification_panel); 585 mNotificationPanel.setStatusBar(this); 586 587 // make the header non-responsive to clicks 588 mNotificationPanel.findViewById(R.id.header).setOnTouchListener( 589 new View.OnTouchListener() { 590 @Override 591 public boolean onTouch(View v, MotionEvent event) { 592 return true; // e eats everything 593 } 594 }); 595 596 if (!ActivityManager.isHighEndGfx()) { 597 mStatusBarWindow.setBackground(null); 598 mNotificationPanel.setBackground(new FastColorDrawable(context.getResources().getColor( 599 R.color.notification_panel_solid_background))); 600 } 601 if (ENABLE_HEADS_UP) { 602 mHeadsUpNotificationView = 603 (HeadsUpNotificationView) View.inflate(context, R.layout.heads_up, null); 604 mHeadsUpNotificationView.setVisibility(View.GONE); 605 mHeadsUpNotificationView.setBar(this); 606 } 607 if (MULTIUSER_DEBUG) { 608 mNotificationPanelDebugText = (TextView) mNotificationPanel.findViewById( 609 R.id.header_debug_info); 610 mNotificationPanelDebugText.setVisibility(View.VISIBLE); 611 } 612 613 updateShowSearchHoldoff(); 614 615 try { 616 boolean showNav = mWindowManagerService.hasNavigationBar(); 617 if (DEBUG) Log.v(TAG, "hasNavigationBar=" + showNav); 618 if (showNav) { 619 mNavigationBarView = 620 (NavigationBarView) View.inflate(context, R.layout.navigation_bar, null); 621 622 mNavigationBarView.setDisabledFlags(mDisabled); 623 mNavigationBarView.setBar(this); 624 mNavigationBarView.setOnTouchListener(new View.OnTouchListener() { 625 @Override 626 public boolean onTouch(View v, MotionEvent event) { 627 checkUserAutohide(v, event); 628 return false; 629 }}); 630 } 631 } catch (RemoteException ex) { 632 // no window manager? good luck with that 633 } 634 635 // figure out which pixel-format to use for the status bar. 636 mPixelFormat = PixelFormat.OPAQUE; 637 638 mSystemIconArea = (LinearLayout) mStatusBarView.findViewById(R.id.system_icon_area); 639 mSystemIcons = (LinearLayout) mStatusBarView.findViewById(R.id.system_icons); 640 mStatusIcons = (LinearLayout)mStatusBarView.findViewById(R.id.statusIcons); 641 mNotificationIcons = (IconMerger)mStatusBarView.findViewById(R.id.notificationIcons); 642 mMoreIcon = mStatusBarView.findViewById(R.id.moreIcon); 643 mNotificationIcons.setOverflowIndicator(mMoreIcon); 644 mStatusBarContents = (LinearLayout)mStatusBarView.findViewById(R.id.status_bar_contents); 645 646 mStackScroller = (NotificationStackScrollLayout) mStatusBarWindow.findViewById( 647 R.id.notification_stack_scroller); 648 mStackScroller.setLongPressListener(getNotificationLongClicker()); 649 mStackScroller.setChildLocationsChangedListener(mOnChildLocationsChangedListener); 650 651 mKeyguardIconOverflowContainer = 652 (NotificationOverflowContainer) LayoutInflater.from(mContext).inflate( 653 R.layout.status_bar_notification_keyguard_overflow, mStackScroller, false); 654 mKeyguardIconOverflowContainer.setOnActivatedListener(this); 655 mKeyguardIconOverflowContainer.setOnClickListener(mOverflowClickListener); 656 mStackScroller.addView(mKeyguardIconOverflowContainer); 657 658 SpeedBumpView speedBump = (SpeedBumpView) LayoutInflater.from(mContext).inflate( 659 R.layout.status_bar_notification_speed_bump, mStackScroller, false); 660 mStackScroller.setSpeedBumpView(speedBump); 661 mExpandedContents = mStackScroller; 662 663 mScrimController = new ScrimController(mStatusBarWindow.findViewById(R.id.scrim_behind), 664 mStatusBarWindow.findViewById(R.id.scrim_in_front)); 665 mStatusBarView.setScrimController(mScrimController); 666 667 mHeader = (StatusBarHeaderView) mStatusBarWindow.findViewById(R.id.header); 668 mHeader.setActivityStarter(this); 669 mKeyguardStatusView = mStatusBarWindow.findViewById(R.id.keyguard_status_view); 670 mKeyguardBottomArea = 671 (KeyguardBottomAreaView) mStatusBarWindow.findViewById(R.id.keyguard_bottom_area); 672 mKeyguardBottomArea.setActivityStarter(this); 673 mKeyguardIndicationController = new KeyguardIndicationController(mContext, 674 (KeyguardIndicationTextView) mStatusBarWindow.findViewById( 675 R.id.keyguard_indication_text)); 676 mDateView = (DateView)mStatusBarWindow.findViewById(R.id.date); 677 678 mDateTimeView = mHeader.findViewById(R.id.datetime); 679 if (mDateTimeView != null) { 680 mDateTimeView.setOnClickListener(mClockClickListener); 681 mDateTimeView.setEnabled(true); 682 } 683 684 mTickerEnabled = res.getBoolean(R.bool.enable_ticker); 685 if (mTickerEnabled) { 686 final ViewStub tickerStub = (ViewStub) mStatusBarView.findViewById(R.id.ticker_stub); 687 if (tickerStub != null) { 688 mTickerView = tickerStub.inflate(); 689 mTicker = new MyTicker(context, mStatusBarView); 690 691 TickerView tickerView = (TickerView) mStatusBarView.findViewById(R.id.tickerText); 692 tickerView.mTicker = mTicker; 693 } 694 } 695 696 mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore); 697 698 // set the inital view visibility 699 setAreThereNotifications(); 700 701 // Other icons 702 mLocationController = new LocationControllerImpl(mContext); // will post a notification 703 mBatteryController = new BatteryController(mContext); 704 mNetworkController = new NetworkControllerImpl(mContext); 705 mBluetoothController = new BluetoothControllerImpl(mContext); 706 if (mContext.getResources().getBoolean(R.bool.config_showRotationLock)) { 707 mRotationLockController = new RotationLockControllerImpl(mContext); 708 } 709 mUserInfoController = new UserInfoController(mContext); 710 mVolumeComponent = getComponent(VolumeComponent.class); 711 mZenModeController = mVolumeComponent.getZenController(); 712 mCastController = new CastControllerImpl(mContext); 713 final SignalClusterView signalCluster = 714 (SignalClusterView)mStatusBarView.findViewById(R.id.signal_cluster); 715 716 717 mNetworkController.addSignalCluster(signalCluster); 718 signalCluster.setNetworkController(mNetworkController); 719 final boolean isAPhone = mNetworkController.hasVoiceCallingFeature(); 720 if (isAPhone) { 721 mNetworkController.addEmergencyLabelView(mHeader); 722 } 723 724 mCarrierLabel = (TextView)mStatusBarWindow.findViewById(R.id.carrier_label); 725 mShowCarrierInPanel = (mCarrierLabel != null); 726 if (DEBUG) Log.v(TAG, "carrierlabel=" + mCarrierLabel + " show=" + mShowCarrierInPanel); 727 if (mShowCarrierInPanel) { 728 mCarrierLabel.setVisibility(mCarrierLabelVisible ? View.VISIBLE : View.INVISIBLE); 729 730 // for mobile devices, we always show mobile connection info here (SPN/PLMN) 731 // for other devices, we show whatever network is connected 732 if (mNetworkController.hasMobileDataFeature()) { 733 mNetworkController.addMobileLabelView(mCarrierLabel); 734 } else { 735 mNetworkController.addCombinedLabelView(mCarrierLabel); 736 } 737 738 // set up the dynamic hide/show of the label 739 // TODO: uncomment, handle this for the Stack scroller aswell 740// ((NotificationRowLayout) mStackScroller) 741// .setOnSizeChangedListener(new OnSizeChangedListener() { 742// @Override 743// public void onSizeChanged(View view, int w, int h, int oldw, int oldh) { 744// updateCarrierLabelVisibility(false); 745 } 746 747 mBatteryController.setStatusBarHeaderView(mHeader); 748 749 // Set up the quick settings tile panel 750 mQSPanel = (QSPanel) mStatusBarWindow.findViewById(R.id.quick_settings_panel); 751 if (mQSPanel != null) { 752 mQSPanel.setUtils(new CircularClipper.Utils() { 753 @Override 754 public ValueAnimator createRevealAnimator(View v, int centerX, int centerY, 755 float startRadius, float endRadius) { 756 return ViewAnimationUtils.createCircularReveal(v, centerX, centerY, 757 startRadius, endRadius); 758 } 759 }); 760 final QSTileHost qsh = new QSTileHost(mContext, this, 761 mBluetoothController, mLocationController, mRotationLockController, 762 mNetworkController, mZenModeController, null /*tethering*/, 763 mCastController, mVolumeComponent); 764 for (QSTile<?> tile : qsh.getTiles()) { 765 mQSPanel.addTile(tile); 766 } 767 mHeader.setQSPanel(mQSPanel); 768 } 769 770 // User info. Trigger first load. 771 mHeader.setUserInfoController(mUserInfoController); 772 mUserInfoController.reloadUserInfo(); 773 774 PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 775 mBroadcastReceiver.onReceive(mContext, 776 new Intent(pm.isScreenOn() ? Intent.ACTION_SCREEN_ON : Intent.ACTION_SCREEN_OFF)); 777 778 // receive broadcasts 779 IntentFilter filter = new IntentFilter(); 780 filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); 781 filter.addAction(Intent.ACTION_SCREEN_OFF); 782 filter.addAction(Intent.ACTION_SCREEN_ON); 783 filter.addAction(ACTION_DEMO); 784 context.registerReceiver(mBroadcastReceiver, filter); 785 786 // listen for USER_SETUP_COMPLETE setting (per-user) 787 resetUserSetupObserver(); 788 789 return mStatusBarView; 790 } 791 792 private void startKeyguard() { 793 KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class); 794 mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this, 795 mStatusBarWindow, mStatusBarWindowManager, mScrimController); 796 mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback(); 797 } 798 799 @Override 800 protected void onShowSearchPanel() { 801 if (mNavigationBarView != null) { 802 mNavigationBarView.getBarTransitions().setContentVisible(false); 803 } 804 } 805 806 @Override 807 protected void onHideSearchPanel() { 808 if (mNavigationBarView != null) { 809 mNavigationBarView.getBarTransitions().setContentVisible(true); 810 } 811 } 812 813 @Override 814 protected View getStatusBarView() { 815 return mStatusBarView; 816 } 817 818 public StatusBarWindowView getStatusBarWindow() { 819 return mStatusBarWindow; 820 } 821 822 @Override 823 protected WindowManager.LayoutParams getSearchLayoutParams(LayoutParams layoutParams) { 824 boolean opaque = false; 825 WindowManager.LayoutParams lp = new WindowManager.LayoutParams( 826 LayoutParams.MATCH_PARENT, 827 LayoutParams.MATCH_PARENT, 828 WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL, 829 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN 830 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM 831 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, 832 (opaque ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT)); 833 if (ActivityManager.isHighEndGfx()) { 834 lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; 835 } 836 lp.gravity = Gravity.BOTTOM | Gravity.START; 837 lp.setTitle("SearchPanel"); 838 // TODO: Define custom animation for Search panel 839 lp.windowAnimations = com.android.internal.R.style.Animation_RecentApplications; 840 lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED 841 | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING; 842 return lp; 843 } 844 845 @Override 846 protected void updateSearchPanel() { 847 super.updateSearchPanel(); 848 if (mNavigationBarView != null) { 849 mNavigationBarView.setDelegateView(mSearchPanelView); 850 } 851 } 852 853 @Override 854 public void showSearchPanel() { 855 super.showSearchPanel(); 856 mHandler.removeCallbacks(mShowSearchPanel); 857 858 // we want to freeze the sysui state wherever it is 859 mSearchPanelView.setSystemUiVisibility(mSystemUiVisibility); 860 861 if (mNavigationBarView != null) { 862 WindowManager.LayoutParams lp = 863 (android.view.WindowManager.LayoutParams) mNavigationBarView.getLayoutParams(); 864 lp.flags &= ~WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; 865 mWindowManager.updateViewLayout(mNavigationBarView, lp); 866 } 867 } 868 869 @Override 870 public void hideSearchPanel() { 871 super.hideSearchPanel(); 872 if (mNavigationBarView != null) { 873 WindowManager.LayoutParams lp = 874 (android.view.WindowManager.LayoutParams) mNavigationBarView.getLayoutParams(); 875 lp.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; 876 mWindowManager.updateViewLayout(mNavigationBarView, lp); 877 } 878 } 879 880 public int getStatusBarHeight() { 881 if (mNaturalBarHeight < 0) { 882 final Resources res = mContext.getResources(); 883 mNaturalBarHeight = 884 res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height); 885 } 886 return mNaturalBarHeight; 887 } 888 889 private View.OnClickListener mRecentsClickListener = new View.OnClickListener() { 890 public void onClick(View v) { 891 awakenDreams(); 892 toggleRecentApps(); 893 } 894 }; 895 896 private int mShowSearchHoldoff = 0; 897 private Runnable mShowSearchPanel = new Runnable() { 898 public void run() { 899 showSearchPanel(); 900 awakenDreams(); 901 } 902 }; 903 904 View.OnTouchListener mHomeActionListener = new View.OnTouchListener() { 905 public boolean onTouch(View v, MotionEvent event) { 906 switch(event.getAction()) { 907 case MotionEvent.ACTION_DOWN: 908 if (!shouldDisableNavbarGestures()) { 909 mHandler.removeCallbacks(mShowSearchPanel); 910 mHandler.postDelayed(mShowSearchPanel, mShowSearchHoldoff); 911 } 912 break; 913 914 case MotionEvent.ACTION_UP: 915 case MotionEvent.ACTION_CANCEL: 916 mHandler.removeCallbacks(mShowSearchPanel); 917 awakenDreams(); 918 break; 919 } 920 return false; 921 } 922 }; 923 924 private void awakenDreams() { 925 if (mDreamManager != null) { 926 try { 927 mDreamManager.awaken(); 928 } catch (RemoteException e) { 929 // fine, stay asleep then 930 } 931 } 932 } 933 934 private void prepareNavigationBarView() { 935 mNavigationBarView.reorient(); 936 937 mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener); 938 mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPreloadOnTouchListener); 939 mNavigationBarView.getHomeButton().setOnTouchListener(mHomeActionListener); 940 updateSearchPanel(); 941 } 942 943 // For small-screen devices (read: phones) that lack hardware navigation buttons 944 private void addNavigationBar() { 945 if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + mNavigationBarView); 946 if (mNavigationBarView == null) return; 947 948 prepareNavigationBarView(); 949 950 mWindowManager.addView(mNavigationBarView, getNavigationBarLayoutParams()); 951 } 952 953 private void repositionNavigationBar() { 954 if (mNavigationBarView == null || !mNavigationBarView.isAttachedToWindow()) return; 955 956 prepareNavigationBarView(); 957 958 mWindowManager.updateViewLayout(mNavigationBarView, getNavigationBarLayoutParams()); 959 } 960 961 private void notifyNavigationBarScreenOn(boolean screenOn) { 962 if (mNavigationBarView == null) return; 963 mNavigationBarView.notifyScreenOn(screenOn); 964 } 965 966 private WindowManager.LayoutParams getNavigationBarLayoutParams() { 967 WindowManager.LayoutParams lp = new WindowManager.LayoutParams( 968 LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, 969 WindowManager.LayoutParams.TYPE_NAVIGATION_BAR, 970 0 971 | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING 972 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 973 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL 974 | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH 975 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, 976 PixelFormat.TRANSLUCENT); 977 // this will allow the navbar to run in an overlay on devices that support this 978 if (ActivityManager.isHighEndGfx()) { 979 lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; 980 } 981 982 lp.setTitle("NavigationBar"); 983 lp.windowAnimations = 0; 984 return lp; 985 } 986 987 private void addHeadsUpView() { 988 int headsUpHeight = mContext.getResources() 989 .getDimensionPixelSize(R.dimen.heads_up_window_height); 990 WindowManager.LayoutParams lp = new WindowManager.LayoutParams( 991 LayoutParams.MATCH_PARENT, headsUpHeight, 992 WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL, // above the status bar! 993 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN 994 | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS 995 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL 996 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 997 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM 998 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, 999 PixelFormat.TRANSLUCENT); 1000 lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; 1001 lp.gravity = Gravity.TOP; 1002 lp.setTitle("Heads Up"); 1003 lp.packageName = mContext.getPackageName(); 1004 lp.windowAnimations = R.style.Animation_StatusBar_HeadsUp; 1005 1006 mWindowManager.addView(mHeadsUpNotificationView, lp); 1007 } 1008 1009 private void removeHeadsUpView() { 1010 mWindowManager.removeView(mHeadsUpNotificationView); 1011 } 1012 1013 public void refreshAllStatusBarIcons() { 1014 refreshAllIconsForLayout(mStatusIcons); 1015 refreshAllIconsForLayout(mNotificationIcons); 1016 } 1017 1018 private void refreshAllIconsForLayout(LinearLayout ll) { 1019 final int count = ll.getChildCount(); 1020 for (int n = 0; n < count; n++) { 1021 View child = ll.getChildAt(n); 1022 if (child instanceof StatusBarIconView) { 1023 ((StatusBarIconView) child).updateDrawable(); 1024 } 1025 } 1026 } 1027 1028 public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) { 1029 if (SPEW) Log.d(TAG, "addIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex 1030 + " icon=" + icon); 1031 StatusBarIconView view = new StatusBarIconView(mContext, slot, null); 1032 view.set(icon); 1033 mStatusIcons.addView(view, viewIndex, new LinearLayout.LayoutParams(mIconSize, mIconSize)); 1034 } 1035 1036 public void updateIcon(String slot, int index, int viewIndex, 1037 StatusBarIcon old, StatusBarIcon icon) { 1038 if (SPEW) Log.d(TAG, "updateIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex 1039 + " old=" + old + " icon=" + icon); 1040 StatusBarIconView view = (StatusBarIconView)mStatusIcons.getChildAt(viewIndex); 1041 view.set(icon); 1042 } 1043 1044 public void removeIcon(String slot, int index, int viewIndex) { 1045 if (SPEW) Log.d(TAG, "removeIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex); 1046 mStatusIcons.removeViewAt(viewIndex); 1047 } 1048 1049 public UserHandle getCurrentUserHandle() { 1050 return new UserHandle(mCurrentUserId); 1051 } 1052 1053 @Override 1054 public void addNotificationInternal(StatusBarNotification notification, RankingMap ranking) { 1055 if (DEBUG) Log.d(TAG, "addNotification key=" + notification.getKey()); 1056 if (mZenMode != Global.ZEN_MODE_OFF && mIntercepted.tryIntercept(notification, ranking)) { 1057 // Forward the ranking so we can sort the new notification. 1058 mNotificationData.updateRanking(ranking); 1059 return; 1060 } 1061 mIntercepted.remove(notification.getKey()); 1062 displayNotification(notification, ranking); 1063 } 1064 1065 public void displayNotification(StatusBarNotification notification, RankingMap ranking) { 1066 if (mUseHeadsUp && shouldInterrupt(notification)) { 1067 if (DEBUG) Log.d(TAG, "launching notification in heads up mode"); 1068 Entry interruptionCandidate = new Entry(notification, null); 1069 ViewGroup holder = mHeadsUpNotificationView.getHolder(); 1070 if (inflateViewsForHeadsUp(interruptionCandidate, holder)) { 1071 mInterruptingNotificationTime = System.currentTimeMillis(); 1072 1073 // 1. Populate mHeadsUpNotificationView 1074 mHeadsUpNotificationView.showNotification(interruptionCandidate); 1075 1076 // do not show the notification in the shade, yet. 1077 return; 1078 } 1079 } 1080 1081 Entry shadeEntry = createNotificationViews(notification); 1082 if (shadeEntry == null) { 1083 return; 1084 } 1085 1086 if (notification.getNotification().fullScreenIntent != null) { 1087 // Stop screensaver if the notification has a full-screen intent. 1088 // (like an incoming phone call) 1089 awakenDreams(); 1090 1091 // not immersive & a full-screen alert should be shown 1092 if (DEBUG) Log.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent"); 1093 try { 1094 notification.getNotification().fullScreenIntent.send(); 1095 } catch (PendingIntent.CanceledException e) { 1096 } 1097 } else { 1098 // usual case: status bar visible & not immersive 1099 1100 // show the ticker if there isn't already a heads up 1101 if (mHeadsUpNotificationView.getEntry() == null) { 1102 tick(notification, true); 1103 } 1104 } 1105 addNotificationViews(shadeEntry, ranking); 1106 // Recalculate the position of the sliding windows and the titles. 1107 setAreThereNotifications(); 1108 updateExpandedViewPos(EXPANDED_LEAVE_ALONE); 1109 } 1110 1111 public void displayNotificationFromHeadsUp(StatusBarNotification notification) { 1112 NotificationData.Entry shadeEntry = createNotificationViews(notification); 1113 if (shadeEntry == null) { 1114 return; 1115 } 1116 shadeEntry.setInterruption(); 1117 1118 addNotificationViews(shadeEntry, null); 1119 // Recalculate the position of the sliding windows and the titles. 1120 setAreThereNotifications(); 1121 updateExpandedViewPos(EXPANDED_LEAVE_ALONE); 1122 } 1123 1124 @Override 1125 public void resetHeadsUpDecayTimer() { 1126 mHandler.removeMessages(MSG_DECAY_HEADS_UP); 1127 if (mUseHeadsUp && mHeadsUpNotificationDecay > 0 1128 && mHeadsUpNotificationView.isClearable()) { 1129 mHandler.sendEmptyMessageDelayed(MSG_DECAY_HEADS_UP, mHeadsUpNotificationDecay); 1130 } 1131 } 1132 1133 @Override 1134 public void scheduleHeadsUpOpen() { 1135 mHandler.sendEmptyMessage(MSG_SHOW_HEADS_UP); 1136 } 1137 1138 @Override 1139 public void scheduleHeadsUpClose() { 1140 mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP); 1141 } 1142 1143 @Override 1144 public void scheduleHeadsUpEscalation() { 1145 mHandler.sendEmptyMessage(MSG_ESCALATE_HEADS_UP); 1146 } 1147 1148 @Override 1149 public void updateNotificationInternal(StatusBarNotification notification, RankingMap ranking) { 1150 super.updateNotificationInternal(notification, ranking); 1151 // if we're here, then the notification is already in the shade 1152 mIntercepted.remove(notification.getKey()); 1153 } 1154 1155 @Override 1156 protected void updateRankingInternal(RankingMap ranking) { 1157 mNotificationData.updateRanking(ranking); 1158 mIntercepted.retryIntercepts(ranking); 1159 updateNotifications(); 1160 } 1161 1162 @Override 1163 public void removeNotificationInternal(String key, RankingMap ranking) { 1164 if (ENABLE_HEADS_UP && mHeadsUpNotificationView.getEntry() != null 1165 && key.equals(mHeadsUpNotificationView.getEntry().notification.getKey())) { 1166 mHeadsUpNotificationView.clear(); 1167 } 1168 1169 StatusBarNotification old = removeNotificationViews(key, ranking); 1170 if (SPEW) Log.d(TAG, "removeNotification key=" + key + " old=" + old); 1171 1172 if (old != null) { 1173 // Cancel the ticker if it's still running 1174 if (mTickerEnabled) { 1175 mTicker.removeEntry(old); 1176 } 1177 1178 // Recalculate the position of the sliding windows and the titles. 1179 updateExpandedViewPos(EXPANDED_LEAVE_ALONE); 1180 1181 if (CLOSE_PANEL_WHEN_EMPTIED && mNotificationData.size() == 0 1182 && !mNotificationPanel.isTracking() && mState != StatusBarState.KEYGUARD) { 1183 animateCollapsePanels(); 1184 } 1185 } 1186 mIntercepted.remove(key); 1187 setAreThereNotifications(); 1188 } 1189 1190 @Override 1191 protected void refreshLayout(int layoutDirection) { 1192 if (mNavigationBarView != null) { 1193 mNavigationBarView.setLayoutDirection(layoutDirection); 1194 } 1195 refreshAllStatusBarIcons(); 1196 } 1197 1198 private void updateShowSearchHoldoff() { 1199 mShowSearchHoldoff = mContext.getResources().getInteger( 1200 R.integer.config_show_search_delay); 1201 } 1202 1203 private void updateNotificationShade() { 1204 if (mStackScroller == null) return; 1205 1206 int N = mNotificationData.size(); 1207 1208 ArrayList<View> toShow = new ArrayList<View>(); 1209 1210 final boolean provisioned = isDeviceProvisioned(); 1211 // If the device hasn't been through Setup, we only show system notifications 1212 for (int i=0; i<N; i++) { 1213 Entry ent = mNotificationData.get(i); 1214 if (!(provisioned || showNotificationEvenIfUnprovisioned(ent.notification))) continue; 1215 1216 if (!notificationIsForCurrentProfiles(ent.notification)) continue; 1217 1218 final int vis = ent.notification.getNotification().visibility; 1219 if (vis != Notification.VISIBILITY_SECRET) { 1220 // when isLockscreenPublicMode() we show the public form of VISIBILITY_PRIVATE notifications 1221 boolean showingPublic = isLockscreenPublicMode() 1222 && vis == Notification.VISIBILITY_PRIVATE 1223 && !userAllowsPrivateNotificationsInPublic(ent.notification.getUserId()); 1224 ent.row.setShowingPublic(showingPublic); 1225 if (ent.autoRedacted && ent.legacy) { 1226 if (showingPublic) { 1227 ent.row.setBackgroundResourceIds( 1228 com.android.internal.R.drawable.notification_material_bg, 1229 com.android.internal.R.drawable.notification_material_bg_dim); 1230 } else { 1231 ent.row.setBackgroundResourceIds( 1232 com.android.internal.R.drawable.notification_bg, 1233 com.android.internal.R.drawable.notification_bg_dim); 1234 } 1235 } 1236 toShow.add(ent.row); 1237 } 1238 } 1239 1240 ArrayList<View> toRemove = new ArrayList<View>(); 1241 for (int i=0; i< mStackScroller.getChildCount(); i++) { 1242 View child = mStackScroller.getChildAt(i); 1243 if (!toShow.contains(child) && child instanceof ExpandableNotificationRow) { 1244 toRemove.add(child); 1245 } 1246 } 1247 1248 for (View remove : toRemove) { 1249 mStackScroller.removeView(remove); 1250 } 1251 1252 for (int i=0; i<toShow.size(); i++) { 1253 View v = toShow.get(i); 1254 if (v.getParent() == null) { 1255 mStackScroller.addView(v); 1256 } 1257 } 1258 1259 // So after all this work notifications still aren't sorted correctly. 1260 // Let's do that now by advancing through toShow and mStackScroller in 1261 // lock-step, making sure mStackScroller matches what we see in toShow. 1262 int j = 0; 1263 for (int i = 0; i < mStackScroller.getChildCount(); i++) { 1264 View child = mStackScroller.getChildAt(i); 1265 if (!(child instanceof ExpandableNotificationRow)) { 1266 // We don't care about non-notification views. 1267 continue; 1268 } 1269 1270 if (child == toShow.get(j)) { 1271 // Everything is well, advance both lists. 1272 j++; 1273 continue; 1274 } 1275 1276 // Oops, wrong notification at this position. Put the right one 1277 // here and advance both lists. 1278 mStackScroller.changeViewPosition(toShow.get(j), i); 1279 j++; 1280 } 1281 updateRowStates(); 1282 updateSpeedbump(); 1283 mNotificationPanel.setQsExpansionEnabled(provisioned && mUserSetup); 1284 } 1285 1286 private void updateSpeedbump() { 1287 int speedbumpIndex = -1; 1288 int currentIndex = 0; 1289 for (int i = 0; i < mNotificationData.size(); i++) { 1290 Entry entry = mNotificationData.get(i); 1291 if (entry.row.getParent() == null) { 1292 // This view isn't even added, so the stack scroller doesn't 1293 // know about it. Ignore completely. 1294 continue; 1295 } 1296 if (entry.row.getVisibility() != View.GONE && 1297 mNotificationData.isAmbient(entry.key)) { 1298 speedbumpIndex = currentIndex; 1299 break; 1300 } 1301 currentIndex++; 1302 } 1303 mStackScroller.updateSpeedBumpIndex(speedbumpIndex); 1304 } 1305 1306 @Override 1307 protected void updateNotifications() { 1308 // TODO: Move this into updateNotificationIcons()? 1309 if (mNotificationIcons == null) return; 1310 1311 updateNotificationShade(); 1312 updateNotificationIcons(); 1313 } 1314 1315 private void updateNotificationIcons() { 1316 final LinearLayout.LayoutParams params 1317 = new LinearLayout.LayoutParams(mIconSize + 2*mIconHPadding, mNaturalBarHeight); 1318 1319 int N = mNotificationData.size(); 1320 1321 if (DEBUG) { 1322 Log.d(TAG, "refreshing icons: " + N + " notifications, mNotificationIcons=" + 1323 mNotificationIcons); 1324 } 1325 1326 ArrayList<View> toShow = new ArrayList<View>(); 1327 1328 final boolean provisioned = isDeviceProvisioned(); 1329 // If the device hasn't been through Setup, we only show system notifications 1330 for (int i=0; i<N; i++) { 1331 Entry ent = mNotificationData.get(i); 1332 if (!((provisioned && ent.notification.getScore() >= HIDE_ICONS_BELOW_SCORE) 1333 || showNotificationEvenIfUnprovisioned(ent.notification))) continue; 1334 if (!notificationIsForCurrentProfiles(ent.notification)) continue; 1335 if (isLockscreenPublicMode() 1336 && ent.notification.getNotification().visibility 1337 == Notification.VISIBILITY_SECRET 1338 && !userAllowsPrivateNotificationsInPublic(ent.notification.getUserId())) { 1339 // in "public" mode (atop a secure keyguard), secret notifs are totally hidden 1340 continue; 1341 } 1342 if (mIntercepted.isSyntheticEntry(ent)) { 1343 continue; 1344 } 1345 toShow.add(ent.icon); 1346 } 1347 1348 ArrayList<View> toRemove = new ArrayList<View>(); 1349 for (int i=0; i<mNotificationIcons.getChildCount(); i++) { 1350 View child = mNotificationIcons.getChildAt(i); 1351 if (!toShow.contains(child)) { 1352 toRemove.add(child); 1353 } 1354 } 1355 1356 for (View remove : toRemove) { 1357 mNotificationIcons.removeView(remove); 1358 } 1359 1360 for (int i=0; i<toShow.size(); i++) { 1361 View v = toShow.get(i); 1362 if (v.getParent() == null) { 1363 mNotificationIcons.addView(v, i, params); 1364 } 1365 } 1366 } 1367 1368 protected void updateCarrierLabelVisibility(boolean force) { 1369 // TODO: Handle this for the notification stack scroller as well 1370 if (!mShowCarrierInPanel) return; 1371 // The idea here is to only show the carrier label when there is enough room to see it, 1372 // i.e. when there aren't enough notifications to fill the panel. 1373 if (SPEW) { 1374 Log.d(TAG, String.format("stackScrollerh=%d scrollh=%d carrierh=%d", 1375 mStackScroller.getHeight(), mStackScroller.getHeight(), 1376 mCarrierLabelHeight)); 1377 } 1378 1379 // Emergency calls only is shown in the expanded header now. 1380 final boolean emergencyCallsShownElsewhere = true; 1381 final boolean makeVisible = 1382 !(emergencyCallsShownElsewhere && mNetworkController.isEmergencyOnly()) 1383 && mStackScroller.getHeight() < (mNotificationPanel.getHeight() 1384 - mCarrierLabelHeight - mStatusBarHeaderHeight) 1385 && mStackScroller.getVisibility() == View.VISIBLE 1386 && mState != StatusBarState.KEYGUARD; 1387 1388 if (force || mCarrierLabelVisible != makeVisible) { 1389 mCarrierLabelVisible = makeVisible; 1390 if (DEBUG) { 1391 Log.d(TAG, "making carrier label " + (makeVisible?"visible":"invisible")); 1392 } 1393 mCarrierLabel.animate().cancel(); 1394 if (makeVisible) { 1395 mCarrierLabel.setVisibility(View.VISIBLE); 1396 } 1397 mCarrierLabel.animate() 1398 .alpha(makeVisible ? 1f : 0f) 1399 //.setStartDelay(makeVisible ? 500 : 0) 1400 //.setDuration(makeVisible ? 750 : 100) 1401 .setDuration(150) 1402 .setListener(makeVisible ? null : new AnimatorListenerAdapter() { 1403 @Override 1404 public void onAnimationEnd(Animator animation) { 1405 if (!mCarrierLabelVisible) { // race 1406 mCarrierLabel.setVisibility(View.INVISIBLE); 1407 mCarrierLabel.setAlpha(0f); 1408 } 1409 } 1410 }) 1411 .start(); 1412 } 1413 } 1414 1415 @Override 1416 protected void setAreThereNotifications() { 1417 final boolean any = mNotificationData.size() > 0; 1418 1419 final boolean clearable = any && mNotificationData.hasClearableItems(); 1420 1421 if (SPEW) { 1422 Log.d(TAG, "setAreThereNotifications: N=" + mNotificationData.size() 1423 + " any=" + any + " clearable=" + clearable); 1424 } 1425 1426 final View nlo = mStatusBarView.findViewById(R.id.notification_lights_out); 1427 final boolean showDot = (any&&!areLightsOn()); 1428 if (showDot != (nlo.getAlpha() == 1.0f)) { 1429 if (showDot) { 1430 nlo.setAlpha(0f); 1431 nlo.setVisibility(View.VISIBLE); 1432 } 1433 nlo.animate() 1434 .alpha(showDot?1:0) 1435 .setDuration(showDot?750:250) 1436 .setInterpolator(new AccelerateInterpolator(2.0f)) 1437 .setListener(showDot ? null : new AnimatorListenerAdapter() { 1438 @Override 1439 public void onAnimationEnd(Animator _a) { 1440 nlo.setVisibility(View.GONE); 1441 } 1442 }) 1443 .start(); 1444 } 1445 1446 updateCarrierLabelVisibility(false); 1447 } 1448 1449 public void showClock(boolean show) { 1450 if (mStatusBarView == null) return; 1451 View clock = mStatusBarView.findViewById(R.id.clock); 1452 if (clock != null) { 1453 clock.setVisibility(show ? View.VISIBLE : View.GONE); 1454 } 1455 } 1456 1457 private int adjustDisableFlags(int state) { 1458 if (mExpandedVisible) { 1459 state |= StatusBarManager.DISABLE_NOTIFICATION_ICONS; 1460 state |= StatusBarManager.DISABLE_SYSTEM_INFO; 1461 } 1462 return state; 1463 } 1464 1465 /** 1466 * State is one or more of the DISABLE constants from StatusBarManager. 1467 */ 1468 public void disable(int state) { 1469 mDisabledUnmodified = state; 1470 state = adjustDisableFlags(state); 1471 final int old = mDisabled; 1472 final int diff = state ^ old; 1473 mDisabled = state; 1474 1475 if (DEBUG) { 1476 Log.d(TAG, String.format("disable: 0x%08x -> 0x%08x (diff: 0x%08x)", 1477 old, state, diff)); 1478 } 1479 1480 StringBuilder flagdbg = new StringBuilder(); 1481 flagdbg.append("disable: < "); 1482 flagdbg.append(((state & StatusBarManager.DISABLE_EXPAND) != 0) ? "EXPAND" : "expand"); 1483 flagdbg.append(((diff & StatusBarManager.DISABLE_EXPAND) != 0) ? "* " : " "); 1484 flagdbg.append(((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) ? "ICONS" : "icons"); 1485 flagdbg.append(((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) ? "* " : " "); 1486 flagdbg.append(((state & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) ? "ALERTS" : "alerts"); 1487 flagdbg.append(((diff & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) ? "* " : " "); 1488 flagdbg.append(((state & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) ? "SYSTEM_INFO" : "system_info"); 1489 flagdbg.append(((diff & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) ? "* " : " "); 1490 flagdbg.append(((state & StatusBarManager.DISABLE_BACK) != 0) ? "BACK" : "back"); 1491 flagdbg.append(((diff & StatusBarManager.DISABLE_BACK) != 0) ? "* " : " "); 1492 flagdbg.append(((state & StatusBarManager.DISABLE_HOME) != 0) ? "HOME" : "home"); 1493 flagdbg.append(((diff & StatusBarManager.DISABLE_HOME) != 0) ? "* " : " "); 1494 flagdbg.append(((state & StatusBarManager.DISABLE_RECENT) != 0) ? "RECENT" : "recent"); 1495 flagdbg.append(((diff & StatusBarManager.DISABLE_RECENT) != 0) ? "* " : " "); 1496 flagdbg.append(((state & StatusBarManager.DISABLE_CLOCK) != 0) ? "CLOCK" : "clock"); 1497 flagdbg.append(((diff & StatusBarManager.DISABLE_CLOCK) != 0) ? "* " : " "); 1498 flagdbg.append(((state & StatusBarManager.DISABLE_SEARCH) != 0) ? "SEARCH" : "search"); 1499 flagdbg.append(((diff & StatusBarManager.DISABLE_SEARCH) != 0) ? "* " : " "); 1500 flagdbg.append(">"); 1501 Log.d(TAG, flagdbg.toString()); 1502 1503 if ((diff & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) { 1504 mSystemIconArea.animate().cancel(); 1505 if ((state & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) { 1506 mSystemIconArea.animate() 1507 .alpha(0f) 1508 .withLayer() 1509 .setDuration(160) 1510 .setInterpolator(mAlphaIn) 1511 .setListener(mMakeIconsInvisible); 1512 } else { 1513 mSystemIconArea.setVisibility(View.VISIBLE); 1514 mSystemIconArea.animate() 1515 .alpha(1f) 1516 .withLayer() 1517 .setInterpolator(mAlphaOut) 1518 .setDuration(320); 1519 } 1520 } 1521 1522 if ((diff & StatusBarManager.DISABLE_CLOCK) != 0) { 1523 boolean show = (state & StatusBarManager.DISABLE_CLOCK) == 0; 1524 showClock(show); 1525 } 1526 if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) { 1527 if ((state & StatusBarManager.DISABLE_EXPAND) != 0) { 1528 animateCollapsePanels(); 1529 } 1530 } 1531 1532 if ((diff & (StatusBarManager.DISABLE_HOME 1533 | StatusBarManager.DISABLE_RECENT 1534 | StatusBarManager.DISABLE_BACK 1535 | StatusBarManager.DISABLE_SEARCH)) != 0) { 1536 // the nav bar will take care of these 1537 if (mNavigationBarView != null) mNavigationBarView.setDisabledFlags(state); 1538 1539 if ((state & StatusBarManager.DISABLE_RECENT) != 0) { 1540 // close recents if it's visible 1541 mHandler.removeMessages(MSG_HIDE_RECENT_APPS); 1542 mHandler.sendEmptyMessage(MSG_HIDE_RECENT_APPS); 1543 } 1544 } 1545 1546 if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) { 1547 if ((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) { 1548 if (mTicking) { 1549 haltTicker(); 1550 } 1551 1552 mNotificationIcons.animate() 1553 .alpha(0f) 1554 .withLayer() 1555 .setDuration(160) 1556 .setInterpolator(mAlphaIn) 1557 .setListener(mMakeIconsInvisible) 1558 .start(); 1559 } else { 1560 mNotificationIcons.setVisibility(View.VISIBLE); 1561 mNotificationIcons.animate() 1562 .alpha(1f) 1563 .withLayer() 1564 .setInterpolator(mAlphaOut) 1565 .setDuration(320); 1566 } 1567 } 1568 } 1569 1570 @Override 1571 protected BaseStatusBar.H createHandler() { 1572 return new PhoneStatusBar.H(); 1573 } 1574 1575 @Override 1576 public void startActivity(Intent intent) { 1577 startActivityDismissingKeyguard(intent, false); 1578 } 1579 1580 public ScrimController getScrimController() { 1581 return mScrimController; 1582 } 1583 1584 /** 1585 * All changes to the status bar and notifications funnel through here and are batched. 1586 */ 1587 private class H extends BaseStatusBar.H { 1588 public void handleMessage(Message m) { 1589 super.handleMessage(m); 1590 switch (m.what) { 1591 case MSG_OPEN_NOTIFICATION_PANEL: 1592 animateExpandNotificationsPanel(); 1593 break; 1594 case MSG_OPEN_SETTINGS_PANEL: 1595 animateExpandSettingsPanel(); 1596 break; 1597 case MSG_CLOSE_PANELS: 1598 animateCollapsePanels(); 1599 break; 1600 case MSG_SHOW_HEADS_UP: 1601 setHeadsUpVisibility(true); 1602 break; 1603 case MSG_DECAY_HEADS_UP: 1604 mHeadsUpNotificationView.release(); 1605 setHeadsUpVisibility(false); 1606 break; 1607 case MSG_HIDE_HEADS_UP: 1608 mHeadsUpNotificationView.release(); 1609 setHeadsUpVisibility(false); 1610 break; 1611 case MSG_ESCALATE_HEADS_UP: 1612 escalateHeadsUp(); 1613 setHeadsUpVisibility(false); 1614 break; 1615 } 1616 } 1617 } 1618 1619 /** if the interrupting notification had a fullscreen intent, fire it now. */ 1620 private void escalateHeadsUp() { 1621 if (mHeadsUpNotificationView.getEntry() != null) { 1622 final StatusBarNotification sbn = mHeadsUpNotificationView.getEntry().notification; 1623 mHeadsUpNotificationView.release(); 1624 final Notification notification = sbn.getNotification(); 1625 if (notification.fullScreenIntent != null) { 1626 if (DEBUG) 1627 Log.d(TAG, "converting a heads up to fullScreen"); 1628 try { 1629 notification.fullScreenIntent.send(); 1630 } catch (PendingIntent.CanceledException e) { 1631 } 1632 } 1633 } 1634 } 1635 1636 private Handler getHandler() { 1637 return mHandler; 1638 } 1639 1640 View.OnFocusChangeListener mFocusChangeListener = new View.OnFocusChangeListener() { 1641 public void onFocusChange(View v, boolean hasFocus) { 1642 // Because 'v' is a ViewGroup, all its children will be (un)selected 1643 // too, which allows marqueeing to work. 1644 v.setSelected(hasFocus); 1645 } 1646 }; 1647 1648 boolean panelsEnabled() { 1649 return (mDisabled & StatusBarManager.DISABLE_EXPAND) == 0; 1650 } 1651 1652 void makeExpandedVisible(boolean force) { 1653 if (SPEW) Log.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible); 1654 if (!force && (mExpandedVisible || !panelsEnabled())) { 1655 return; 1656 } 1657 1658 mExpandedVisible = true; 1659 if (mNavigationBarView != null) 1660 mNavigationBarView.setSlippery(true); 1661 1662 updateCarrierLabelVisibility(true); 1663 1664 updateExpandedViewPos(EXPANDED_LEAVE_ALONE); 1665 1666 // Expand the window to encompass the full screen in anticipation of the drag. 1667 // This is only possible to do atomically because the status bar is at the top of the screen! 1668 mStatusBarWindowManager.setStatusBarExpanded(true); 1669 1670 visibilityChanged(true); 1671 disable(mDisabledUnmodified); 1672 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true); 1673 } 1674 1675 public void animateCollapsePanels() { 1676 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE); 1677 } 1678 1679 private final Runnable mAnimateCollapsePanels = new Runnable() { 1680 @Override 1681 public void run() { 1682 animateCollapsePanels(); 1683 } 1684 }; 1685 1686 public void postAnimateCollapsePanels() { 1687 mHandler.post(mAnimateCollapsePanels); 1688 } 1689 1690 public void animateCollapsePanels(int flags) { 1691 if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) { 1692 return; 1693 } 1694 if (SPEW) { 1695 Log.d(TAG, "animateCollapse():" 1696 + " mExpandedVisible=" + mExpandedVisible 1697 + " flags=" + flags); 1698 } 1699 1700 if ((flags & CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL) == 0) { 1701 mHandler.removeMessages(MSG_HIDE_RECENT_APPS); 1702 mHandler.sendEmptyMessage(MSG_HIDE_RECENT_APPS); 1703 } 1704 1705 if ((flags & CommandQueue.FLAG_EXCLUDE_SEARCH_PANEL) == 0) { 1706 mHandler.removeMessages(MSG_CLOSE_SEARCH_PANEL); 1707 mHandler.sendEmptyMessage(MSG_CLOSE_SEARCH_PANEL); 1708 } 1709 1710 if (mStatusBarWindow != null) { 1711 // release focus immediately to kick off focus change transition 1712 mStatusBarWindowManager.setStatusBarFocusable(false); 1713 1714 mStatusBarWindow.cancelExpandHelper(); 1715 mStatusBarView.collapseAllPanels(true); 1716 if (isFlippedToSettings()) { 1717 flipToNotifications(true /*animate*/); 1718 } 1719 } 1720 } 1721 1722 public ViewPropertyAnimator setVisibilityWhenDone( 1723 final ViewPropertyAnimator a, final View v, final int vis) { 1724 a.setListener(new AnimatorListenerAdapter() { 1725 @Override 1726 public void onAnimationEnd(Animator animation) { 1727 v.setVisibility(vis); 1728 a.setListener(null); // oneshot 1729 } 1730 }); 1731 return a; 1732 } 1733 1734 public Animator setVisibilityWhenDone( 1735 final Animator a, final View v, final int vis) { 1736 a.addListener(new AnimatorListenerAdapter() { 1737 @Override 1738 public void onAnimationEnd(Animator animation) { 1739 v.setVisibility(vis); 1740 } 1741 }); 1742 return a; 1743 } 1744 1745 public Animator interpolator(TimeInterpolator ti, Animator a) { 1746 a.setInterpolator(ti); 1747 return a; 1748 } 1749 1750 public Animator startDelay(int d, Animator a) { 1751 a.setStartDelay(d); 1752 return a; 1753 } 1754 1755 public Animator start(Animator a) { 1756 a.start(); 1757 return a; 1758 } 1759 1760 final TimeInterpolator mAccelerateInterpolator = new AccelerateInterpolator(); 1761 final TimeInterpolator mDecelerateInterpolator = new DecelerateInterpolator(); 1762 final int FLIP_DURATION_OUT = 125; 1763 final int FLIP_DURATION_IN = 225; 1764 final int FLIP_DURATION = (FLIP_DURATION_IN + FLIP_DURATION_OUT); 1765 1766 Animator mScrollViewAnim, mClearButtonAnim; 1767 1768 @Override 1769 public void animateExpandNotificationsPanel() { 1770 if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible); 1771 if (!panelsEnabled()) { 1772 return ; 1773 } 1774 1775 mNotificationPanel.expand(); 1776 if (mStackScroller.getVisibility() != View.VISIBLE) { 1777 flipToNotifications(true /*animate*/); 1778 } 1779 1780 if (false) postStartTracing(); 1781 } 1782 1783 private static void cancelAnim(Animator anim) { 1784 if (anim != null) { 1785 anim.cancel(); 1786 } 1787 } 1788 1789 public void flipToNotifications(boolean animate) { 1790 // TODO: Animation 1791 mNotificationPanel.closeQs(); 1792 } 1793 1794 @Override 1795 public void animateExpandSettingsPanel() { 1796 if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible); 1797 if (!panelsEnabled()) { 1798 return; 1799 } 1800 1801 // Settings are not available in setup 1802 if (!mUserSetup) return; 1803 1804 mNotificationPanel.expand(); 1805 mNotificationPanel.openQs(); 1806 1807 if (false) postStartTracing(); 1808 } 1809 1810 public boolean isFlippedToSettings() { 1811 if (mNotificationPanel != null) { 1812 return mNotificationPanel.isQsExpanded(); 1813 } 1814 return false; 1815 } 1816 1817 public void animateCollapseQuickSettings() { 1818 mStatusBarView.collapseAllPanels(true); 1819 } 1820 1821 void makeExpandedInvisible() { 1822 if (SPEW) Log.d(TAG, "makeExpandedInvisible: mExpandedVisible=" + mExpandedVisible 1823 + " mExpandedVisible=" + mExpandedVisible); 1824 1825 if (!mExpandedVisible || mStatusBarWindow == null) { 1826 return; 1827 } 1828 1829 // Ensure the panel is fully collapsed (just in case; bug 6765842, 7260868) 1830 mStatusBarView.collapseAllPanels(/*animate=*/ false); 1831 1832 // reset things to their proper state 1833 if (mScrollViewAnim != null) mScrollViewAnim.cancel(); 1834 if (mClearButtonAnim != null) mClearButtonAnim.cancel(); 1835 1836 mStackScroller.setVisibility(View.VISIBLE); 1837 mNotificationPanel.setVisibility(View.GONE); 1838 1839 setAreThereNotifications(); // show the clear button 1840 1841 mNotificationPanel.closeQs(); 1842 1843 mExpandedVisible = false; 1844 if (mNavigationBarView != null) 1845 mNavigationBarView.setSlippery(false); 1846 visibilityChanged(false); 1847 1848 // Shrink the window to the size of the status bar only 1849 mStatusBarWindowManager.setStatusBarExpanded(false); 1850 1851 if ((mDisabled & StatusBarManager.DISABLE_NOTIFICATION_ICONS) == 0) { 1852 setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in); 1853 } 1854 1855 // Close any "App info" popups that might have snuck on-screen 1856 dismissPopups(); 1857 1858 if (mPostCollapseCleanup != null) { 1859 mPostCollapseCleanup.run(); 1860 mPostCollapseCleanup = null; 1861 } 1862 1863 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false); 1864 disable(mDisabledUnmodified); 1865 showBouncer(); 1866 } 1867 1868 public boolean interceptTouchEvent(MotionEvent event) { 1869 if (DEBUG_GESTURES) { 1870 if (event.getActionMasked() != MotionEvent.ACTION_MOVE) { 1871 EventLog.writeEvent(EventLogTags.SYSUI_STATUSBAR_TOUCH, 1872 event.getActionMasked(), (int) event.getX(), (int) event.getY(), mDisabled); 1873 } 1874 1875 } 1876 1877 if (SPEW) { 1878 Log.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled=" 1879 + mDisabled + " mTracking=" + mTracking); 1880 } else if (CHATTY) { 1881 if (event.getAction() != MotionEvent.ACTION_MOVE) { 1882 Log.d(TAG, String.format( 1883 "panel: %s at (%f, %f) mDisabled=0x%08x", 1884 MotionEvent.actionToString(event.getAction()), 1885 event.getRawX(), event.getRawY(), mDisabled)); 1886 } 1887 } 1888 1889 if (DEBUG_GESTURES) { 1890 mGestureRec.add(event); 1891 } 1892 1893 if (mStatusBarWindowState == WINDOW_STATE_SHOWING) { 1894 final boolean upOrCancel = 1895 event.getAction() == MotionEvent.ACTION_UP || 1896 event.getAction() == MotionEvent.ACTION_CANCEL; 1897 if (upOrCancel && !mExpandedVisible) { 1898 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false); 1899 } else { 1900 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true); 1901 } 1902 } 1903 return false; 1904 } 1905 1906 public GestureRecorder getGestureRecorder() { 1907 return mGestureRec; 1908 } 1909 1910 private void setNavigationIconHints(int hints) { 1911 if (hints == mNavigationIconHints) return; 1912 1913 mNavigationIconHints = hints; 1914 1915 if (mNavigationBarView != null) { 1916 mNavigationBarView.setNavigationIconHints(hints); 1917 } 1918 checkBarModes(); 1919 } 1920 1921 @Override // CommandQueue 1922 public void setWindowState(int window, int state) { 1923 boolean showing = state == WINDOW_STATE_SHOWING; 1924 if (mStatusBarWindow != null 1925 && window == StatusBarManager.WINDOW_STATUS_BAR 1926 && mStatusBarWindowState != state) { 1927 mStatusBarWindowState = state; 1928 if (DEBUG_WINDOW_STATE) Log.d(TAG, "Status bar " + windowStateToString(state)); 1929 if (!showing) { 1930 mStatusBarView.collapseAllPanels(false); 1931 } 1932 } 1933 if (mNavigationBarView != null 1934 && window == StatusBarManager.WINDOW_NAVIGATION_BAR 1935 && mNavigationBarWindowState != state) { 1936 mNavigationBarWindowState = state; 1937 if (DEBUG_WINDOW_STATE) Log.d(TAG, "Navigation bar " + windowStateToString(state)); 1938 } 1939 } 1940 1941 @Override // CommandQueue 1942 public void setSystemUiVisibility(int vis, int mask) { 1943 final int oldVal = mSystemUiVisibility; 1944 final int newVal = (oldVal&~mask) | (vis&mask); 1945 final int diff = newVal ^ oldVal; 1946 if (DEBUG) Log.d(TAG, String.format( 1947 "setSystemUiVisibility vis=%s mask=%s oldVal=%s newVal=%s diff=%s", 1948 Integer.toHexString(vis), Integer.toHexString(mask), 1949 Integer.toHexString(oldVal), Integer.toHexString(newVal), 1950 Integer.toHexString(diff))); 1951 if (diff != 0) { 1952 mSystemUiVisibility = newVal; 1953 1954 // update low profile 1955 if ((diff & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0) { 1956 final boolean lightsOut = (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0; 1957 if (lightsOut) { 1958 animateCollapsePanels(); 1959 if (mTicking) { 1960 haltTicker(); 1961 } 1962 } 1963 1964 setAreThereNotifications(); 1965 } 1966 1967 // update status bar mode 1968 final int sbMode = computeBarMode(oldVal, newVal, mStatusBarView.getBarTransitions(), 1969 View.STATUS_BAR_TRANSIENT, View.STATUS_BAR_TRANSLUCENT); 1970 1971 // update navigation bar mode 1972 final int nbMode = mNavigationBarView == null ? -1 : computeBarMode( 1973 oldVal, newVal, mNavigationBarView.getBarTransitions(), 1974 View.NAVIGATION_BAR_TRANSIENT, View.NAVIGATION_BAR_TRANSLUCENT); 1975 final boolean sbModeChanged = sbMode != -1; 1976 final boolean nbModeChanged = nbMode != -1; 1977 boolean checkBarModes = false; 1978 if (sbModeChanged && sbMode != mStatusBarMode) { 1979 mStatusBarMode = sbMode; 1980 checkBarModes = true; 1981 } 1982 if (nbModeChanged && nbMode != mNavigationBarMode) { 1983 mNavigationBarMode = nbMode; 1984 checkBarModes = true; 1985 } 1986 if (checkBarModes) { 1987 checkBarModes(); 1988 } 1989 if (sbModeChanged || nbModeChanged) { 1990 // update transient bar autohide 1991 if (mStatusBarMode == MODE_SEMI_TRANSPARENT || mNavigationBarMode == MODE_SEMI_TRANSPARENT) { 1992 scheduleAutohide(); 1993 } else { 1994 cancelAutohide(); 1995 } 1996 } 1997 1998 // ready to unhide 1999 if ((vis & View.STATUS_BAR_UNHIDE) != 0) { 2000 mSystemUiVisibility &= ~View.STATUS_BAR_UNHIDE; 2001 } 2002 if ((vis & View.NAVIGATION_BAR_UNHIDE) != 0) { 2003 mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE; 2004 } 2005 2006 // send updated sysui visibility to window manager 2007 notifyUiVisibilityChanged(mSystemUiVisibility); 2008 } 2009 } 2010 2011 private int computeBarMode(int oldVis, int newVis, BarTransitions transitions, 2012 int transientFlag, int translucentFlag) { 2013 final int oldMode = barMode(oldVis, transientFlag, translucentFlag); 2014 final int newMode = barMode(newVis, transientFlag, translucentFlag); 2015 if (oldMode == newMode) { 2016 return -1; // no mode change 2017 } 2018 return newMode; 2019 } 2020 2021 private int barMode(int vis, int transientFlag, int translucentFlag) { 2022 return (vis & transientFlag) != 0 ? MODE_SEMI_TRANSPARENT 2023 : (vis & translucentFlag) != 0 ? MODE_TRANSLUCENT 2024 : (vis & View.SYSTEM_UI_TRANSPARENT) != 0 ? MODE_TRANSPARENT 2025 : (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0 ? MODE_LIGHTS_OUT 2026 : MODE_OPAQUE; 2027 } 2028 2029 private void checkBarModes() { 2030 if (mDemoMode) return; 2031 checkBarMode(mStatusBarMode, mStatusBarWindowState, mStatusBarView.getBarTransitions()); 2032 if (mNavigationBarView != null) { 2033 checkBarMode(mNavigationBarMode, 2034 mNavigationBarWindowState, mNavigationBarView.getBarTransitions()); 2035 } 2036 } 2037 2038 private void checkBarMode(int mode, int windowState, BarTransitions transitions) { 2039 final boolean anim = (mScreenOn == null || mScreenOn) && windowState != WINDOW_STATE_HIDDEN; 2040 transitions.transitionTo(mode, anim); 2041 } 2042 2043 private void finishBarAnimations() { 2044 mStatusBarView.getBarTransitions().finishAnimations(); 2045 if (mNavigationBarView != null) { 2046 mNavigationBarView.getBarTransitions().finishAnimations(); 2047 } 2048 } 2049 2050 private final Runnable mCheckBarModes = new Runnable() { 2051 @Override 2052 public void run() { 2053 checkBarModes(); 2054 }}; 2055 2056 @Override 2057 public void setInteracting(int barWindow, boolean interacting) { 2058 mInteractingWindows = interacting 2059 ? (mInteractingWindows | barWindow) 2060 : (mInteractingWindows & ~barWindow); 2061 if (mInteractingWindows != 0) { 2062 suspendAutohide(); 2063 } else { 2064 resumeSuspendedAutohide(); 2065 } 2066 checkBarModes(); 2067 } 2068 2069 private void resumeSuspendedAutohide() { 2070 if (mAutohideSuspended) { 2071 scheduleAutohide(); 2072 mHandler.postDelayed(mCheckBarModes, 500); // longer than home -> launcher 2073 } 2074 } 2075 2076 private void suspendAutohide() { 2077 mHandler.removeCallbacks(mAutohide); 2078 mHandler.removeCallbacks(mCheckBarModes); 2079 mAutohideSuspended = (mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0; 2080 } 2081 2082 private void cancelAutohide() { 2083 mAutohideSuspended = false; 2084 mHandler.removeCallbacks(mAutohide); 2085 } 2086 2087 private void scheduleAutohide() { 2088 cancelAutohide(); 2089 mHandler.postDelayed(mAutohide, AUTOHIDE_TIMEOUT_MS); 2090 } 2091 2092 private void checkUserAutohide(View v, MotionEvent event) { 2093 if ((mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0 // a transient bar is revealed 2094 && event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar 2095 && event.getX() == 0 && event.getY() == 0 // a touch outside both bars 2096 ) { 2097 userAutohide(); 2098 } 2099 } 2100 2101 private void userAutohide() { 2102 cancelAutohide(); 2103 mHandler.postDelayed(mAutohide, 350); // longer than app gesture -> flag clear 2104 } 2105 2106 private boolean areLightsOn() { 2107 return 0 == (mSystemUiVisibility & View.SYSTEM_UI_FLAG_LOW_PROFILE); 2108 } 2109 2110 public void setLightsOn(boolean on) { 2111 Log.v(TAG, "setLightsOn(" + on + ")"); 2112 if (on) { 2113 setSystemUiVisibility(0, View.SYSTEM_UI_FLAG_LOW_PROFILE); 2114 } else { 2115 setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE, View.SYSTEM_UI_FLAG_LOW_PROFILE); 2116 } 2117 } 2118 2119 private void notifyUiVisibilityChanged(int vis) { 2120 try { 2121 mWindowManagerService.statusBarVisibilityChanged(vis); 2122 } catch (RemoteException ex) { 2123 } 2124 } 2125 2126 public void topAppWindowChanged(boolean showMenu) { 2127 if (DEBUG) { 2128 Log.d(TAG, (showMenu?"showing":"hiding") + " the MENU button"); 2129 } 2130 if (mNavigationBarView != null) { 2131 mNavigationBarView.setMenuVisibility(showMenu); 2132 } 2133 2134 // See above re: lights-out policy for legacy apps. 2135 if (showMenu) setLightsOn(true); 2136 } 2137 2138 @Override 2139 public void setImeWindowStatus(IBinder token, int vis, int backDisposition, 2140 boolean showImeSwitcher) { 2141 boolean imeShown = (vis & InputMethodService.IME_VISIBLE) != 0; 2142 int flags = mNavigationIconHints; 2143 if ((backDisposition == InputMethodService.BACK_DISPOSITION_WILL_DISMISS) || imeShown) { 2144 flags |= NAVIGATION_HINT_BACK_ALT; 2145 } else { 2146 flags &= ~NAVIGATION_HINT_BACK_ALT; 2147 } 2148 if (showImeSwitcher) { 2149 flags |= NAVIGATION_HINT_IME_SHOWN; 2150 } else { 2151 flags &= ~NAVIGATION_HINT_IME_SHOWN; 2152 } 2153 2154 setNavigationIconHints(flags); 2155 } 2156 2157 @Override 2158 public void setHardKeyboardStatus(boolean available, boolean enabled) {} 2159 2160 @Override 2161 protected void tick(StatusBarNotification n, boolean firstTime) { 2162 if (!mTickerEnabled) return; 2163 2164 // no ticking in lights-out mode 2165 if (!areLightsOn()) return; 2166 2167 // no ticking in Setup 2168 if (!isDeviceProvisioned()) return; 2169 2170 // not for you 2171 if (!notificationIsForCurrentProfiles(n)) return; 2172 2173 // Show the ticker if one is requested. Also don't do this 2174 // until status bar window is attached to the window manager, 2175 // because... well, what's the point otherwise? And trying to 2176 // run a ticker without being attached will crash! 2177 if (n.getNotification().tickerText != null && mStatusBarWindow != null 2178 && mStatusBarWindow.getWindowToken() != null) { 2179 if (0 == (mDisabled & (StatusBarManager.DISABLE_NOTIFICATION_ICONS 2180 | StatusBarManager.DISABLE_NOTIFICATION_TICKER))) { 2181 mTicker.addEntry(n); 2182 } 2183 } 2184 } 2185 2186 private class MyTicker extends Ticker { 2187 MyTicker(Context context, View sb) { 2188 super(context, sb); 2189 if (!mTickerEnabled) { 2190 Log.w(TAG, "MyTicker instantiated with mTickerEnabled=false", new Throwable()); 2191 } 2192 } 2193 2194 @Override 2195 public void tickerStarting() { 2196 if (!mTickerEnabled) return; 2197 mTicking = true; 2198 mStatusBarContents.setVisibility(View.GONE); 2199 mTickerView.setVisibility(View.VISIBLE); 2200 mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_up_in, null)); 2201 mStatusBarContents.startAnimation(loadAnim(com.android.internal.R.anim.push_up_out, null)); 2202 } 2203 2204 @Override 2205 public void tickerDone() { 2206 if (!mTickerEnabled) return; 2207 mStatusBarContents.setVisibility(View.VISIBLE); 2208 mTickerView.setVisibility(View.GONE); 2209 mStatusBarContents.startAnimation(loadAnim(com.android.internal.R.anim.push_down_in, null)); 2210 mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_down_out, 2211 mTickingDoneListener)); 2212 } 2213 2214 public void tickerHalting() { 2215 if (!mTickerEnabled) return; 2216 if (mStatusBarContents.getVisibility() != View.VISIBLE) { 2217 mStatusBarContents.setVisibility(View.VISIBLE); 2218 mStatusBarContents 2219 .startAnimation(loadAnim(com.android.internal.R.anim.fade_in, null)); 2220 } 2221 mTickerView.setVisibility(View.GONE); 2222 // we do not animate the ticker away at this point, just get rid of it (b/6992707) 2223 } 2224 } 2225 2226 Animation.AnimationListener mTickingDoneListener = new Animation.AnimationListener() {; 2227 public void onAnimationEnd(Animation animation) { 2228 mTicking = false; 2229 } 2230 public void onAnimationRepeat(Animation animation) { 2231 } 2232 public void onAnimationStart(Animation animation) { 2233 } 2234 }; 2235 2236 private Animation loadAnim(int id, Animation.AnimationListener listener) { 2237 Animation anim = AnimationUtils.loadAnimation(mContext, id); 2238 if (listener != null) { 2239 anim.setAnimationListener(listener); 2240 } 2241 return anim; 2242 } 2243 2244 public static String viewInfo(View v) { 2245 return "[(" + v.getLeft() + "," + v.getTop() + ")(" + v.getRight() + "," + v.getBottom() 2246 + ") " + v.getWidth() + "x" + v.getHeight() + "]"; 2247 } 2248 2249 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2250 synchronized (mQueueLock) { 2251 pw.println("Current Status Bar state:"); 2252 pw.println(" mExpandedVisible=" + mExpandedVisible 2253 + ", mTrackingPosition=" + mTrackingPosition); 2254 pw.println(" mTickerEnabled=" + mTickerEnabled); 2255 if (mTickerEnabled) { 2256 pw.println(" mTicking=" + mTicking); 2257 pw.println(" mTickerView: " + viewInfo(mTickerView)); 2258 } 2259 pw.println(" mTracking=" + mTracking); 2260 pw.println(" mDisplayMetrics=" + mDisplayMetrics); 2261 pw.println(" mStackScroller: " + viewInfo(mStackScroller)); 2262 pw.println(" mStackScroller: " + viewInfo(mStackScroller) 2263 + " scroll " + mStackScroller.getScrollX() 2264 + "," + mStackScroller.getScrollY()); 2265 } 2266 2267 pw.print(" mInteractingWindows="); pw.println(mInteractingWindows); 2268 pw.print(" mStatusBarWindowState="); 2269 pw.println(windowStateToString(mStatusBarWindowState)); 2270 pw.print(" mStatusBarMode="); 2271 pw.println(BarTransitions.modeToString(mStatusBarMode)); 2272 pw.print(" mZenMode="); 2273 pw.println(Settings.Global.zenModeToString(mZenMode)); 2274 pw.print(" mUseHeadsUp="); 2275 pw.println(mUseHeadsUp); 2276 pw.print(" interrupting package: "); 2277 pw.println(hunStateToString(mHeadsUpNotificationView.getEntry())); 2278 dumpBarTransitions(pw, "mStatusBarView", mStatusBarView.getBarTransitions()); 2279 if (mNavigationBarView != null) { 2280 pw.print(" mNavigationBarWindowState="); 2281 pw.println(windowStateToString(mNavigationBarWindowState)); 2282 pw.print(" mNavigationBarMode="); 2283 pw.println(BarTransitions.modeToString(mNavigationBarMode)); 2284 dumpBarTransitions(pw, "mNavigationBarView", mNavigationBarView.getBarTransitions()); 2285 } 2286 2287 pw.print(" mNavigationBarView="); 2288 if (mNavigationBarView == null) { 2289 pw.println("null"); 2290 } else { 2291 mNavigationBarView.dump(fd, pw, args); 2292 } 2293 2294 pw.println(" Panels: "); 2295 if (mNotificationPanel != null) { 2296 pw.println(" mNotificationPanel=" + 2297 mNotificationPanel + " params=" + mNotificationPanel.getLayoutParams().debug("")); 2298 pw.print (" "); 2299 mNotificationPanel.dump(fd, pw, args); 2300 } 2301 2302 if (DUMPTRUCK) { 2303 synchronized (mNotificationData) { 2304 int N = mNotificationData.size(); 2305 pw.println(" notification icons: " + N); 2306 for (int i=0; i<N; i++) { 2307 NotificationData.Entry e = mNotificationData.get(i); 2308 pw.println(" [" + i + "] key=" + e.key + " icon=" + e.icon); 2309 StatusBarNotification n = e.notification; 2310 pw.println(" pkg=" + n.getPackageName() + " id=" + n.getId() + " score=" + n.getScore()); 2311 pw.println(" notification=" + n.getNotification()); 2312 pw.println(" tickerText=\"" + n.getNotification().tickerText + "\""); 2313 } 2314 } 2315 2316 int N = mStatusIcons.getChildCount(); 2317 pw.println(" system icons: " + N); 2318 for (int i=0; i<N; i++) { 2319 StatusBarIconView ic = (StatusBarIconView) mStatusIcons.getChildAt(i); 2320 pw.println(" [" + i + "] icon=" + ic); 2321 } 2322 2323 if (false) { 2324 pw.println("see the logcat for a dump of the views we have created."); 2325 // must happen on ui thread 2326 mHandler.post(new Runnable() { 2327 public void run() { 2328 mStatusBarView.getLocationOnScreen(mAbsPos); 2329 Log.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1] 2330 + ") " + mStatusBarView.getWidth() + "x" 2331 + getStatusBarHeight()); 2332 mStatusBarView.debug(); 2333 } 2334 }); 2335 } 2336 } 2337 2338 if (DEBUG_GESTURES) { 2339 pw.print(" status bar gestures: "); 2340 mGestureRec.dump(fd, pw, args); 2341 } 2342 2343 mNetworkController.dump(fd, pw, args); 2344 } 2345 2346 private String hunStateToString(Entry entry) { 2347 if (entry == null) return "null"; 2348 if (entry.notification == null) return "corrupt"; 2349 return entry.notification.getPackageName(); 2350 } 2351 2352 private static void dumpBarTransitions(PrintWriter pw, String var, BarTransitions transitions) { 2353 pw.print(" "); pw.print(var); pw.print(".BarTransitions.mMode="); 2354 pw.println(BarTransitions.modeToString(transitions.getMode())); 2355 } 2356 2357 @Override 2358 public void createAndAddWindows() { 2359 addStatusBarWindow(); 2360 } 2361 2362 private void addStatusBarWindow() { 2363 makeStatusBarView(); 2364 mStatusBarWindowManager = new StatusBarWindowManager(mContext); 2365 mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight()); 2366 } 2367 2368 void setNotificationIconVisibility(boolean visible, int anim) { 2369 int old = mNotificationIcons.getVisibility(); 2370 int v = visible ? View.VISIBLE : View.INVISIBLE; 2371 if (old != v) { 2372 mNotificationIcons.setVisibility(v); 2373 mNotificationIcons.startAnimation(loadAnim(anim, null)); 2374 } 2375 } 2376 2377 static final float saturate(float a) { 2378 return a < 0f ? 0f : (a > 1f ? 1f : a); 2379 } 2380 2381 @Override 2382 public void updateExpandedViewPos(int thingy) { 2383 if (SPEW) Log.v(TAG, "updateExpandedViewPos"); 2384 2385 // on larger devices, the notification panel is propped open a bit 2386 mNotificationPanel.setMinimumHeight( 2387 (int)(mNotificationPanelMinHeightFrac * mCurrentDisplaySize.y)); 2388 2389 FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mNotificationPanel.getLayoutParams(); 2390 lp.gravity = mNotificationPanelGravity; 2391 mNotificationPanel.setLayoutParams(lp); 2392 2393 updateCarrierLabelVisibility(false); 2394 } 2395 2396 // called by makeStatusbar and also by PhoneStatusBarView 2397 void updateDisplaySize() { 2398 mDisplay.getMetrics(mDisplayMetrics); 2399 mDisplay.getSize(mCurrentDisplaySize); 2400 if (DEBUG_GESTURES) { 2401 mGestureRec.tag("display", 2402 String.format("%dx%d", mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels)); 2403 } 2404 } 2405 2406 private View.OnClickListener mClearButtonListener = new View.OnClickListener() { 2407 public void onClick(View v) { 2408 synchronized (mNotificationData) { 2409 mPostCollapseCleanup = new Runnable() { 2410 @Override 2411 public void run() { 2412 if (DEBUG) { 2413 Log.v(TAG, "running post-collapse cleanup"); 2414 } 2415 try { 2416 mBarService.onClearAllNotifications(mCurrentUserId); 2417 } catch (Exception ex) { } 2418 } 2419 }; 2420 2421 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE); 2422 return; 2423 // TODO: Handle this better with notification stack scroller 2424 } 2425 } 2426 }; 2427 2428 public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned) { 2429 if (onlyProvisioned && !isDeviceProvisioned()) return; 2430 2431 dismissKeyguardThenExecute(new OnDismissAction() { 2432 @Override 2433 public boolean onDismiss() { 2434 try { 2435 // Dismiss the lock screen when Settings starts. 2436 ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity(); 2437 } catch (RemoteException e) { 2438 } 2439 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); 2440 mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT)); 2441 animateCollapsePanels(); 2442 2443 return DELAY_DISMISS_TO_ACTIVITY_LAUNCH; 2444 } 2445 }); 2446 } 2447 2448 private View.OnClickListener mClockClickListener = new View.OnClickListener() { 2449 public void onClick(View v) { 2450 startActivityDismissingKeyguard( 2451 new Intent(Intent.ACTION_QUICK_CLOCK), true); // have fun, everyone 2452 } 2453 }; 2454 2455 private View.OnClickListener mNotificationButtonListener = new View.OnClickListener() { 2456 public void onClick(View v) { 2457 animateExpandNotificationsPanel(); 2458 } 2459 }; 2460 2461 private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 2462 public void onReceive(Context context, Intent intent) { 2463 if (DEBUG) Log.v(TAG, "onReceive: " + intent); 2464 String action = intent.getAction(); 2465 if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) { 2466 int flags = CommandQueue.FLAG_EXCLUDE_NONE; 2467 if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) { 2468 String reason = intent.getStringExtra("reason"); 2469 if (reason != null && reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) { 2470 flags |= CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL; 2471 } 2472 } 2473 animateCollapsePanels(flags); 2474 } 2475 else if (Intent.ACTION_SCREEN_OFF.equals(action)) { 2476 mScreenOn = false; 2477 notifyNavigationBarScreenOn(false); 2478 notifyHeadsUpScreenOn(false); 2479 finishBarAnimations(); 2480 stopNotificationLogging(); 2481 } 2482 else if (Intent.ACTION_SCREEN_ON.equals(action)) { 2483 mScreenOn = true; 2484 // work around problem where mDisplay.getRotation() is not stable while screen is off (bug 7086018) 2485 repositionNavigationBar(); 2486 notifyNavigationBarScreenOn(true); 2487 startNotificationLoggingIfScreenOnAndVisible(); 2488 } 2489 else if (ACTION_DEMO.equals(action)) { 2490 Bundle bundle = intent.getExtras(); 2491 if (bundle != null) { 2492 String command = bundle.getString("command", "").trim().toLowerCase(); 2493 if (command.length() > 0) { 2494 try { 2495 dispatchDemoCommand(command, bundle); 2496 } catch (Throwable t) { 2497 Log.w(TAG, "Error running demo command, intent=" + intent, t); 2498 } 2499 } 2500 } 2501 } 2502 } 2503 }; 2504 2505 @Override 2506 protected void dismissKeyguardThenExecute(OnDismissAction action) { 2507 if (mStatusBarKeyguardViewManager.isShowing()) { 2508 mStatusBarKeyguardViewManager.dismissWithAction(action); 2509 } else { 2510 action.onDismiss(); 2511 } 2512 } 2513 2514 // SystemUIService notifies SystemBars of configuration changes, which then calls down here 2515 @Override 2516 protected void onConfigurationChanged(Configuration newConfig) { 2517 super.onConfigurationChanged(newConfig); // calls refreshLayout 2518 2519 if (DEBUG) { 2520 Log.v(TAG, "configuration changed: " + mContext.getResources().getConfiguration()); 2521 } 2522 updateDisplaySize(); // populates mDisplayMetrics 2523 2524 updateResources(); 2525 repositionNavigationBar(); 2526 updateExpandedViewPos(EXPANDED_LEAVE_ALONE); 2527 updateShowSearchHoldoff(); 2528 } 2529 2530 @Override 2531 public void userSwitched(int newUserId) { 2532 if (MULTIUSER_DEBUG) mNotificationPanelDebugText.setText("USER " + newUserId); 2533 animateCollapsePanels(); 2534 updateNotifications(); 2535 resetUserSetupObserver(); 2536 } 2537 2538 private void resetUserSetupObserver() { 2539 mContext.getContentResolver().unregisterContentObserver(mUserSetupObserver); 2540 mUserSetupObserver.onChange(false); 2541 mContext.getContentResolver().registerContentObserver( 2542 Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE), true, 2543 mUserSetupObserver, 2544 mCurrentUserId); 2545 } 2546 2547 private void setHeadsUpVisibility(boolean vis) { 2548 if (!ENABLE_HEADS_UP) return; 2549 if (DEBUG) Log.v(TAG, (vis ? "showing" : "hiding") + " heads up window"); 2550 mHeadsUpNotificationView.setVisibility(vis ? View.VISIBLE : View.GONE); 2551 } 2552 2553 public void onHeadsUpDismissed() { 2554 mHeadsUpNotificationView.dismiss(); 2555 } 2556 2557 /** 2558 * Reload some of our resources when the configuration changes. 2559 * 2560 * We don't reload everything when the configuration changes -- we probably 2561 * should, but getting that smooth is tough. Someday we'll fix that. In the 2562 * meantime, just update the things that we know change. 2563 */ 2564 void updateResources() { 2565 // Update the quick setting tiles 2566 if (mQSPanel != null) mQSPanel.updateResources(); 2567 2568 loadDimens(); 2569 } 2570 2571 protected void loadDimens() { 2572 final Resources res = mContext.getResources(); 2573 2574 mNaturalBarHeight = res.getDimensionPixelSize( 2575 com.android.internal.R.dimen.status_bar_height); 2576 2577 int newIconSize = res.getDimensionPixelSize( 2578 com.android.internal.R.dimen.status_bar_icon_size); 2579 int newIconHPadding = res.getDimensionPixelSize( 2580 R.dimen.status_bar_icon_padding); 2581 2582 if (newIconHPadding != mIconHPadding || newIconSize != mIconSize) { 2583// Log.d(TAG, "size=" + newIconSize + " padding=" + newIconHPadding); 2584 mIconHPadding = newIconHPadding; 2585 mIconSize = newIconSize; 2586 //reloadAllNotificationIcons(); // reload the tray 2587 } 2588 2589 mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore); 2590 2591 mSelfExpandVelocityPx = res.getDimension(R.dimen.self_expand_velocity); 2592 mSelfCollapseVelocityPx = res.getDimension(R.dimen.self_collapse_velocity); 2593 mFlingExpandMinVelocityPx = res.getDimension(R.dimen.fling_expand_min_velocity); 2594 mFlingCollapseMinVelocityPx = res.getDimension(R.dimen.fling_collapse_min_velocity); 2595 2596 mCollapseMinDisplayFraction = res.getFraction(R.dimen.collapse_min_display_fraction, 1, 1); 2597 mExpandMinDisplayFraction = res.getFraction(R.dimen.expand_min_display_fraction, 1, 1); 2598 2599 mExpandAccelPx = res.getDimension(R.dimen.expand_accel); 2600 mCollapseAccelPx = res.getDimension(R.dimen.collapse_accel); 2601 2602 mFlingGestureMaxXVelocityPx = res.getDimension(R.dimen.fling_gesture_max_x_velocity); 2603 2604 mFlingGestureMaxOutputVelocityPx = res.getDimension(R.dimen.fling_gesture_max_output_velocity); 2605 2606 mNotificationPanelGravity = res.getInteger(R.integer.notification_panel_layout_gravity); 2607 if (mNotificationPanelGravity <= 0) { 2608 mNotificationPanelGravity = Gravity.START | Gravity.TOP; 2609 } 2610 2611 mCarrierLabelHeight = res.getDimensionPixelSize(R.dimen.carrier_label_height); 2612 mStatusBarHeaderHeight = res.getDimensionPixelSize(R.dimen.status_bar_header_height); 2613 2614 mNotificationPanelMinHeightFrac = res.getFraction(R.dimen.notification_panel_min_height_frac, 1, 1); 2615 if (mNotificationPanelMinHeightFrac < 0f || mNotificationPanelMinHeightFrac > 1f) { 2616 mNotificationPanelMinHeightFrac = 0f; 2617 } 2618 2619 mHeadsUpNotificationDecay = res.getInteger(R.integer.heads_up_notification_decay); 2620 mRowMinHeight = res.getDimensionPixelSize(R.dimen.notification_min_height); 2621 mRowMaxHeight = res.getDimensionPixelSize(R.dimen.notification_max_height); 2622 2623 mKeyguardMaxNotificationCount = res.getInteger(R.integer.keyguard_max_notification_count); 2624 2625 if (false) Log.v(TAG, "updateResources"); 2626 } 2627 2628 // Visibility reporting 2629 2630 @Override 2631 protected void visibilityChanged(boolean visible) { 2632 mVisible = visible; 2633 if (visible) { 2634 startNotificationLoggingIfScreenOnAndVisible(); 2635 } else { 2636 stopNotificationLogging(); 2637 } 2638 super.visibilityChanged(visible); 2639 } 2640 2641 private void stopNotificationLogging() { 2642 // Report all notifications as invisible and turn down the 2643 // reporter. 2644 if (!mCurrentlyVisibleNotifications.isEmpty()) { 2645 logNotificationVisibilityChanges( 2646 Collections.<String>emptyList(), mCurrentlyVisibleNotifications); 2647 mCurrentlyVisibleNotifications.clear(); 2648 } 2649 mHandler.removeCallbacks(mVisibilityReporter); 2650 mStackScroller.setChildLocationsChangedListener(null); 2651 } 2652 2653 private void startNotificationLoggingIfScreenOnAndVisible() { 2654 if (mVisible && mScreenOn) { 2655 mStackScroller.setChildLocationsChangedListener(mNotificationLocationsChangedListener); 2656 // Some transitions like mScreenOn=false -> mScreenOn=true don't 2657 // cause the scroller to emit child location events. Hence generate 2658 // one ourselves to guarantee that we're reporting visible 2659 // notifications. 2660 // (Note that in cases where the scroller does emit events, this 2661 // additional event doesn't break anything.) 2662 mNotificationLocationsChangedListener.onChildLocationsChanged(mStackScroller); 2663 } 2664 } 2665 2666 private void logNotificationVisibilityChanges( 2667 Collection<String> newlyVisible, Collection<String> noLongerVisible) { 2668 if (newlyVisible.isEmpty() && noLongerVisible.isEmpty()) { 2669 return; 2670 } 2671 2672 String[] newlyVisibleAr = newlyVisible.toArray(new String[newlyVisible.size()]); 2673 String[] noLongerVisibleAr = noLongerVisible.toArray(new String[noLongerVisible.size()]); 2674 try { 2675 mBarService.onNotificationVisibilityChanged(newlyVisibleAr, noLongerVisibleAr); 2676 } catch (RemoteException e) { 2677 // Ignore. 2678 } 2679 } 2680 2681 // 2682 // tracing 2683 // 2684 2685 void postStartTracing() { 2686 mHandler.postDelayed(mStartTracing, 3000); 2687 } 2688 2689 void vibrate() { 2690 android.os.Vibrator vib = (android.os.Vibrator)mContext.getSystemService( 2691 Context.VIBRATOR_SERVICE); 2692 vib.vibrate(250, AudioManager.STREAM_SYSTEM); 2693 } 2694 2695 Runnable mStartTracing = new Runnable() { 2696 public void run() { 2697 vibrate(); 2698 SystemClock.sleep(250); 2699 Log.d(TAG, "startTracing"); 2700 android.os.Debug.startMethodTracing("/data/statusbar-traces/trace"); 2701 mHandler.postDelayed(mStopTracing, 10000); 2702 } 2703 }; 2704 2705 Runnable mStopTracing = new Runnable() { 2706 public void run() { 2707 android.os.Debug.stopMethodTracing(); 2708 Log.d(TAG, "stopTracing"); 2709 vibrate(); 2710 } 2711 }; 2712 2713 @Override 2714 protected void haltTicker() { 2715 if (mTickerEnabled) { 2716 mTicker.halt(); 2717 } 2718 } 2719 2720 @Override 2721 protected boolean shouldDisableNavbarGestures() { 2722 return !isDeviceProvisioned() 2723 || mExpandedVisible 2724 || (mDisabled & StatusBarManager.DISABLE_SEARCH) != 0; 2725 } 2726 2727 public void postStartSettingsActivity(final Intent intent, int delay) { 2728 mHandler.postDelayed(new Runnable() { 2729 @Override 2730 public void run() { 2731 handleStartSettingsActivity(intent, true /*onlyProvisioned*/); 2732 } 2733 }, delay); 2734 } 2735 2736 private void handleStartSettingsActivity(Intent intent, boolean onlyProvisioned) { 2737 if (onlyProvisioned && !isDeviceProvisioned()) return; 2738 try { 2739 // Dismiss the lock screen when Settings starts. 2740 ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity(); 2741 } catch (RemoteException e) { 2742 } 2743 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); 2744 mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT)); 2745 animateCollapsePanels(); 2746 } 2747 2748 public void startSettingsActivity(String action) { 2749 postStartSettingsActivity(new Intent(action), 0); 2750 } 2751 2752 private static class FastColorDrawable extends Drawable { 2753 private final int mColor; 2754 2755 public FastColorDrawable(int color) { 2756 mColor = 0xff000000 | color; 2757 } 2758 2759 @Override 2760 public void draw(Canvas canvas) { 2761 canvas.drawColor(mColor, PorterDuff.Mode.SRC); 2762 } 2763 2764 @Override 2765 public void setAlpha(int alpha) { 2766 } 2767 2768 @Override 2769 public void setColorFilter(ColorFilter cf) { 2770 } 2771 2772 @Override 2773 public int getOpacity() { 2774 return PixelFormat.OPAQUE; 2775 } 2776 2777 @Override 2778 public void setBounds(int left, int top, int right, int bottom) { 2779 } 2780 2781 @Override 2782 public void setBounds(Rect bounds) { 2783 } 2784 } 2785 2786 @Override 2787 public void destroy() { 2788 super.destroy(); 2789 if (mStatusBarWindow != null) { 2790 mWindowManager.removeViewImmediate(mStatusBarWindow); 2791 mStatusBarWindow = null; 2792 } 2793 if (mNavigationBarView != null) { 2794 mWindowManager.removeViewImmediate(mNavigationBarView); 2795 mNavigationBarView = null; 2796 } 2797 mContext.unregisterReceiver(mBroadcastReceiver); 2798 } 2799 2800 private boolean mDemoModeAllowed; 2801 private boolean mDemoMode; 2802 private DemoStatusIcons mDemoStatusIcons; 2803 2804 @Override 2805 public void dispatchDemoCommand(String command, Bundle args) { 2806 if (!mDemoModeAllowed) { 2807 mDemoModeAllowed = Settings.Global.getInt(mContext.getContentResolver(), 2808 "sysui_demo_allowed", 0) != 0; 2809 } 2810 if (!mDemoModeAllowed) return; 2811 if (command.equals(COMMAND_ENTER)) { 2812 mDemoMode = true; 2813 } else if (command.equals(COMMAND_EXIT)) { 2814 mDemoMode = false; 2815 checkBarModes(); 2816 } else if (!mDemoMode) { 2817 // automatically enter demo mode on first demo command 2818 dispatchDemoCommand(COMMAND_ENTER, new Bundle()); 2819 } 2820 boolean modeChange = command.equals(COMMAND_ENTER) || command.equals(COMMAND_EXIT); 2821 if (modeChange || command.equals(COMMAND_CLOCK)) { 2822 dispatchDemoCommandToView(command, args, R.id.clock); 2823 } 2824 if (modeChange || command.equals(COMMAND_BATTERY)) { 2825 dispatchDemoCommandToView(command, args, R.id.battery); 2826 } 2827 if (modeChange || command.equals(COMMAND_STATUS)) { 2828 if (mDemoStatusIcons == null) { 2829 mDemoStatusIcons = new DemoStatusIcons(mStatusIcons, mIconSize); 2830 } 2831 mDemoStatusIcons.dispatchDemoCommand(command, args); 2832 } 2833 if (mNetworkController != null && (modeChange || command.equals(COMMAND_NETWORK))) { 2834 mNetworkController.dispatchDemoCommand(command, args); 2835 } 2836 if (modeChange || command.equals(COMMAND_NOTIFICATIONS)) { 2837 View notifications = mStatusBarView == null ? null 2838 : mStatusBarView.findViewById(R.id.notification_icon_area); 2839 if (notifications != null) { 2840 String visible = args.getString("visible"); 2841 int vis = mDemoMode && "false".equals(visible) ? View.INVISIBLE : View.VISIBLE; 2842 notifications.setVisibility(vis); 2843 } 2844 } 2845 if (command.equals(COMMAND_BARS)) { 2846 String mode = args.getString("mode"); 2847 int barMode = "opaque".equals(mode) ? MODE_OPAQUE : 2848 "translucent".equals(mode) ? MODE_TRANSLUCENT : 2849 "semi-transparent".equals(mode) ? MODE_SEMI_TRANSPARENT : 2850 -1; 2851 if (barMode != -1) { 2852 boolean animate = true; 2853 if (mStatusBarView != null) { 2854 mStatusBarView.getBarTransitions().transitionTo(barMode, animate); 2855 } 2856 if (mNavigationBarView != null) { 2857 mNavigationBarView.getBarTransitions().transitionTo(barMode, animate); 2858 } 2859 } 2860 } 2861 } 2862 2863 private void dispatchDemoCommandToView(String command, Bundle args, int id) { 2864 if (mStatusBarView == null) return; 2865 View v = mStatusBarView.findViewById(id); 2866 if (v instanceof DemoMode) { 2867 ((DemoMode)v).dispatchDemoCommand(command, args); 2868 } 2869 } 2870 2871 /** 2872 * @return The {@link StatusBarState} the status bar is in. 2873 */ 2874 public int getBarState() { 2875 return mState; 2876 } 2877 2878 public void showKeyguard() { 2879 setBarState(StatusBarState.KEYGUARD); 2880 updateKeyguardState(); 2881 instantExpandNotificationsPanel(); 2882 mLeaveOpenOnKeyguardHide = false; 2883 } 2884 2885 public void hideKeyguard() { 2886 setBarState(StatusBarState.SHADE); 2887 if (mLeaveOpenOnKeyguardHide) { 2888 mLeaveOpenOnKeyguardHide = false; 2889 mNotificationPanel.animateToFullShade(); 2890 } else { 2891 instantCollapseNotificationPanel(); 2892 } 2893 updateKeyguardState(); 2894 } 2895 2896 private void updatePublicMode() { 2897 setLockscreenPublicMode( 2898 (mStatusBarKeyguardViewManager.isShowing() || 2899 mStatusBarKeyguardViewManager.isOccluded()) 2900 && mStatusBarKeyguardViewManager.isSecure()); 2901 } 2902 2903 private void updateKeyguardState() { 2904 if (mState == StatusBarState.KEYGUARD) { 2905 mKeyguardStatusView.setVisibility(View.VISIBLE); 2906 mKeyguardIndicationController.setVisible(true); 2907 mNotificationPanel.resetViews(); 2908 } else { 2909 mKeyguardStatusView.setVisibility(View.GONE); 2910 mKeyguardIndicationController.setVisible(false); 2911 } 2912 if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) { 2913 mKeyguardBottomArea.setVisibility(View.VISIBLE); 2914 mHeader.setKeyguardShowing(true); 2915 mNotificationPanel.setKeyguardShowing(true); 2916 mScrimController.setKeyguardShowing(true); 2917 } else { 2918 mKeyguardBottomArea.setVisibility(View.GONE); 2919 mHeader.setKeyguardShowing(false); 2920 mNotificationPanel.setKeyguardShowing(false); 2921 mScrimController.setKeyguardShowing(false); 2922 } 2923 updateStackScrollerState(); 2924 updatePublicMode(); 2925 updateNotifications(); 2926 checkBarModes(); 2927 updateCarrierLabelVisibility(false); 2928 } 2929 2930 public void updateStackScrollerState() { 2931 if (mStackScroller == null) return; 2932 boolean onKeyguard = mState == StatusBarState.KEYGUARD; 2933 mStackScroller.setDimmed(onKeyguard, false /* animate */); 2934 mStackScroller.setVisibility(!mShowLockscreenNotifications && onKeyguard 2935 ? View.INVISIBLE : View.VISIBLE); 2936 mStackScroller.setScrollingEnabled(!onKeyguard); 2937 mStackScroller.setExpandingEnabled(!onKeyguard); 2938 ActivatableNotificationView activatedChild = mStackScroller.getActivatedChild(); 2939 mStackScroller.setActivatedChild(null); 2940 if (activatedChild != null) { 2941 activatedChild.makeInactive(false /* animate */); 2942 } 2943 } 2944 2945 public void userActivity() { 2946 mHandler.removeCallbacks(mUserActivity); 2947 mHandler.post(mUserActivity); 2948 } 2949 2950 public boolean interceptMediaKey(KeyEvent event) { 2951 return mState == StatusBarState.KEYGUARD 2952 && mStatusBarKeyguardViewManager.interceptMediaKey(event); 2953 } 2954 2955 public boolean onMenuPressed() { 2956 return mState == StatusBarState.KEYGUARD && mStatusBarKeyguardViewManager.onMenuPressed(); 2957 } 2958 2959 public boolean onBackPressed() { 2960 if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) { 2961 return mStatusBarKeyguardViewManager.onBackPressed(); 2962 } else { 2963 animateCollapsePanels(); 2964 return true; 2965 } 2966 } 2967 2968 private void showBouncer() { 2969 if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) { 2970 mStatusBarKeyguardViewManager.dismiss(); 2971 } 2972 } 2973 2974 private void instantExpandNotificationsPanel() { 2975 2976 // Make our window larger and the panel expanded. 2977 makeExpandedVisible(true); 2978 mNotificationPanel.instantExpand(); 2979 } 2980 2981 private void instantCollapseNotificationPanel() { 2982 mNotificationPanel.setExpandedFraction(0); 2983 } 2984 2985 @Override 2986 public void onActivated(ActivatableNotificationView view) { 2987 userActivity(); 2988 mKeyguardIndicationController.showTransientIndication(R.string.notification_tap_again); 2989 ActivatableNotificationView previousView = mStackScroller.getActivatedChild(); 2990 if (previousView != null) { 2991 previousView.makeInactive(true /* animate */); 2992 } 2993 mStackScroller.setActivatedChild(view); 2994 } 2995 2996 /** 2997 * @param state The {@link StatusBarState} to set. 2998 */ 2999 public void setBarState(int state) { 3000 mState = state; 3001 mStatusBarWindowManager.setStatusBarState(state); 3002 } 3003 3004 @Override 3005 public void onActivationReset(ActivatableNotificationView view) { 3006 if (view == mStackScroller.getActivatedChild()) { 3007 mKeyguardIndicationController.hideTransientIndication(); 3008 mStackScroller.setActivatedChild(null); 3009 } 3010 } 3011 3012 public void onTrackingStarted() { 3013 } 3014 3015 public void onUnlockHintStarted() { 3016 mKeyguardIndicationController.showTransientIndication(R.string.keyguard_unlock); 3017 } 3018 3019 public void onHintFinished() { 3020 // Delay the reset a bit so the user can read the text. 3021 mKeyguardIndicationController.hideTransientIndicationDelayed(HINT_RESET_DELAY_MS); 3022 } 3023 3024 public void onCameraHintStarted() { 3025 mKeyguardIndicationController.showTransientIndication(R.string.camera_hint); 3026 } 3027 3028 public void onPhoneHintStarted() { 3029 mKeyguardIndicationController.showTransientIndication(R.string.phone_hint); 3030 } 3031 3032 public void onTrackingStopped(boolean expand) { 3033 if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) { 3034 if (!expand && !mUnlockMethodCache.isMethodInsecure()) { 3035 showBouncer(); 3036 } 3037 } 3038 } 3039 3040 @Override 3041 protected int getMaxKeyguardNotifications() { 3042 return mKeyguardMaxNotificationCount; 3043 } 3044 3045 public NavigationBarView getNavigationBarView() { 3046 return mNavigationBarView; 3047 } 3048 3049 // ---------------------- DragDownHelper.OnDragDownListener ------------------------------------ 3050 3051 @Override 3052 public void onDraggedDown(View startingChild) { 3053 goToLockedShade(startingChild); 3054 } 3055 3056 @Override 3057 public void onDragDownReset() { 3058 mStackScroller.setDimmed(true /* dimmed */, true /* animated */); 3059 } 3060 3061 public void onThresholdReached() { 3062 mStackScroller.setDimmed(false /* dimmed */, true /* animate */); 3063 } 3064 3065 @Override 3066 public void onTouchSlopExceeded() { 3067 mStackScroller.removeLongPressCallback(); 3068 } 3069 3070 /** 3071 * If secure with redaction: Show bouncer, go to unlocked shade. 3072 * 3073 * <p>If secure without redaction or no security: Go to {@link StatusBarState#SHADE_LOCKED}.</p> 3074 * 3075 * @param expandView The view to expand after going to the shade. 3076 */ 3077 public void goToLockedShade(View expandView) { 3078 if (expandView instanceof ExpandableNotificationRow) { 3079 ExpandableNotificationRow row = (ExpandableNotificationRow) expandView; 3080 row.setUserExpanded(true); 3081 } 3082 if (isLockscreenPublicMode() && !userAllowsPrivateNotificationsInPublic(mCurrentUserId)) { 3083 mLeaveOpenOnKeyguardHide = true; 3084 showBouncer(); 3085 } else { 3086 mNotificationPanel.animateToFullShade(); 3087 setBarState(StatusBarState.SHADE_LOCKED); 3088 updateKeyguardState(); 3089 } 3090 } 3091 3092 /** 3093 * Goes back to the keyguard after hanging around in {@link StatusBarState#SHADE_LOCKED}. 3094 */ 3095 public void goToKeyguard() { 3096 if (mState == StatusBarState.SHADE_LOCKED) { 3097 setBarState(StatusBarState.KEYGUARD); 3098 updateKeyguardState(); 3099 } 3100 } 3101 3102 /** 3103 * @return a ViewGroup that spans the entire panel which contains the quick settings 3104 */ 3105 public ViewGroup getQuickSettingsOverlayParent() { 3106 return mNotificationPanel; 3107 } 3108 3109 public LinearLayout getSystemIcons() { 3110 return mSystemIcons; 3111 } 3112 3113 /** 3114 * Reattaches the system icons to its normal parent in collapsed status bar. 3115 */ 3116 public void reattachSystemIcons() { 3117 mSystemIconArea.addView(mSystemIcons, 0); 3118 } 3119 3120 public void onScreenTurnedOff() { 3121 mStackScroller.setAnimationsEnabled(false); 3122 } 3123 3124 public void onScreenTurnedOn() { 3125 mStackScroller.setAnimationsEnabled(true); 3126 } 3127 3128 private final Runnable mUserActivity = new Runnable() { 3129 @Override 3130 public void run() { 3131 if (mState == StatusBarState.KEYGUARD) { 3132 mKeyguardViewMediatorCallback.userActivity(); 3133 } 3134 } 3135 }; 3136 3137 // Recents 3138 3139 @Override 3140 protected void showRecents(boolean triggeredFromAltTab) { 3141 // Set the recents visibility flag 3142 mSystemUiVisibility |= View.RECENT_APPS_VISIBLE; 3143 notifyUiVisibilityChanged(mSystemUiVisibility); 3144 super.showRecents(triggeredFromAltTab); 3145 } 3146 3147 @Override 3148 protected void hideRecents(boolean triggeredFromAltTab) { 3149 // Unset the recents visibility flag 3150 mSystemUiVisibility &= ~View.RECENT_APPS_VISIBLE; 3151 notifyUiVisibilityChanged(mSystemUiVisibility); 3152 super.hideRecents(triggeredFromAltTab); 3153 } 3154 3155 @Override 3156 protected void toggleRecents() { 3157 // Toggle the recents visibility flag 3158 mSystemUiVisibility ^= View.RECENT_APPS_VISIBLE; 3159 notifyUiVisibilityChanged(mSystemUiVisibility); 3160 super.toggleRecents(); 3161 } 3162} 3163