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