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