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