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