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