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