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