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