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