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