PhoneStatusBar.java revision d63c59786509aadd6a8d0c5cb45ed696339f16b7
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 android.animation.Animator; 20import android.animation.AnimatorListenerAdapter; 21import android.animation.AnimatorSet; 22import android.animation.LayoutTransition; 23import android.animation.ObjectAnimator; 24import android.app.ActivityManager; 25import android.app.ActivityManagerNative; 26import android.app.Notification; 27import android.app.PendingIntent; 28import android.app.StatusBarManager; 29import android.content.BroadcastReceiver; 30import android.content.Context; 31import android.content.Intent; 32import android.content.IntentFilter; 33import android.content.res.Resources; 34import android.graphics.Canvas; 35import android.graphics.ColorFilter; 36import android.graphics.PixelFormat; 37import android.graphics.PorterDuff; 38import android.graphics.Rect; 39import android.graphics.drawable.Drawable; 40import android.graphics.drawable.NinePatchDrawable; 41import android.inputmethodservice.InputMethodService; 42import android.os.IBinder; 43import android.os.Message; 44import android.os.RemoteException; 45import android.os.ServiceManager; 46import android.os.SystemClock; 47import android.os.UserHandle; 48import android.provider.Settings; 49import android.service.dreams.IDreamManager; 50import android.util.DisplayMetrics; 51import android.util.Log; 52import android.util.Slog; 53import android.view.Display; 54import android.view.Gravity; 55import android.view.LayoutInflater; 56import android.view.MotionEvent; 57import android.view.VelocityTracker; 58import android.view.View; 59import android.view.ViewGroup; 60import android.view.ViewGroup.LayoutParams; 61import android.view.WindowManager; 62import android.view.animation.AccelerateInterpolator; 63import android.view.animation.Animation; 64import android.view.animation.AnimationUtils; 65import android.view.animation.DecelerateInterpolator; 66import android.widget.FrameLayout; 67import android.widget.ImageView; 68import android.widget.LinearLayout; 69import android.widget.ScrollView; 70import android.widget.TextView; 71 72import com.android.internal.statusbar.StatusBarIcon; 73import com.android.internal.statusbar.StatusBarNotification; 74import com.android.systemui.R; 75import com.android.systemui.statusbar.BaseStatusBar; 76import com.android.systemui.statusbar.CommandQueue; 77import com.android.systemui.statusbar.GestureRecorder; 78import com.android.systemui.statusbar.NotificationData; 79import com.android.systemui.statusbar.NotificationData.Entry; 80import com.android.systemui.statusbar.RotationToggle; 81import com.android.systemui.statusbar.SignalClusterView; 82import com.android.systemui.statusbar.StatusBarIconView; 83import com.android.systemui.statusbar.policy.BatteryController; 84import com.android.systemui.statusbar.policy.BluetoothController; 85import com.android.systemui.statusbar.policy.DateView; 86import com.android.systemui.statusbar.policy.IntruderAlertView; 87import com.android.systemui.statusbar.policy.LocationController; 88import com.android.systemui.statusbar.policy.NetworkController; 89import com.android.systemui.statusbar.policy.NotificationRowLayout; 90import com.android.systemui.statusbar.policy.OnSizeChangedListener; 91 92import java.io.FileDescriptor; 93import java.io.PrintWriter; 94import java.util.ArrayList; 95 96public class PhoneStatusBar extends BaseStatusBar { 97 static final String TAG = "PhoneStatusBar"; 98 public static final boolean DEBUG = false; 99 public static final boolean SPEW = DEBUG; 100 public static final boolean DUMPTRUCK = true; // extra dumpsys info 101 102 // additional instrumentation for testing purposes; intended to be left on during development 103 public static final boolean CHATTY = DEBUG; 104 105 public static final String ACTION_STATUSBAR_START 106 = "com.android.internal.policy.statusbar.START"; 107 108 private static final int MSG_OPEN_NOTIFICATION_PANEL = 1000; 109 private static final int MSG_CLOSE_NOTIFICATION_PANEL = 1001; 110 // 1020-1030 reserved for BaseStatusBar 111 112 // will likely move to a resource or other tunable param at some point 113 private static final int INTRUDER_ALERT_DECAY_MS = 0; // disabled, was 10000; 114 115 private static final boolean CLOSE_PANEL_WHEN_EMPTIED = true; 116 117 private static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10; // see NotificationManagerService 118 private static final int HIDE_ICONS_BELOW_SCORE = Notification.PRIORITY_LOW * NOTIFICATION_PRIORITY_MULTIPLIER; 119 120 // fling gesture tuning parameters, scaled to display density 121 private float mSelfExpandVelocityPx; // classic value: 2000px/s 122 private float mSelfCollapseVelocityPx; // classic value: 2000px/s (will be negated to collapse "up") 123 private float mFlingExpandMinVelocityPx; // classic value: 200px/s 124 private float mFlingCollapseMinVelocityPx; // classic value: 200px/s 125 private float mCollapseMinDisplayFraction; // classic value: 0.08 (25px/min(320px,480px) on G1) 126 private float mExpandMinDisplayFraction; // classic value: 0.5 (drag open halfway to expand) 127 private float mFlingGestureMaxXVelocityPx; // classic value: 150px/s 128 129 private float mExpandAccelPx; // classic value: 2000px/s/s 130 private float mCollapseAccelPx; // classic value: 2000px/s/s (will be negated to collapse "up") 131 132 private float mFlingGestureMaxOutputVelocityPx; // how fast can it really go? (should be a little 133 // faster than mSelfCollapseVelocityPx) 134 135 PhoneStatusBarPolicy mIconPolicy; 136 137 // These are no longer handled by the policy, because we need custom strategies for them 138 BluetoothController mBluetoothController; 139 BatteryController mBatteryController; 140 LocationController mLocationController; 141 NetworkController mNetworkController; 142 143 int mNaturalBarHeight = -1; 144 int mIconSize = -1; 145 int mIconHPadding = -1; 146 Display mDisplay; 147 148 IDreamManager mDreamManager; 149 150 StatusBarWindowView mStatusBarWindow; 151 PhoneStatusBarView mStatusBarView; 152 153 int mPixelFormat; 154 Object mQueueLock = new Object(); 155 156 // icons 157 LinearLayout mIcons; 158 IconMerger mNotificationIcons; 159 View mMoreIcon; 160 LinearLayout mStatusIcons; 161 162 // expanded notifications 163 PanelView mNotificationPanel; // the sliding/resizing panel within the notification window 164 ScrollView mScrollView; 165 View mExpandedContents; 166 final Rect mNotificationPanelBackgroundPadding = new Rect(); 167 int mNotificationPanelGravity; 168 int mNotificationPanelMarginBottomPx, mNotificationPanelMarginPx; 169 int mNotificationPanelMinHeight; 170 boolean mNotificationPanelIsFullScreenWidth; 171 TextView mNotificationPanelDebugText; 172 173 // settings 174 PanelView mSettingsPanel; 175 int mSettingsPanelGravity; 176 177 // top bar 178 View mClearButton; 179 View mSettingsButton; 180 RotationToggle mRotationButton; 181 182 // carrier/wifi label 183 private TextView mCarrierLabel; 184 private boolean mCarrierLabelVisible = false; 185 private int mCarrierLabelHeight; 186 private TextView mEmergencyCallLabel; 187 private int mNotificationHeaderHeight; 188 189 private boolean mShowCarrierInPanel = false; 190 191 // position 192 int[] mPositionTmp = new int[2]; 193 boolean mExpandedVisible; 194 195 // the date view 196 DateView mDateView; 197 198 // for immersive activities 199 private IntruderAlertView mIntruderAlertView; 200 201 // on-screen navigation buttons 202 private NavigationBarView mNavigationBarView = null; 203 204 // the tracker view 205 int mTrackingPosition; // the position of the top of the tracking view. 206 207 // ticker 208 private Ticker mTicker; 209 private View mTickerView; 210 private boolean mTicking; 211 212 // Tracking finger for opening/closing. 213 int mEdgeBorder; // corresponds to R.dimen.status_bar_edge_ignore 214 boolean mTracking; 215 VelocityTracker mVelocityTracker; 216 217 boolean mAnimating; 218 boolean mClosing; // only valid when mAnimating; indicates the initial acceleration 219 float mAnimY; 220 float mAnimVel; 221 float mAnimAccel; 222 long mAnimLastTimeNanos; 223 boolean mAnimatingReveal = false; 224 int mViewDelta; 225 float mFlingVelocity; 226 int mFlingY; 227 int[] mAbsPos = new int[2]; 228 Runnable mPostCollapseCleanup = null; 229 230 private AnimatorSet mLightsOutAnimation; 231 private AnimatorSet mLightsOnAnimation; 232 233 // for disabling the status bar 234 int mDisabled = 0; 235 236 // tracking calls to View.setSystemUiVisibility() 237 int mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE; 238 239 DisplayMetrics mDisplayMetrics = new DisplayMetrics(); 240 241 // XXX: gesture research 242 private GestureRecorder mGestureRec = new GestureRecorder("/sdcard/statusbar_gestures.dat"); 243 244 private int mNavigationIconHints = 0; 245 private final Animator.AnimatorListener mMakeIconsInvisible = new AnimatorListenerAdapter() { 246 @Override 247 public void onAnimationEnd(Animator animation) { 248 // double-check to avoid races 249 if (mIcons.getAlpha() == 0) { 250 Slog.d(TAG, "makeIconsInvisible"); 251 mIcons.setVisibility(View.INVISIBLE); 252 } 253 } 254 }; 255 256 @Override 257 public void start() { 258 mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE)) 259 .getDefaultDisplay(); 260 261 mDreamManager = IDreamManager.Stub.asInterface( 262 ServiceManager.checkService("dreams")); 263 264 super.start(); // calls createAndAddWindows() 265 266 addNavigationBar(); 267 268 if (ENABLE_INTRUDERS) addIntruderView(); 269 270 // Lastly, call to the icon policy to install/update all the icons. 271 mIconPolicy = new PhoneStatusBarPolicy(mContext); 272 } 273 274 // ================================================================================ 275 // Constructing the view 276 // ================================================================================ 277 protected PhoneStatusBarView makeStatusBarView() { 278 final Context context = mContext; 279 280 Resources res = context.getResources(); 281 282 updateDisplaySize(); // populates mDisplayMetrics 283 loadDimens(); 284 285 mIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size); 286 287 mStatusBarWindow = (StatusBarWindowView) View.inflate(context, 288 R.layout.super_status_bar, null); 289 if (DEBUG) { 290 mStatusBarWindow.setBackgroundColor(0x6000FF80); 291 } 292 mStatusBarWindow.mService = this; 293 mStatusBarWindow.setOnTouchListener(new View.OnTouchListener() { 294 @Override 295 public boolean onTouch(View v, MotionEvent event) { 296 if (event.getAction() == MotionEvent.ACTION_DOWN) { 297 if (mExpandedVisible && !mAnimating) { 298 animateCollapse(); 299 } 300 } 301 return mStatusBarWindow.onTouchEvent(event); 302 }}); 303 304 mStatusBarView = (PhoneStatusBarView) mStatusBarWindow.findViewById(R.id.status_bar); 305 mStatusBarView.setBar(this); 306 307 PanelHolder holder = (PanelHolder) mStatusBarWindow.findViewById(R.id.panel_holder); 308 mStatusBarView.setPanelHolder(holder); 309 310 mNotificationPanel = (PanelView) mStatusBarWindow.findViewById(R.id.notification_panel); 311 mNotificationPanelIsFullScreenWidth = 312 (mNotificationPanel.getLayoutParams().width == ViewGroup.LayoutParams.MATCH_PARENT); 313 mNotificationPanel.setSystemUiVisibility( 314 View.STATUS_BAR_DISABLE_NOTIFICATION_TICKER 315 | (mNotificationPanelIsFullScreenWidth ? 0 : View.STATUS_BAR_DISABLE_SYSTEM_INFO)); 316 317 if (!ActivityManager.isHighEndGfx()) { 318 mStatusBarWindow.setBackground(null); 319 mNotificationPanel.setBackground(new FastColorDrawable(context.getResources().getColor( 320 R.color.notification_panel_solid_background))); 321 mSettingsPanel.setBackground(new FastColorDrawable(context.getResources().getColor( 322 R.color.notification_panel_solid_background))); 323 } 324 if (ENABLE_INTRUDERS) { 325 mIntruderAlertView = (IntruderAlertView) View.inflate(context, R.layout.intruder_alert, null); 326 mIntruderAlertView.setVisibility(View.GONE); 327 mIntruderAlertView.setBar(this); 328 } 329 if (MULTIUSER_DEBUG) { 330 mNotificationPanelDebugText = (TextView) mNotificationPanel.findViewById(R.id.header_debug_info); 331 mNotificationPanelDebugText.setVisibility(View.VISIBLE); 332 } 333 334 updateShowSearchHoldoff(); 335 336 try { 337 boolean showNav = mWindowManagerService.hasNavigationBar(); 338 if (DEBUG) Slog.v(TAG, "hasNavigationBar=" + showNav); 339 if (showNav) { 340 mNavigationBarView = 341 (NavigationBarView) View.inflate(context, R.layout.navigation_bar, null); 342 343 mNavigationBarView.setDisabledFlags(mDisabled); 344 mNavigationBarView.setBar(this); 345 } 346 } catch (RemoteException ex) { 347 // no window manager? good luck with that 348 } 349 350 // figure out which pixel-format to use for the status bar. 351 mPixelFormat = PixelFormat.OPAQUE; 352 mStatusIcons = (LinearLayout)mStatusBarView.findViewById(R.id.statusIcons); 353 mNotificationIcons = (IconMerger)mStatusBarView.findViewById(R.id.notificationIcons); 354 mNotificationIcons.setOverflowIndicator(mMoreIcon); 355 mIcons = (LinearLayout)mStatusBarView.findViewById(R.id.icons); 356 mTickerView = mStatusBarView.findViewById(R.id.ticker); 357 358 mPile = (NotificationRowLayout)mStatusBarWindow.findViewById(R.id.latestItems); 359 mPile.setLayoutTransitionsEnabled(false); 360 mPile.setLongPressListener(getNotificationLongClicker()); 361 mExpandedContents = mPile; // was: expanded.findViewById(R.id.notificationLinearLayout); 362 363 mClearButton = mStatusBarWindow.findViewById(R.id.clear_all_button); 364 mClearButton.setOnClickListener(mClearButtonListener); 365 mClearButton.setAlpha(0f); 366 mClearButton.setVisibility(View.INVISIBLE); 367 mClearButton.setEnabled(false); 368 mDateView = (DateView)mStatusBarWindow.findViewById(R.id.date); 369 mSettingsButton = mStatusBarWindow.findViewById(R.id.settings_button); 370 mSettingsButton.setOnClickListener(mSettingsButtonListener); 371 mRotationButton = (RotationToggle) mStatusBarWindow.findViewById(R.id.rotation_lock_button); 372 373 mScrollView = (ScrollView)mStatusBarWindow.findViewById(R.id.scroll); 374 mScrollView.setVerticalScrollBarEnabled(false); // less drawing during pulldowns 375 376 mTicker = new MyTicker(context, mStatusBarView); 377 378 TickerView tickerView = (TickerView)mStatusBarView.findViewById(R.id.tickerText); 379 tickerView.mTicker = mTicker; 380 381 mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore); 382 383 // set the inital view visibility 384 setAreThereNotifications(); 385 386 // Other icons 387 mLocationController = new LocationController(mContext); // will post a notification 388 mBatteryController = new BatteryController(mContext); 389 mBatteryController.addIconView((ImageView)mStatusBarView.findViewById(R.id.battery)); 390 mNetworkController = new NetworkController(mContext); 391 mBluetoothController = new BluetoothController(mContext); 392 final SignalClusterView signalCluster = 393 (SignalClusterView)mStatusBarView.findViewById(R.id.signal_cluster); 394 395 396 mNetworkController.addSignalCluster(signalCluster); 397 signalCluster.setNetworkController(mNetworkController); 398 399 mEmergencyCallLabel = (TextView)mStatusBarWindow.findViewById(R.id.emergency_calls_only); 400 if (mEmergencyCallLabel != null) { 401 mNetworkController.addEmergencyLabelView(mEmergencyCallLabel); 402 mEmergencyCallLabel.addOnLayoutChangeListener(new View.OnLayoutChangeListener() { 403 @Override 404 public void onLayoutChange(View v, int left, int top, int right, int bottom, 405 int oldLeft, int oldTop, int oldRight, int oldBottom) { 406 updateCarrierLabelVisibility(false); 407 }}); 408 } 409 410 mCarrierLabel = (TextView)mStatusBarWindow.findViewById(R.id.carrier_label); 411 mShowCarrierInPanel = (mCarrierLabel != null); 412 Slog.v(TAG, "carrierlabel=" + mCarrierLabel + " show=" + mShowCarrierInPanel); 413 if (mShowCarrierInPanel) { 414 mCarrierLabel.setVisibility(mCarrierLabelVisible ? View.VISIBLE : View.INVISIBLE); 415 416 // for mobile devices, we always show mobile connection info here (SPN/PLMN) 417 // for other devices, we show whatever network is connected 418 if (mNetworkController.hasMobileDataFeature()) { 419 mNetworkController.addMobileLabelView(mCarrierLabel); 420 } else { 421 mNetworkController.addCombinedLabelView(mCarrierLabel); 422 } 423 424 // set up the dynamic hide/show of the label 425 mPile.setOnSizeChangedListener(new OnSizeChangedListener() { 426 @Override 427 public void onSizeChanged(View view, int w, int h, int oldw, int oldh) { 428 updateCarrierLabelVisibility(false); 429 } 430 }); 431 } 432 433 // Quick Settings (WIP) 434 mSettingsPanel = (PanelView) mStatusBarWindow.findViewById(R.id.settings_panel); 435 mSettingsPanel.setBar(mStatusBarView); 436 mSettingsPanel.setup(mNetworkController, mBluetoothController, mBatteryController, 437 mLocationController); 438 439// final ImageView wimaxRSSI = 440// (ImageView)sb.findViewById(R.id.wimax_signal); 441// if (wimaxRSSI != null) { 442// mNetworkController.addWimaxIconView(wimaxRSSI); 443// } 444 445 // receive broadcasts 446 IntentFilter filter = new IntentFilter(); 447 filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); 448 filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); 449 filter.addAction(Intent.ACTION_SCREEN_OFF); 450 filter.addAction(Intent.ACTION_SCREEN_ON); 451 context.registerReceiver(mBroadcastReceiver, filter); 452 453 return mStatusBarView; 454 } 455 456 @Override 457 protected View getStatusBarView() { 458 return mStatusBarView; 459 } 460 461 @Override 462 protected WindowManager.LayoutParams getRecentsLayoutParams(LayoutParams layoutParams) { 463 boolean opaque = false; 464 WindowManager.LayoutParams lp = new WindowManager.LayoutParams( 465 layoutParams.width, 466 layoutParams.height, 467 WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL, 468 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN 469 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM 470 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, 471 (opaque ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT)); 472 if (ActivityManager.isHighEndGfx()) { 473 lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; 474 } else { 475 lp.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND; 476 lp.dimAmount = 0.75f; 477 } 478 lp.gravity = Gravity.BOTTOM | Gravity.LEFT; 479 lp.setTitle("RecentsPanel"); 480 lp.windowAnimations = com.android.internal.R.style.Animation_RecentApplications; 481 lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED 482 | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING; 483 return lp; 484 } 485 486 @Override 487 protected WindowManager.LayoutParams getSearchLayoutParams(LayoutParams layoutParams) { 488 boolean opaque = false; 489 WindowManager.LayoutParams lp = new WindowManager.LayoutParams( 490 LayoutParams.MATCH_PARENT, 491 LayoutParams.MATCH_PARENT, 492 WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL, 493 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN 494 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM 495 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, 496 (opaque ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT)); 497 if (ActivityManager.isHighEndGfx()) { 498 lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; 499 } 500 lp.gravity = Gravity.BOTTOM | Gravity.LEFT; 501 lp.setTitle("SearchPanel"); 502 // TODO: Define custom animation for Search panel 503 lp.windowAnimations = com.android.internal.R.style.Animation_RecentApplications; 504 lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED 505 | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING; 506 return lp; 507 } 508 509 @Override 510 protected void updateSearchPanel() { 511 super.updateSearchPanel(); 512 mSearchPanelView.setStatusBarView(mNavigationBarView); 513 mNavigationBarView.setDelegateView(mSearchPanelView); 514 } 515 516 @Override 517 public void showSearchPanel() { 518 super.showSearchPanel(); 519 WindowManager.LayoutParams lp = 520 (android.view.WindowManager.LayoutParams) mNavigationBarView.getLayoutParams(); 521 lp.flags &= ~WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; 522 mWindowManager.updateViewLayout(mNavigationBarView, lp); 523 } 524 525 @Override 526 public void hideSearchPanel() { 527 super.hideSearchPanel(); 528 WindowManager.LayoutParams lp = 529 (android.view.WindowManager.LayoutParams) mNavigationBarView.getLayoutParams(); 530 lp.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; 531 mWindowManager.updateViewLayout(mNavigationBarView, lp); 532 } 533 534 protected int getStatusBarGravity() { 535 return Gravity.TOP | Gravity.FILL_HORIZONTAL; 536 } 537 538 public int getStatusBarHeight() { 539 if (mNaturalBarHeight < 0) { 540 final Resources res = mContext.getResources(); 541 mNaturalBarHeight = 542 res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height); 543 } 544 return mNaturalBarHeight; 545 } 546 547 private View.OnClickListener mRecentsClickListener = new View.OnClickListener() { 548 public void onClick(View v) { 549 toggleRecentApps(); 550 } 551 }; 552 553 private int mShowSearchHoldoff = 0; 554 private Runnable mShowSearchPanel = new Runnable() { 555 public void run() { 556 showSearchPanel(); 557 awakenDreams(); 558 } 559 }; 560 561 View.OnTouchListener mHomeSearchActionListener = new View.OnTouchListener() { 562 public boolean onTouch(View v, MotionEvent event) { 563 switch(event.getAction()) { 564 case MotionEvent.ACTION_DOWN: 565 if (!shouldDisableNavbarGestures() && !inKeyguardRestrictedInputMode()) { 566 mHandler.removeCallbacks(mShowSearchPanel); 567 mHandler.postDelayed(mShowSearchPanel, mShowSearchHoldoff); 568 } 569 break; 570 571 case MotionEvent.ACTION_UP: 572 case MotionEvent.ACTION_CANCEL: 573 mHandler.removeCallbacks(mShowSearchPanel); 574 awakenDreams(); 575 break; 576 } 577 return false; 578 } 579 }; 580 581 private void awakenDreams() { 582 if (mDreamManager != null) { 583 try { 584 mDreamManager.awaken(); 585 } catch (RemoteException e) { 586 // fine, stay asleep then 587 } 588 } 589 } 590 591 private void prepareNavigationBarView() { 592 mNavigationBarView.reorient(); 593 594 mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener); 595 mNavigationBarView.getRecentsButton().setOnTouchListener(getRecentTasksLoader()); 596 mNavigationBarView.getHomeButton().setOnTouchListener(mHomeSearchActionListener); 597 updateSearchPanel(); 598 } 599 600 // For small-screen devices (read: phones) that lack hardware navigation buttons 601 private void addNavigationBar() { 602 if (DEBUG) Slog.v(TAG, "addNavigationBar: about to add " + mNavigationBarView); 603 if (mNavigationBarView == null) return; 604 605 prepareNavigationBarView(); 606 607 mWindowManager.addView(mNavigationBarView, getNavigationBarLayoutParams()); 608 } 609 610 private void repositionNavigationBar() { 611 if (mNavigationBarView == null) return; 612 613 prepareNavigationBarView(); 614 615 mWindowManager.updateViewLayout(mNavigationBarView, getNavigationBarLayoutParams()); 616 } 617 618 private WindowManager.LayoutParams getNavigationBarLayoutParams() { 619 WindowManager.LayoutParams lp = new WindowManager.LayoutParams( 620 LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, 621 WindowManager.LayoutParams.TYPE_NAVIGATION_BAR, 622 0 623 | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING 624 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 625 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL 626 | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH 627 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, 628 PixelFormat.OPAQUE); 629 // this will allow the navbar to run in an overlay on devices that support this 630 if (ActivityManager.isHighEndGfx()) { 631 lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; 632 } 633 634 lp.setTitle("NavigationBar"); 635 lp.windowAnimations = 0; 636 return lp; 637 } 638 639 private void addIntruderView() { 640 WindowManager.LayoutParams lp = new WindowManager.LayoutParams( 641 ViewGroup.LayoutParams.MATCH_PARENT, 642 ViewGroup.LayoutParams.WRAP_CONTENT, 643 WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL, // above the status bar! 644 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN 645 | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS 646 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL 647 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 648 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM 649 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, 650 PixelFormat.TRANSLUCENT); 651 lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL; 652 //lp.y += height * 1.5; // FIXME 653 lp.setTitle("IntruderAlert"); 654 lp.packageName = mContext.getPackageName(); 655 lp.windowAnimations = R.style.Animation_StatusBar_IntruderAlert; 656 657 mWindowManager.addView(mIntruderAlertView, lp); 658 } 659 660 public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) { 661 if (SPEW) Slog.d(TAG, "addIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex 662 + " icon=" + icon); 663 StatusBarIconView view = new StatusBarIconView(mContext, slot, null); 664 view.set(icon); 665 mStatusIcons.addView(view, viewIndex, new LinearLayout.LayoutParams(mIconSize, mIconSize)); 666 } 667 668 public void updateIcon(String slot, int index, int viewIndex, 669 StatusBarIcon old, StatusBarIcon icon) { 670 if (SPEW) Slog.d(TAG, "updateIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex 671 + " old=" + old + " icon=" + icon); 672 StatusBarIconView view = (StatusBarIconView)mStatusIcons.getChildAt(viewIndex); 673 view.set(icon); 674 } 675 676 public void removeIcon(String slot, int index, int viewIndex) { 677 if (SPEW) Slog.d(TAG, "removeIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex); 678 mStatusIcons.removeViewAt(viewIndex); 679 } 680 681 public void addNotification(IBinder key, StatusBarNotification notification) { 682 /* if (DEBUG) */ Slog.d(TAG, "addNotification score=" + notification.score); 683 StatusBarIconView iconView = addNotificationViews(key, notification); 684 if (iconView == null) return; 685 686 boolean immersive = false; 687 try { 688 immersive = ActivityManagerNative.getDefault().isTopActivityImmersive(); 689 if (DEBUG) { 690 Slog.d(TAG, "Top activity is " + (immersive?"immersive":"not immersive")); 691 } 692 } catch (RemoteException ex) { 693 } 694 695 /* 696 * DISABLED due to missing API 697 if (ENABLE_INTRUDERS && ( 698 // TODO(dsandler): Only if the screen is on 699 notification.notification.intruderView != null)) { 700 Slog.d(TAG, "Presenting high-priority notification"); 701 // special new transient ticker mode 702 // 1. Populate mIntruderAlertView 703 704 if (notification.notification.intruderView == null) { 705 Slog.e(TAG, notification.notification.toString() + " wanted to intrude but intruderView was null"); 706 return; 707 } 708 709 // bind the click event to the content area 710 PendingIntent contentIntent = notification.notification.contentIntent; 711 final View.OnClickListener listener = (contentIntent != null) 712 ? new NotificationClicker(contentIntent, 713 notification.pkg, notification.tag, notification.id) 714 : null; 715 716 mIntruderAlertView.applyIntruderContent(notification.notification.intruderView, listener); 717 718 mCurrentlyIntrudingNotification = notification; 719 720 // 2. Animate mIntruderAlertView in 721 mHandler.sendEmptyMessage(MSG_SHOW_INTRUDER); 722 723 // 3. Set alarm to age the notification off (TODO) 724 mHandler.removeMessages(MSG_HIDE_INTRUDER); 725 if (INTRUDER_ALERT_DECAY_MS > 0) { 726 mHandler.sendEmptyMessageDelayed(MSG_HIDE_INTRUDER, INTRUDER_ALERT_DECAY_MS); 727 } 728 } else 729 */ 730 731 if (notification.notification.fullScreenIntent != null) { 732 // Stop screensaver if the notification has a full-screen intent. 733 // (like an incoming phone call) 734 awakenDreams(); 735 736 // not immersive & a full-screen alert should be shown 737 Slog.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent"); 738 try { 739 notification.notification.fullScreenIntent.send(); 740 } catch (PendingIntent.CanceledException e) { 741 } 742 } else { 743 // usual case: status bar visible & not immersive 744 745 // show the ticker if there isn't an intruder too 746 if (mCurrentlyIntrudingNotification == null) { 747 tick(null, notification, true); 748 } 749 } 750 751 // Recalculate the position of the sliding windows and the titles. 752 setAreThereNotifications(); 753 updateExpandedViewPos(EXPANDED_LEAVE_ALONE); 754 } 755 756 public void removeNotification(IBinder key) { 757 StatusBarNotification old = removeNotificationViews(key); 758 if (SPEW) Slog.d(TAG, "removeNotification key=" + key + " old=" + old); 759 760 if (old != null) { 761 // Cancel the ticker if it's still running 762 mTicker.removeEntry(old); 763 764 // Recalculate the position of the sliding windows and the titles. 765 updateExpandedViewPos(EXPANDED_LEAVE_ALONE); 766 767 if (ENABLE_INTRUDERS && old == mCurrentlyIntrudingNotification) { 768 mHandler.sendEmptyMessage(MSG_HIDE_INTRUDER); 769 } 770 771 if (CLOSE_PANEL_WHEN_EMPTIED && mNotificationData.size() == 0 && !mAnimating) { 772 animateCollapse(); 773 } 774 } 775 776 setAreThereNotifications(); 777 } 778 779 private void updateShowSearchHoldoff() { 780 mShowSearchHoldoff = mContext.getResources().getInteger( 781 R.integer.config_show_search_delay); 782 } 783 784 private void loadNotificationShade() { 785 if (mPile == null) return; 786 787 int N = mNotificationData.size(); 788 789 ArrayList<View> toShow = new ArrayList<View>(); 790 791 final boolean provisioned = isDeviceProvisioned(); 792 // If the device hasn't been through Setup, we only show system notifications 793 for (int i=0; i<N; i++) { 794 Entry ent = mNotificationData.get(N-i-1); 795 if (!(provisioned || showNotificationEvenIfUnprovisioned(ent.notification))) continue; 796 if (!notificationIsForCurrentUser(ent.notification)) continue; 797 toShow.add(ent.row); 798 } 799 800 ArrayList<View> toRemove = new ArrayList<View>(); 801 for (int i=0; i<mPile.getChildCount(); i++) { 802 View child = mPile.getChildAt(i); 803 if (!toShow.contains(child)) { 804 toRemove.add(child); 805 } 806 } 807 808 for (View remove : toRemove) { 809 mPile.removeView(remove); 810 } 811 812 for (int i=0; i<toShow.size(); i++) { 813 View v = toShow.get(i); 814 if (v.getParent() == null) { 815 mPile.addView(v, i); 816 } 817 } 818 819 mSettingsButton.setEnabled(isDeviceProvisioned()); 820 } 821 822 @Override 823 protected void updateNotificationIcons() { 824 if (mNotificationIcons == null) return; 825 826 loadNotificationShade(); 827 828 final LinearLayout.LayoutParams params 829 = new LinearLayout.LayoutParams(mIconSize + 2*mIconHPadding, mNaturalBarHeight); 830 831 int N = mNotificationData.size(); 832 833 if (DEBUG) { 834 Slog.d(TAG, "refreshing icons: " + N + " notifications, mNotificationIcons=" + mNotificationIcons); 835 } 836 837 ArrayList<View> toShow = new ArrayList<View>(); 838 839 final boolean provisioned = isDeviceProvisioned(); 840 // If the device hasn't been through Setup, we only show system notifications 841 for (int i=0; i<N; i++) { 842 Entry ent = mNotificationData.get(N-i-1); 843 if (!((provisioned && ent.notification.score >= HIDE_ICONS_BELOW_SCORE) 844 || showNotificationEvenIfUnprovisioned(ent.notification))) continue; 845 if (!notificationIsForCurrentUser(ent.notification)) continue; 846 toShow.add(ent.icon); 847 } 848 849 ArrayList<View> toRemove = new ArrayList<View>(); 850 for (int i=0; i<mNotificationIcons.getChildCount(); i++) { 851 View child = mNotificationIcons.getChildAt(i); 852 if (!toShow.contains(child)) { 853 toRemove.add(child); 854 } 855 } 856 857 for (View remove : toRemove) { 858 mNotificationIcons.removeView(remove); 859 } 860 861 for (int i=0; i<toShow.size(); i++) { 862 View v = toShow.get(i); 863 if (v.getParent() == null) { 864 mNotificationIcons.addView(v, i, params); 865 } 866 } 867 } 868 869 protected void updateCarrierLabelVisibility(boolean force) { 870 if (!mShowCarrierInPanel) return; 871 // The idea here is to only show the carrier label when there is enough room to see it, 872 // i.e. when there aren't enough notifications to fill the panel. 873 if (DEBUG) { 874 Slog.d(TAG, String.format("pileh=%d scrollh=%d carrierh=%d", 875 mPile.getHeight(), mScrollView.getHeight(), mCarrierLabelHeight)); 876 } 877 878 final boolean emergencyCallsShownElsewhere = mEmergencyCallLabel != null; 879 final boolean makeVisible = 880 !(emergencyCallsShownElsewhere && mNetworkController.isEmergencyOnly()) 881 && mPile.getHeight() < (mNotificationPanel.getHeight() - mCarrierLabelHeight - mNotificationHeaderHeight); 882 883 if (force || mCarrierLabelVisible != makeVisible) { 884 mCarrierLabelVisible = makeVisible; 885 if (DEBUG) { 886 Slog.d(TAG, "making carrier label " + (makeVisible?"visible":"invisible")); 887 } 888 mCarrierLabel.animate().cancel(); 889 if (makeVisible) { 890 mCarrierLabel.setVisibility(View.VISIBLE); 891 } 892 mCarrierLabel.animate() 893 .alpha(makeVisible ? 1f : 0f) 894 //.setStartDelay(makeVisible ? 500 : 0) 895 //.setDuration(makeVisible ? 750 : 100) 896 .setDuration(150) 897 .setListener(makeVisible ? null : new AnimatorListenerAdapter() { 898 @Override 899 public void onAnimationEnd(Animator animation) { 900 if (!mCarrierLabelVisible) { // race 901 mCarrierLabel.setVisibility(View.INVISIBLE); 902 mCarrierLabel.setAlpha(0f); 903 } 904 } 905 }) 906 .start(); 907 } 908 } 909 910 @Override 911 protected void setAreThereNotifications() { 912 final boolean any = mNotificationData.size() > 0; 913 914 final boolean clearable = any && mNotificationData.hasClearableItems(); 915 916 if (DEBUG) { 917 Slog.d(TAG, "setAreThereNotifications: N=" + mNotificationData.size() 918 + " any=" + any + " clearable=" + clearable); 919 } 920 921 if (mClearButton.isShown()) { 922 if (clearable != (mClearButton.getAlpha() == 1.0f)) { 923 ObjectAnimator clearAnimation = ObjectAnimator.ofFloat( 924 mClearButton, "alpha", clearable ? 1.0f : 0.0f).setDuration(250); 925 clearAnimation.addListener(new AnimatorListenerAdapter() { 926 @Override 927 public void onAnimationEnd(Animator animation) { 928 if (mClearButton.getAlpha() <= 0.0f) { 929 mClearButton.setVisibility(View.INVISIBLE); 930 } 931 } 932 933 @Override 934 public void onAnimationStart(Animator animation) { 935 if (mClearButton.getAlpha() <= 0.0f) { 936 mClearButton.setVisibility(View.VISIBLE); 937 } 938 } 939 }); 940 clearAnimation.start(); 941 } 942 } else { 943 mClearButton.setAlpha(clearable ? 1.0f : 0.0f); 944 mClearButton.setVisibility(clearable ? View.VISIBLE : View.INVISIBLE); 945 } 946 mClearButton.setEnabled(clearable); 947 948 final View nlo = mStatusBarView.findViewById(R.id.notification_lights_out); 949 final boolean showDot = (any&&!areLightsOn()); 950 if (showDot != (nlo.getAlpha() == 1.0f)) { 951 if (showDot) { 952 nlo.setAlpha(0f); 953 nlo.setVisibility(View.VISIBLE); 954 } 955 nlo.animate() 956 .alpha(showDot?1:0) 957 .setDuration(showDot?750:250) 958 .setInterpolator(new AccelerateInterpolator(2.0f)) 959 .setListener(showDot ? null : new AnimatorListenerAdapter() { 960 @Override 961 public void onAnimationEnd(Animator _a) { 962 nlo.setVisibility(View.GONE); 963 } 964 }) 965 .start(); 966 } 967 968 updateCarrierLabelVisibility(false); 969 } 970 971 public void showClock(boolean show) { 972 if (mStatusBarView == null) return; 973 View clock = mStatusBarView.findViewById(R.id.clock); 974 if (clock != null) { 975 clock.setVisibility(show ? View.VISIBLE : View.GONE); 976 } 977 } 978 979 /** 980 * State is one or more of the DISABLE constants from StatusBarManager. 981 */ 982 public void disable(int state) { 983 final int old = mDisabled; 984 final int diff = state ^ old; 985 mDisabled = state; 986 987 if (DEBUG) { 988 Slog.d(TAG, String.format("disable: 0x%08x -> 0x%08x (diff: 0x%08x)", 989 old, state, diff)); 990 } 991 992 StringBuilder flagdbg = new StringBuilder(); 993 flagdbg.append("disable: < "); 994 flagdbg.append(((state & StatusBarManager.DISABLE_EXPAND) != 0) ? "EXPAND" : "expand"); 995 flagdbg.append(((diff & StatusBarManager.DISABLE_EXPAND) != 0) ? "* " : " "); 996 flagdbg.append(((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) ? "ICONS" : "icons"); 997 flagdbg.append(((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) ? "* " : " "); 998 flagdbg.append(((state & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) ? "ALERTS" : "alerts"); 999 flagdbg.append(((diff & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) ? "* " : " "); 1000 flagdbg.append(((state & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) ? "TICKER" : "ticker"); 1001 flagdbg.append(((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) ? "* " : " "); 1002 flagdbg.append(((state & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) ? "SYSTEM_INFO" : "system_info"); 1003 flagdbg.append(((diff & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) ? "* " : " "); 1004 flagdbg.append(((state & StatusBarManager.DISABLE_BACK) != 0) ? "BACK" : "back"); 1005 flagdbg.append(((diff & StatusBarManager.DISABLE_BACK) != 0) ? "* " : " "); 1006 flagdbg.append(((state & StatusBarManager.DISABLE_HOME) != 0) ? "HOME" : "home"); 1007 flagdbg.append(((diff & StatusBarManager.DISABLE_HOME) != 0) ? "* " : " "); 1008 flagdbg.append(((state & StatusBarManager.DISABLE_RECENT) != 0) ? "RECENT" : "recent"); 1009 flagdbg.append(((diff & StatusBarManager.DISABLE_RECENT) != 0) ? "* " : " "); 1010 flagdbg.append(((state & StatusBarManager.DISABLE_CLOCK) != 0) ? "CLOCK" : "clock"); 1011 flagdbg.append(((diff & StatusBarManager.DISABLE_CLOCK) != 0) ? "* " : " "); 1012 flagdbg.append(">"); 1013 Slog.d(TAG, flagdbg.toString()); 1014 1015 if ((diff & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) { 1016 mIcons.animate().cancel(); 1017 if ((state & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) { 1018 if (mTicking) { 1019 mTicker.halt(); 1020 } 1021 mIcons.animate() 1022 .alpha(0f) 1023 .translationY(mNaturalBarHeight*0.5f) 1024 //.setStartDelay(100) 1025 .setDuration(175) 1026 .setInterpolator(new DecelerateInterpolator(1.5f)) 1027 .setListener(mMakeIconsInvisible) 1028 .start(); 1029 } else { 1030 mIcons.setVisibility(View.VISIBLE); 1031 mIcons.animate() 1032 .alpha(1f) 1033 .translationY(0) 1034 .setStartDelay(0) 1035 .setInterpolator(new DecelerateInterpolator(1.5f)) 1036 .setDuration(175) 1037 .start(); 1038 } 1039 } 1040 1041 if ((diff & StatusBarManager.DISABLE_CLOCK) != 0) { 1042 boolean show = (state & StatusBarManager.DISABLE_CLOCK) == 0; 1043 showClock(show); 1044 } 1045 if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) { 1046 if ((state & StatusBarManager.DISABLE_EXPAND) != 0) { 1047 animateCollapse(); 1048 } 1049 } 1050 1051 if ((diff & (StatusBarManager.DISABLE_HOME 1052 | StatusBarManager.DISABLE_RECENT 1053 | StatusBarManager.DISABLE_BACK)) != 0) { 1054 // the nav bar will take care of these 1055 if (mNavigationBarView != null) mNavigationBarView.setDisabledFlags(state); 1056 1057 if ((state & StatusBarManager.DISABLE_RECENT) != 0) { 1058 // close recents if it's visible 1059 mHandler.removeMessages(MSG_CLOSE_RECENTS_PANEL); 1060 mHandler.sendEmptyMessage(MSG_CLOSE_RECENTS_PANEL); 1061 } 1062 } 1063 1064 if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) { 1065 if ((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) { 1066 if (mTicking) { 1067 mTicker.halt(); 1068 } else { 1069 setNotificationIconVisibility(false, com.android.internal.R.anim.fade_out); 1070 } 1071 } else { 1072 if (!mExpandedVisible) { 1073 setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in); 1074 } 1075 } 1076 } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) { 1077 if (mTicking && (state & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) { 1078 mTicker.halt(); 1079 } 1080 } 1081 } 1082 1083 @Override 1084 protected BaseStatusBar.H createHandler() { 1085 return new PhoneStatusBar.H(); 1086 } 1087 1088 /** 1089 * All changes to the status bar and notifications funnel through here and are batched. 1090 */ 1091 private class H extends BaseStatusBar.H { 1092 public void handleMessage(Message m) { 1093 super.handleMessage(m); 1094 switch (m.what) { 1095 case MSG_OPEN_NOTIFICATION_PANEL: 1096 animateExpand(); 1097 break; 1098 case MSG_CLOSE_NOTIFICATION_PANEL: 1099 animateCollapse(); 1100 break; 1101 case MSG_SHOW_INTRUDER: 1102 setIntruderAlertVisibility(true); 1103 break; 1104 case MSG_HIDE_INTRUDER: 1105 setIntruderAlertVisibility(false); 1106 mCurrentlyIntrudingNotification = null; 1107 break; 1108 } 1109 } 1110 } 1111 1112 View.OnFocusChangeListener mFocusChangeListener = new View.OnFocusChangeListener() { 1113 public void onFocusChange(View v, boolean hasFocus) { 1114 // Because 'v' is a ViewGroup, all its children will be (un)selected 1115 // too, which allows marqueeing to work. 1116 v.setSelected(hasFocus); 1117 } 1118 }; 1119 1120 void makeExpandedVisible(boolean revealAfterDraw) { 1121 if (SPEW) Slog.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible); 1122 if (mExpandedVisible) { 1123 return; 1124 } 1125 1126 mExpandedVisible = true; 1127 mPile.setLayoutTransitionsEnabled(true); 1128 if (mNavigationBarView != null) 1129 mNavigationBarView.setSlippery(true); 1130 1131 updateCarrierLabelVisibility(true); 1132 1133 updateExpandedViewPos(EXPANDED_LEAVE_ALONE); 1134 1135 // Expand the window to encompass the full screen in anticipation of the drag. 1136 // This is only possible to do atomically because the status bar is at the top of the screen! 1137 WindowManager.LayoutParams lp = (WindowManager.LayoutParams) mStatusBarWindow.getLayoutParams(); 1138 lp.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; 1139 lp.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; 1140 lp.height = ViewGroup.LayoutParams.MATCH_PARENT; 1141 mWindowManager.updateViewLayout(mStatusBarWindow, lp); 1142 1143 // Updating the window layout will force an expensive traversal/redraw. 1144 // Kick off the reveal animation after this is complete to avoid animation latency. 1145 if (revealAfterDraw) { 1146// mHandler.post(mStartRevealAnimation); 1147 } 1148 1149 visibilityChanged(true); 1150 } 1151 1152 public void animateCollapse() { 1153 animateCollapse(CommandQueue.FLAG_EXCLUDE_NONE); 1154 } 1155 1156 public void animateCollapse(int flags) { 1157 if (SPEW) { 1158 Slog.d(TAG, "animateCollapse(): " 1159 + " mExpandedVisible=" + mExpandedVisible 1160 + " mAnimating=" + mAnimating 1161 + " mAnimatingReveal=" + mAnimatingReveal 1162 + " mAnimY=" + mAnimY 1163 + " mAnimVel=" + mAnimVel 1164 + " flags=" + flags); 1165 } 1166 1167 if ((flags & CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL) == 0) { 1168 mHandler.removeMessages(MSG_CLOSE_RECENTS_PANEL); 1169 mHandler.sendEmptyMessage(MSG_CLOSE_RECENTS_PANEL); 1170 } 1171 1172 if ((flags & CommandQueue.FLAG_EXCLUDE_SEARCH_PANEL) == 0) { 1173 mHandler.removeMessages(MSG_CLOSE_SEARCH_PANEL); 1174 mHandler.sendEmptyMessage(MSG_CLOSE_SEARCH_PANEL); 1175 } 1176 1177 mStatusBarView.collapseAllPanels(true); 1178 } 1179 1180 @Override 1181 public void animateExpand() { 1182 if (SPEW) Slog.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible); 1183 if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) { 1184 return ; 1185 } 1186 1187 mNotificationPanel.expand(); 1188 1189 if (false) postStartTracing(); 1190 } 1191 1192 void makeExpandedInvisible() { 1193 if (SPEW) Slog.d(TAG, "makeExpandedInvisible: mExpandedVisible=" + mExpandedVisible 1194 + " mExpandedVisible=" + mExpandedVisible); 1195 1196 if (!mExpandedVisible) { 1197 return; 1198 } 1199 1200 // Ensure the panel is fully collapsed (just in case; bug 6765842) 1201 mStatusBarView.collapseAllPanels(/*animate=*/ false); 1202 1203 mExpandedVisible = false; 1204 mPile.setLayoutTransitionsEnabled(false); 1205 if (mNavigationBarView != null) 1206 mNavigationBarView.setSlippery(false); 1207 visibilityChanged(false); 1208 1209 // Shrink the window to the size of the status bar only 1210 WindowManager.LayoutParams lp = (WindowManager.LayoutParams) mStatusBarWindow.getLayoutParams(); 1211 lp.height = getStatusBarHeight(); 1212 lp.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; 1213 lp.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; 1214 mWindowManager.updateViewLayout(mStatusBarWindow, lp); 1215 1216 if ((mDisabled & StatusBarManager.DISABLE_NOTIFICATION_ICONS) == 0) { 1217 setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in); 1218 } 1219 1220 // Close any "App info" popups that might have snuck on-screen 1221 dismissPopups(); 1222 1223 if (mPostCollapseCleanup != null) { 1224 mPostCollapseCleanup.run(); 1225 mPostCollapseCleanup = null; 1226 } 1227 } 1228 1229 /** 1230 * Enables or disables layers on the children of the notifications pile. 1231 * 1232 * When layers are enabled, this method attempts to enable layers for the minimal 1233 * number of children. Only children visible when the notification area is fully 1234 * expanded will receive a layer. The technique used in this method might cause 1235 * more children than necessary to get a layer (at most one extra child with the 1236 * current UI.) 1237 * 1238 * @param layerType {@link View#LAYER_TYPE_NONE} or {@link View#LAYER_TYPE_HARDWARE} 1239 */ 1240 private void setPileLayers(int layerType) { 1241 final int count = mPile.getChildCount(); 1242 1243 switch (layerType) { 1244 case View.LAYER_TYPE_NONE: 1245 for (int i = 0; i < count; i++) { 1246 mPile.getChildAt(i).setLayerType(layerType, null); 1247 } 1248 break; 1249 case View.LAYER_TYPE_HARDWARE: 1250 final int[] location = new int[2]; 1251 mNotificationPanel.getLocationInWindow(location); 1252 1253 final int left = location[0]; 1254 final int top = location[1]; 1255 final int right = left + mNotificationPanel.getWidth(); 1256 final int bottom = top + getExpandedViewMaxHeight(); 1257 1258 final Rect childBounds = new Rect(); 1259 1260 for (int i = 0; i < count; i++) { 1261 final View view = mPile.getChildAt(i); 1262 view.getLocationInWindow(location); 1263 1264 childBounds.set(location[0], location[1], 1265 location[0] + view.getWidth(), location[1] + view.getHeight()); 1266 1267 if (childBounds.intersects(left, top, right, bottom)) { 1268 view.setLayerType(layerType, null); 1269 } 1270 } 1271 1272 break; 1273 } 1274 } 1275 1276 boolean interceptTouchEvent(MotionEvent event) { 1277 if (SPEW) { 1278 Slog.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled=" 1279 + mDisabled + " mTracking=" + mTracking); 1280 } else if (CHATTY) { 1281 if (event.getAction() != MotionEvent.ACTION_MOVE) { 1282 Slog.d(TAG, String.format( 1283 "panel: %s at (%f, %f) mDisabled=0x%08x", 1284 MotionEvent.actionToString(event.getAction()), 1285 event.getRawX(), event.getRawY(), mDisabled)); 1286 } 1287 } 1288 1289 mGestureRec.add(event); 1290 1291 return false; 1292 } 1293 1294 public GestureRecorder getGestureRecorder() { 1295 return mGestureRec; 1296 } 1297 1298 @Override // CommandQueue 1299 public void setNavigationIconHints(int hints) { 1300 if (hints == mNavigationIconHints) return; 1301 1302 mNavigationIconHints = hints; 1303 1304 if (mNavigationBarView != null) { 1305 mNavigationBarView.setNavigationIconHints(hints); 1306 } 1307 } 1308 1309 @Override // CommandQueue 1310 public void setSystemUiVisibility(int vis, int mask) { 1311 final int oldVal = mSystemUiVisibility; 1312 final int newVal = (oldVal&~mask) | (vis&mask); 1313 final int diff = newVal ^ oldVal; 1314 1315 if (diff != 0) { 1316 mSystemUiVisibility = newVal; 1317 1318 if (0 != (diff & View.SYSTEM_UI_FLAG_LOW_PROFILE)) { 1319 final boolean lightsOut = (0 != (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE)); 1320 if (lightsOut) { 1321 animateCollapse(); 1322 if (mTicking) { 1323 mTicker.halt(); 1324 } 1325 } 1326 1327 if (mNavigationBarView != null) { 1328 mNavigationBarView.setLowProfile(lightsOut); 1329 } 1330 1331 setStatusBarLowProfile(lightsOut); 1332 } 1333 1334 notifyUiVisibilityChanged(); 1335 } 1336 } 1337 1338 private void setStatusBarLowProfile(boolean lightsOut) { 1339 if (mLightsOutAnimation == null) { 1340 final View notifications = mStatusBarView.findViewById(R.id.notification_icon_area); 1341 final View systemIcons = mStatusBarView.findViewById(R.id.statusIcons); 1342 final View signal = mStatusBarView.findViewById(R.id.signal_cluster); 1343 final View battery = mStatusBarView.findViewById(R.id.battery); 1344 final View clock = mStatusBarView.findViewById(R.id.clock); 1345 1346 mLightsOutAnimation = new AnimatorSet(); 1347 mLightsOutAnimation.playTogether( 1348 ObjectAnimator.ofFloat(notifications, View.ALPHA, 0), 1349 ObjectAnimator.ofFloat(systemIcons, View.ALPHA, 0), 1350 ObjectAnimator.ofFloat(signal, View.ALPHA, 0), 1351 ObjectAnimator.ofFloat(battery, View.ALPHA, 0.5f), 1352 ObjectAnimator.ofFloat(clock, View.ALPHA, 0.5f) 1353 ); 1354 mLightsOutAnimation.setDuration(750); 1355 1356 mLightsOnAnimation = new AnimatorSet(); 1357 mLightsOnAnimation.playTogether( 1358 ObjectAnimator.ofFloat(notifications, View.ALPHA, 1), 1359 ObjectAnimator.ofFloat(systemIcons, View.ALPHA, 1), 1360 ObjectAnimator.ofFloat(signal, View.ALPHA, 1), 1361 ObjectAnimator.ofFloat(battery, View.ALPHA, 1), 1362 ObjectAnimator.ofFloat(clock, View.ALPHA, 1) 1363 ); 1364 mLightsOnAnimation.setDuration(250); 1365 } 1366 1367 mLightsOutAnimation.cancel(); 1368 mLightsOnAnimation.cancel(); 1369 1370 final Animator a = lightsOut ? mLightsOutAnimation : mLightsOnAnimation; 1371 a.start(); 1372 1373 setAreThereNotifications(); 1374 } 1375 1376 private boolean areLightsOn() { 1377 return 0 == (mSystemUiVisibility & View.SYSTEM_UI_FLAG_LOW_PROFILE); 1378 } 1379 1380 public void setLightsOn(boolean on) { 1381 Log.v(TAG, "setLightsOn(" + on + ")"); 1382 if (on) { 1383 setSystemUiVisibility(0, View.SYSTEM_UI_FLAG_LOW_PROFILE); 1384 } else { 1385 setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE, View.SYSTEM_UI_FLAG_LOW_PROFILE); 1386 } 1387 } 1388 1389 private void notifyUiVisibilityChanged() { 1390 try { 1391 mWindowManagerService.statusBarVisibilityChanged(mSystemUiVisibility); 1392 } catch (RemoteException ex) { 1393 } 1394 } 1395 1396 public void topAppWindowChanged(boolean showMenu) { 1397 if (DEBUG) { 1398 Slog.d(TAG, (showMenu?"showing":"hiding") + " the MENU button"); 1399 } 1400 if (mNavigationBarView != null) { 1401 mNavigationBarView.setMenuVisibility(showMenu); 1402 } 1403 1404 // See above re: lights-out policy for legacy apps. 1405 if (showMenu) setLightsOn(true); 1406 } 1407 1408 @Override 1409 public void setImeWindowStatus(IBinder token, int vis, int backDisposition) { 1410 boolean altBack = (backDisposition == InputMethodService.BACK_DISPOSITION_WILL_DISMISS) 1411 || ((vis & InputMethodService.IME_VISIBLE) != 0); 1412 1413 mCommandQueue.setNavigationIconHints( 1414 altBack ? (mNavigationIconHints | StatusBarManager.NAVIGATION_HINT_BACK_ALT) 1415 : (mNavigationIconHints & ~StatusBarManager.NAVIGATION_HINT_BACK_ALT)); 1416 } 1417 1418 @Override 1419 public void setHardKeyboardStatus(boolean available, boolean enabled) { } 1420 1421 @Override 1422 protected void tick(IBinder key, StatusBarNotification n, boolean firstTime) { 1423 // no ticking in lights-out mode 1424 if (!areLightsOn()) return; 1425 1426 // no ticking in Setup 1427 if (!isDeviceProvisioned()) return; 1428 1429 // Show the ticker if one is requested. Also don't do this 1430 // until status bar window is attached to the window manager, 1431 // because... well, what's the point otherwise? And trying to 1432 // run a ticker without being attached will crash! 1433 if (n.notification.tickerText != null && mStatusBarWindow.getWindowToken() != null) { 1434 if (0 == (mDisabled & (StatusBarManager.DISABLE_NOTIFICATION_ICONS 1435 | StatusBarManager.DISABLE_NOTIFICATION_TICKER))) { 1436 mTicker.addEntry(n); 1437 } 1438 } 1439 } 1440 1441 private class MyTicker extends Ticker { 1442 MyTicker(Context context, View sb) { 1443 super(context, sb); 1444 } 1445 1446 @Override 1447 public void tickerStarting() { 1448 mTicking = true; 1449 mIcons.setVisibility(View.GONE); 1450 mTickerView.setVisibility(View.VISIBLE); 1451 mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_up_in, null)); 1452 mIcons.startAnimation(loadAnim(com.android.internal.R.anim.push_up_out, null)); 1453 } 1454 1455 @Override 1456 public void tickerDone() { 1457 mIcons.setVisibility(View.VISIBLE); 1458 mTickerView.setVisibility(View.GONE); 1459 mIcons.startAnimation(loadAnim(com.android.internal.R.anim.push_down_in, null)); 1460 mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_down_out, 1461 mTickingDoneListener)); 1462 } 1463 1464 public void tickerHalting() { 1465 mIcons.setVisibility(View.VISIBLE); 1466 mTickerView.setVisibility(View.GONE); 1467 mIcons.startAnimation(loadAnim(com.android.internal.R.anim.fade_in, null)); 1468 mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.fade_out, 1469 mTickingDoneListener)); 1470 } 1471 } 1472 1473 Animation.AnimationListener mTickingDoneListener = new Animation.AnimationListener() {; 1474 public void onAnimationEnd(Animation animation) { 1475 mTicking = false; 1476 } 1477 public void onAnimationRepeat(Animation animation) { 1478 } 1479 public void onAnimationStart(Animation animation) { 1480 } 1481 }; 1482 1483 private Animation loadAnim(int id, Animation.AnimationListener listener) { 1484 Animation anim = AnimationUtils.loadAnimation(mContext, id); 1485 if (listener != null) { 1486 anim.setAnimationListener(listener); 1487 } 1488 return anim; 1489 } 1490 1491 public static String viewInfo(View v) { 1492 return "[(" + v.getLeft() + "," + v.getTop() + ")(" + v.getRight() + "," + v.getBottom() 1493 + ") " + v.getWidth() + "x" + v.getHeight() + "]"; 1494 } 1495 1496 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1497 synchronized (mQueueLock) { 1498 pw.println("Current Status Bar state:"); 1499 pw.println(" mExpandedVisible=" + mExpandedVisible 1500 + ", mTrackingPosition=" + mTrackingPosition); 1501 pw.println(" mTicking=" + mTicking); 1502 pw.println(" mTracking=" + mTracking); 1503 pw.println(" mNotificationPanel=" + 1504 ((mNotificationPanel == null) 1505 ? "null" 1506 : (mNotificationPanel + " params=" + mNotificationPanel.getLayoutParams().debug("")))); 1507 pw.println(" mAnimating=" + mAnimating 1508 + ", mAnimY=" + mAnimY + ", mAnimVel=" + mAnimVel 1509 + ", mAnimAccel=" + mAnimAccel); 1510 pw.println(" mAnimLastTimeNanos=" + mAnimLastTimeNanos); 1511 pw.println(" mAnimatingReveal=" + mAnimatingReveal 1512 + " mViewDelta=" + mViewDelta); 1513 pw.println(" mDisplayMetrics=" + mDisplayMetrics); 1514 pw.println(" mPile: " + viewInfo(mPile)); 1515 pw.println(" mTickerView: " + viewInfo(mTickerView)); 1516 pw.println(" mScrollView: " + viewInfo(mScrollView) 1517 + " scroll " + mScrollView.getScrollX() + "," + mScrollView.getScrollY()); 1518 } 1519 1520 pw.print(" mNavigationBarView="); 1521 if (mNavigationBarView == null) { 1522 pw.println("null"); 1523 } else { 1524 mNavigationBarView.dump(fd, pw, args); 1525 } 1526 1527 if (DUMPTRUCK) { 1528 synchronized (mNotificationData) { 1529 int N = mNotificationData.size(); 1530 pw.println(" notification icons: " + N); 1531 for (int i=0; i<N; i++) { 1532 NotificationData.Entry e = mNotificationData.get(i); 1533 pw.println(" [" + i + "] key=" + e.key + " icon=" + e.icon); 1534 StatusBarNotification n = e.notification; 1535 pw.println(" pkg=" + n.pkg + " id=" + n.id + " score=" + n.score); 1536 pw.println(" notification=" + n.notification); 1537 pw.println(" tickerText=\"" + n.notification.tickerText + "\""); 1538 } 1539 } 1540 1541 int N = mStatusIcons.getChildCount(); 1542 pw.println(" system icons: " + N); 1543 for (int i=0; i<N; i++) { 1544 StatusBarIconView ic = (StatusBarIconView) mStatusIcons.getChildAt(i); 1545 pw.println(" [" + i + "] icon=" + ic); 1546 } 1547 1548 if (false) { 1549 pw.println("see the logcat for a dump of the views we have created."); 1550 // must happen on ui thread 1551 mHandler.post(new Runnable() { 1552 public void run() { 1553 mStatusBarView.getLocationOnScreen(mAbsPos); 1554 Slog.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1] 1555 + ") " + mStatusBarView.getWidth() + "x" 1556 + getStatusBarHeight()); 1557 mStatusBarView.debug(); 1558 } 1559 }); 1560 } 1561 } 1562 1563 pw.print(" status bar gestures: "); 1564 mGestureRec.dump(fd, pw, args); 1565 1566 mNetworkController.dump(fd, pw, args); 1567 } 1568 1569 @Override 1570 public void createAndAddWindows() { 1571 addStatusBarWindow(); 1572 } 1573 1574 private void addStatusBarWindow() { 1575 // Put up the view 1576 final int height = getStatusBarHeight(); 1577 1578 // Now that the status bar window encompasses the sliding panel and its 1579 // translucent backdrop, the entire thing is made TRANSLUCENT and is 1580 // hardware-accelerated. 1581 final WindowManager.LayoutParams lp = new WindowManager.LayoutParams( 1582 ViewGroup.LayoutParams.MATCH_PARENT, 1583 height, 1584 WindowManager.LayoutParams.TYPE_STATUS_BAR, 1585 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 1586 | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING 1587 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, 1588 PixelFormat.TRANSLUCENT); 1589 1590 lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; 1591 1592 lp.gravity = getStatusBarGravity(); 1593 lp.setTitle("StatusBar"); 1594 lp.packageName = mContext.getPackageName(); 1595 1596 makeStatusBarView(); 1597 mWindowManager.addView(mStatusBarWindow, lp); 1598 } 1599 1600 void setNotificationIconVisibility(boolean visible, int anim) { 1601 int old = mNotificationIcons.getVisibility(); 1602 int v = visible ? View.VISIBLE : View.INVISIBLE; 1603 if (old != v) { 1604 mNotificationIcons.setVisibility(v); 1605 mNotificationIcons.startAnimation(loadAnim(anim, null)); 1606 } 1607 } 1608 1609 void updateExpandedInvisiblePosition() { 1610 mTrackingPosition = -mDisplayMetrics.heightPixels; 1611 } 1612 1613 static final float saturate(float a) { 1614 return a < 0f ? 0f : (a > 1f ? 1f : a); 1615 } 1616 1617 @Override 1618 protected int getExpandedViewMaxHeight() { 1619 return mDisplayMetrics.heightPixels - mNotificationPanelMarginBottomPx; 1620 } 1621 1622 @Override 1623 public void updateExpandedViewPos(int thingy) { 1624 // TODO 1625 if (DEBUG) Slog.v(TAG, "updateExpandedViewPos"); 1626 FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mNotificationPanel.getLayoutParams(); 1627 lp.gravity = mNotificationPanelGravity; 1628 lp.leftMargin = mNotificationPanelMarginPx; 1629 mNotificationPanel.setLayoutParams(lp); 1630 lp = (FrameLayout.LayoutParams) mSettingsPanel.getLayoutParams(); 1631 lp.gravity = mSettingsPanelGravity; 1632 lp.rightMargin = mNotificationPanelMarginPx; 1633 mSettingsPanel.setLayoutParams(lp); 1634 1635 updateCarrierLabelVisibility(false); 1636 } 1637 1638 // called by makeStatusbar and also by PhoneStatusBarView 1639 void updateDisplaySize() { 1640 mDisplay.getMetrics(mDisplayMetrics); 1641 mGestureRec.tag("display", 1642 String.format("%dx%d", mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels)); 1643 } 1644 1645 void performDisableActions(int net) { 1646 int old = mDisabled; 1647 int diff = net ^ old; 1648 mDisabled = net; 1649 1650 // act accordingly 1651 if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) { 1652 if ((net & StatusBarManager.DISABLE_EXPAND) != 0) { 1653 Slog.d(TAG, "DISABLE_EXPAND: yes"); 1654 animateCollapse(); 1655 } 1656 } 1657 if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) { 1658 if ((net & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) { 1659 Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: yes"); 1660 if (mTicking) { 1661 mNotificationIcons.setVisibility(View.INVISIBLE); 1662 mTicker.halt(); 1663 } else { 1664 setNotificationIconVisibility(false, com.android.internal.R.anim.fade_out); 1665 } 1666 } else { 1667 Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: no"); 1668 if (!mExpandedVisible) { 1669 setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in); 1670 } 1671 } 1672 } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) { 1673 if (mTicking && (net & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) { 1674 mTicker.halt(); 1675 } 1676 } 1677 } 1678 1679 private View.OnClickListener mClearButtonListener = new View.OnClickListener() { 1680 public void onClick(View v) { 1681 synchronized (mNotificationData) { 1682 // animate-swipe all dismissable notifications, then animate the shade closed 1683 int numChildren = mPile.getChildCount(); 1684 1685 int scrollTop = mScrollView.getScrollY(); 1686 int scrollBottom = scrollTop + mScrollView.getHeight(); 1687 final ArrayList<View> snapshot = new ArrayList<View>(numChildren); 1688 for (int i=0; i<numChildren; i++) { 1689 final View child = mPile.getChildAt(i); 1690 if (mPile.canChildBeDismissed(child) && child.getBottom() > scrollTop && 1691 child.getTop() < scrollBottom) { 1692 snapshot.add(child); 1693 } 1694 } 1695 if (snapshot.isEmpty()) { 1696 animateCollapse(CommandQueue.FLAG_EXCLUDE_NONE); 1697 return; 1698 } 1699 new Thread(new Runnable() { 1700 @Override 1701 public void run() { 1702 // Decrease the delay for every row we animate to give the sense of 1703 // accelerating the swipes 1704 final int ROW_DELAY_DECREMENT = 10; 1705 int currentDelay = 140; 1706 int totalDelay = 0; 1707 1708 // Set the shade-animating state to avoid doing other work during 1709 // all of these animations. In particular, avoid layout and 1710 // redrawing when collapsing the shade. 1711 mPile.setViewRemoval(false); 1712 1713 mPostCollapseCleanup = new Runnable() { 1714 @Override 1715 public void run() { 1716 if (DEBUG) { 1717 Slog.v(TAG, "running post-collapse cleanup"); 1718 } 1719 try { 1720 mPile.setViewRemoval(true); 1721 mBarService.onClearAllNotifications(); 1722 } catch (Exception ex) { } 1723 } 1724 }; 1725 1726 View sampleView = snapshot.get(0); 1727 int width = sampleView.getWidth(); 1728 final int velocity = width * 8; // 1000/8 = 125 ms duration 1729 for (final View _v : snapshot) { 1730 mHandler.postDelayed(new Runnable() { 1731 @Override 1732 public void run() { 1733 mPile.dismissRowAnimated(_v, velocity); 1734 } 1735 }, totalDelay); 1736 currentDelay = Math.max(50, currentDelay - ROW_DELAY_DECREMENT); 1737 totalDelay += currentDelay; 1738 } 1739 // Delay the collapse animation until after all swipe animations have 1740 // finished. Provide some buffer because there may be some extra delay 1741 // before actually starting each swipe animation. Ideally, we'd 1742 // synchronize the end of those animations with the start of the collaps 1743 // exactly. 1744 mHandler.postDelayed(new Runnable() { 1745 @Override 1746 public void run() { 1747 animateCollapse(CommandQueue.FLAG_EXCLUDE_NONE); 1748 } 1749 }, totalDelay + 225); 1750 } 1751 }).start(); 1752 } 1753 } 1754 }; 1755 1756 private View.OnClickListener mSettingsButtonListener = new View.OnClickListener() { 1757 public void onClick(View v) { 1758 // We take this as a good indicator that Setup is running and we shouldn't 1759 // allow you to go somewhere else 1760 if (!isDeviceProvisioned()) return; 1761 try { 1762 // Dismiss the lock screen when Settings starts. 1763 ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity(); 1764 } catch (RemoteException e) { 1765 } 1766 v.getContext().startActivityAsUser(new Intent(Settings.ACTION_SETTINGS) 1767 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK), 1768 new UserHandle(UserHandle.USER_CURRENT)); 1769 animateCollapse(); 1770 } 1771 }; 1772 1773 private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 1774 public void onReceive(Context context, Intent intent) { 1775 Slog.v(TAG, "onReceive: " + intent); 1776 String action = intent.getAction(); 1777 if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) { 1778 int flags = CommandQueue.FLAG_EXCLUDE_NONE; 1779 if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) { 1780 String reason = intent.getStringExtra("reason"); 1781 if (reason != null && reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) { 1782 flags |= CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL; 1783 } 1784 } 1785 animateCollapse(flags); 1786 } 1787 else if (Intent.ACTION_SCREEN_OFF.equals(action)) { 1788 // no waiting! 1789 makeExpandedInvisible(); 1790 } 1791 else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) { 1792 if (DEBUG) { 1793 Slog.v(TAG, "configuration changed: " + mContext.getResources().getConfiguration()); 1794 } 1795 updateResources(); 1796 repositionNavigationBar(); 1797 updateExpandedViewPos(EXPANDED_LEAVE_ALONE); 1798 updateShowSearchHoldoff(); 1799 } 1800 else if (Intent.ACTION_SCREEN_ON.equals(action)) { 1801 // work around problem where mDisplay.getRotation() is not stable while screen is off (bug 7086018) 1802 repositionNavigationBar(); 1803 } 1804 } 1805 }; 1806 1807 @Override 1808 public void userSwitched(int newUserId) { 1809 if (MULTIUSER_DEBUG) mNotificationPanelDebugText.setText("USER " + newUserId); 1810 animateCollapse(); 1811 updateNotificationIcons(); 1812 } 1813 1814 private void setIntruderAlertVisibility(boolean vis) { 1815 if (!ENABLE_INTRUDERS) return; 1816 if (DEBUG) { 1817 Slog.v(TAG, (vis ? "showing" : "hiding") + " intruder alert window"); 1818 } 1819 mIntruderAlertView.setVisibility(vis ? View.VISIBLE : View.GONE); 1820 } 1821 1822 public void dismissIntruder() { 1823 if (mCurrentlyIntrudingNotification == null) return; 1824 1825 try { 1826 mBarService.onNotificationClear( 1827 mCurrentlyIntrudingNotification.pkg, 1828 mCurrentlyIntrudingNotification.tag, 1829 mCurrentlyIntrudingNotification.id); 1830 } catch (android.os.RemoteException ex) { 1831 // oh well 1832 } 1833 } 1834 1835 /** 1836 * Reload some of our resources when the configuration changes. 1837 * 1838 * We don't reload everything when the configuration changes -- we probably 1839 * should, but getting that smooth is tough. Someday we'll fix that. In the 1840 * meantime, just update the things that we know change. 1841 */ 1842 void updateResources() { 1843 final Context context = mContext; 1844 final Resources res = context.getResources(); 1845 1846 if (mClearButton instanceof TextView) { 1847 ((TextView)mClearButton).setText(context.getText(R.string.status_bar_clear_all_button)); 1848 } 1849 1850 // Update the QuickSettings container 1851 ((SettingsPanelView) mSettingsPanel).updateResources(); 1852 1853 loadDimens(); 1854 } 1855 1856 protected void loadDimens() { 1857 final Resources res = mContext.getResources(); 1858 1859 mNaturalBarHeight = res.getDimensionPixelSize( 1860 com.android.internal.R.dimen.status_bar_height); 1861 1862 int newIconSize = res.getDimensionPixelSize( 1863 com.android.internal.R.dimen.status_bar_icon_size); 1864 int newIconHPadding = res.getDimensionPixelSize( 1865 R.dimen.status_bar_icon_padding); 1866 1867 if (newIconHPadding != mIconHPadding || newIconSize != mIconSize) { 1868// Slog.d(TAG, "size=" + newIconSize + " padding=" + newIconHPadding); 1869 mIconHPadding = newIconHPadding; 1870 mIconSize = newIconSize; 1871 //reloadAllNotificationIcons(); // reload the tray 1872 } 1873 1874 mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore); 1875 1876 mSelfExpandVelocityPx = res.getDimension(R.dimen.self_expand_velocity); 1877 mSelfCollapseVelocityPx = res.getDimension(R.dimen.self_collapse_velocity); 1878 mFlingExpandMinVelocityPx = res.getDimension(R.dimen.fling_expand_min_velocity); 1879 mFlingCollapseMinVelocityPx = res.getDimension(R.dimen.fling_collapse_min_velocity); 1880 1881 mCollapseMinDisplayFraction = res.getFraction(R.dimen.collapse_min_display_fraction, 1, 1); 1882 mExpandMinDisplayFraction = res.getFraction(R.dimen.expand_min_display_fraction, 1, 1); 1883 1884 mExpandAccelPx = res.getDimension(R.dimen.expand_accel); 1885 mCollapseAccelPx = res.getDimension(R.dimen.collapse_accel); 1886 1887 mFlingGestureMaxXVelocityPx = res.getDimension(R.dimen.fling_gesture_max_x_velocity); 1888 1889 mFlingGestureMaxOutputVelocityPx = res.getDimension(R.dimen.fling_gesture_max_output_velocity); 1890 1891 mNotificationPanelMarginBottomPx 1892 = (int) res.getDimension(R.dimen.notification_panel_margin_bottom); 1893 mNotificationPanelMarginPx 1894 = (int) res.getDimension(R.dimen.notification_panel_margin_left); 1895 mNotificationPanelGravity = res.getInteger(R.integer.notification_panel_layout_gravity); 1896 if (mNotificationPanelGravity <= 0) { 1897 mNotificationPanelGravity = Gravity.LEFT | Gravity.TOP; 1898 } 1899 mSettingsPanelGravity = res.getInteger(R.integer.settings_panel_layout_gravity); 1900 if (mSettingsPanelGravity <= 0) { 1901 mSettingsPanelGravity = Gravity.RIGHT | Gravity.TOP; 1902 } 1903 getNinePatchPadding(res.getDrawable(R.drawable.notification_panel_bg), mNotificationPanelBackgroundPadding); 1904 final int notificationPanelDecorationHeight = 1905 res.getDimensionPixelSize(R.dimen.notification_panel_padding_top) 1906 + res.getDimensionPixelSize(R.dimen.notification_panel_header_height) 1907 + mNotificationPanelBackgroundPadding.top 1908 + mNotificationPanelBackgroundPadding.bottom; 1909 mNotificationPanelMinHeight = 1910 notificationPanelDecorationHeight 1911 + res.getDimensionPixelSize(R.dimen.close_handle_underlap); 1912 1913 mCarrierLabelHeight = res.getDimensionPixelSize(R.dimen.carrier_label_height); 1914 mNotificationHeaderHeight = res.getDimensionPixelSize(R.dimen.notification_panel_header_height); 1915 1916 if (false) Slog.v(TAG, "updateResources"); 1917 } 1918 1919 private static void getNinePatchPadding(Drawable d, Rect outPadding) { 1920 if (d instanceof NinePatchDrawable) { 1921 NinePatchDrawable ninePatch = (NinePatchDrawable) d; 1922 ninePatch.getPadding(outPadding); 1923 } 1924 } 1925 1926 // 1927 // tracing 1928 // 1929 1930 void postStartTracing() { 1931 mHandler.postDelayed(mStartTracing, 3000); 1932 } 1933 1934 void vibrate() { 1935 android.os.Vibrator vib = (android.os.Vibrator)mContext.getSystemService( 1936 Context.VIBRATOR_SERVICE); 1937 vib.vibrate(250); 1938 } 1939 1940 Runnable mStartTracing = new Runnable() { 1941 public void run() { 1942 vibrate(); 1943 SystemClock.sleep(250); 1944 Slog.d(TAG, "startTracing"); 1945 android.os.Debug.startMethodTracing("/data/statusbar-traces/trace"); 1946 mHandler.postDelayed(mStopTracing, 10000); 1947 } 1948 }; 1949 1950 Runnable mStopTracing = new Runnable() { 1951 public void run() { 1952 android.os.Debug.stopMethodTracing(); 1953 Slog.d(TAG, "stopTracing"); 1954 vibrate(); 1955 } 1956 }; 1957 1958 @Override 1959 protected void haltTicker() { 1960 mTicker.halt(); 1961 } 1962 1963 @Override 1964 protected boolean shouldDisableNavbarGestures() { 1965 return mExpandedVisible || (mDisabled & StatusBarManager.DISABLE_HOME) != 0; 1966 } 1967 1968 private static class FastColorDrawable extends Drawable { 1969 private final int mColor; 1970 1971 public FastColorDrawable(int color) { 1972 mColor = 0xff000000 | color; 1973 } 1974 1975 @Override 1976 public void draw(Canvas canvas) { 1977 canvas.drawColor(mColor, PorterDuff.Mode.SRC); 1978 } 1979 1980 @Override 1981 public void setAlpha(int alpha) { 1982 } 1983 1984 @Override 1985 public void setColorFilter(ColorFilter cf) { 1986 } 1987 1988 @Override 1989 public int getOpacity() { 1990 return PixelFormat.OPAQUE; 1991 } 1992 1993 @Override 1994 public void setBounds(int left, int top, int right, int bottom) { 1995 } 1996 1997 @Override 1998 public void setBounds(Rect bounds) { 1999 } 2000 } 2001} 2002