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