PhoneStatusBar.java revision f0b06c773867610d747d2063e74f13c12e3595c4
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 userActivity(); 788 if (mSettingsClosing 789 && mFlipSettingsViewAnim != null && mFlipSettingsViewAnim.isRunning()) { 790 return true; 791 } 792 if (mSettingsTracker != null) { 793 mSettingsTracker.addMovement(event); 794 } 795 796 if (event.getAction() == MotionEvent.ACTION_DOWN) { 797 mSettingsTracker = VelocityTracker.obtain(); 798 mSettingsDownY = event.getY(); 799 mSettingsCancelled = false; 800 mSettingsClosing = mFlipSettingsView.getVisibility() == View.VISIBLE; 801 mFlipSettingsView.setVisibility(View.VISIBLE); 802 mStackScroller.setVisibility(View.VISIBLE); 803 positionSettings(0); 804 if (!mSettingsClosing) { 805 mFlipSettingsView.setTranslationY(-mNotificationPanel.getMeasuredHeight()); 806 } 807 dispatchSettingsEvent(event); 808 } else if (mSettingsTracker != null && (event.getAction() == MotionEvent.ACTION_UP 809 || event.getAction() == MotionEvent.ACTION_CANCEL)) { 810 final float dy = event.getY() - mSettingsDownY; 811 final FlipperButton flipper = mOnKeyguard ? mKeyguardFlipper : mHeaderFlipper; 812 final boolean inButton = flipper.inHolderBounds(event); 813 final int slop = ViewConfiguration.get(mContext).getScaledTouchSlop(); 814 final boolean qsTap = mSettingsClosing && Math.abs(dy) < slop; 815 if (!qsTap && !inButton) { 816 mSettingsTracker.computeCurrentVelocity(1000); 817 final float vy = mSettingsTracker.getYVelocity(); 818 if (dy <= slop || vy <= 0) { 819 flipToNotifications(); 820 } else { 821 flipToSettings(); 822 } 823 } 824 mSettingsTracker.recycle(); 825 mSettingsTracker = null; 826 dispatchSettingsEvent(event); 827 } else if (mSettingsTracker != null && event.getAction() == MotionEvent.ACTION_MOVE) { 828 final float dy = event.getY() - mSettingsDownY; 829 positionSettings(dy); 830 if (mSettingsClosing) { 831 final boolean qsTap = 832 Math.abs(dy) < ViewConfiguration.get(mContext).getScaledTouchSlop(); 833 if (!mSettingsCancelled && !qsTap) { 834 MotionEvent cancelEvent = MotionEvent.obtainNoHistory(event); 835 cancelEvent.setAction(MotionEvent.ACTION_CANCEL); 836 dispatchSettingsEvent(cancelEvent); 837 mSettingsCancelled = true; 838 } 839 } else { 840 dispatchSettingsEvent(event); 841 } 842 } 843 return true; 844 } 845 846 private void dispatchSettingsEvent(MotionEvent event) { 847 final View target = mSettingsClosing ? mFlipSettingsView : mNotificationPanelHeader; 848 final int[] targetLoc = new int[2]; 849 target.getLocationInWindow(targetLoc); 850 final int[] panelLoc = new int[2]; 851 mNotificationPanel.getLocationInWindow(panelLoc); 852 final int dx = targetLoc[0] - panelLoc[0]; 853 final int dy = targetLoc[1] - panelLoc[1]; 854 event.offsetLocation(-dx, -dy); 855 target.dispatchTouchEvent(event); 856 } 857 858 private void positionSettings(float dy) { 859 if (mSettingsClosing) { 860 final int ph = mNotificationPanel.getMeasuredHeight(); 861 dy = Math.min(Math.max(-ph, dy), 0); 862 mFlipSettingsView.setTranslationY(dy); 863 mStackScroller.setTranslationY(ph + dy); 864 } else { 865 final int h = mFlipSettingsView.getBottom(); 866 dy = Math.min(Math.max(0, dy), h); 867 mFlipSettingsView.setTranslationY(-h + dy); 868 mStackScroller.setTranslationY(dy); 869 } 870 } 871 872 private void startKeyguard() { 873 KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class); 874 mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this, 875 mStatusBarWindow, mStatusBarWindowManager); 876 mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback(); 877 } 878 879 @Override 880 protected void onShowSearchPanel() { 881 if (mNavigationBarView != null) { 882 mNavigationBarView.getBarTransitions().setContentVisible(false); 883 } 884 } 885 886 @Override 887 protected void onHideSearchPanel() { 888 if (mNavigationBarView != null) { 889 mNavigationBarView.getBarTransitions().setContentVisible(true); 890 } 891 } 892 893 @Override 894 protected View getStatusBarView() { 895 return mStatusBarView; 896 } 897 898 @Override 899 protected WindowManager.LayoutParams getSearchLayoutParams(LayoutParams layoutParams) { 900 boolean opaque = false; 901 WindowManager.LayoutParams lp = new WindowManager.LayoutParams( 902 LayoutParams.MATCH_PARENT, 903 LayoutParams.MATCH_PARENT, 904 WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL, 905 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN 906 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM 907 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, 908 (opaque ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT)); 909 if (ActivityManager.isHighEndGfx()) { 910 lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; 911 } 912 lp.gravity = Gravity.BOTTOM | Gravity.START; 913 lp.setTitle("SearchPanel"); 914 // TODO: Define custom animation for Search panel 915 lp.windowAnimations = com.android.internal.R.style.Animation_RecentApplications; 916 lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED 917 | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING; 918 return lp; 919 } 920 921 @Override 922 protected void updateSearchPanel() { 923 super.updateSearchPanel(); 924 if (mNavigationBarView != null) { 925 mNavigationBarView.setDelegateView(mSearchPanelView); 926 } 927 } 928 929 @Override 930 public void showSearchPanel() { 931 super.showSearchPanel(); 932 mHandler.removeCallbacks(mShowSearchPanel); 933 934 // we want to freeze the sysui state wherever it is 935 mSearchPanelView.setSystemUiVisibility(mSystemUiVisibility); 936 937 if (mNavigationBarView != null) { 938 WindowManager.LayoutParams lp = 939 (android.view.WindowManager.LayoutParams) mNavigationBarView.getLayoutParams(); 940 lp.flags &= ~WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; 941 mWindowManager.updateViewLayout(mNavigationBarView, lp); 942 } 943 } 944 945 @Override 946 public void hideSearchPanel() { 947 super.hideSearchPanel(); 948 if (mNavigationBarView != null) { 949 WindowManager.LayoutParams lp = 950 (android.view.WindowManager.LayoutParams) mNavigationBarView.getLayoutParams(); 951 lp.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; 952 mWindowManager.updateViewLayout(mNavigationBarView, lp); 953 } 954 } 955 956 public int getStatusBarHeight() { 957 if (mNaturalBarHeight < 0) { 958 final Resources res = mContext.getResources(); 959 mNaturalBarHeight = 960 res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height); 961 } 962 return mNaturalBarHeight; 963 } 964 965 private View.OnClickListener mRecentsClickListener = new View.OnClickListener() { 966 public void onClick(View v) { 967 awakenDreams(); 968 toggleRecentApps(); 969 } 970 }; 971 972 private int mShowSearchHoldoff = 0; 973 private Runnable mShowSearchPanel = new Runnable() { 974 public void run() { 975 showSearchPanel(); 976 awakenDreams(); 977 } 978 }; 979 980 View.OnTouchListener mHomeSearchActionListener = new View.OnTouchListener() { 981 public boolean onTouch(View v, MotionEvent event) { 982 switch(event.getAction()) { 983 case MotionEvent.ACTION_DOWN: 984 if (!shouldDisableNavbarGestures()) { 985 mHandler.removeCallbacks(mShowSearchPanel); 986 mHandler.postDelayed(mShowSearchPanel, mShowSearchHoldoff); 987 } 988 break; 989 990 case MotionEvent.ACTION_UP: 991 case MotionEvent.ACTION_CANCEL: 992 mHandler.removeCallbacks(mShowSearchPanel); 993 awakenDreams(); 994 break; 995 } 996 return false; 997 } 998 }; 999 1000 private void awakenDreams() { 1001 if (mDreamManager != null) { 1002 try { 1003 mDreamManager.awaken(); 1004 } catch (RemoteException e) { 1005 // fine, stay asleep then 1006 } 1007 } 1008 } 1009 1010 private void prepareNavigationBarView() { 1011 mNavigationBarView.reorient(); 1012 1013 mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener); 1014 mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPreloadOnTouchListener); 1015 mNavigationBarView.getHomeButton().setOnTouchListener(mHomeSearchActionListener); 1016 mNavigationBarView.getSearchLight().setOnTouchListener(mHomeSearchActionListener); 1017 updateSearchPanel(); 1018 } 1019 1020 // For small-screen devices (read: phones) that lack hardware navigation buttons 1021 private void addNavigationBar() { 1022 if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + mNavigationBarView); 1023 if (mNavigationBarView == null) return; 1024 1025 prepareNavigationBarView(); 1026 1027 mWindowManager.addView(mNavigationBarView, getNavigationBarLayoutParams()); 1028 } 1029 1030 private void repositionNavigationBar() { 1031 if (mNavigationBarView == null || !mNavigationBarView.isAttachedToWindow()) return; 1032 1033 prepareNavigationBarView(); 1034 1035 mWindowManager.updateViewLayout(mNavigationBarView, getNavigationBarLayoutParams()); 1036 } 1037 1038 private void notifyNavigationBarScreenOn(boolean screenOn) { 1039 if (mNavigationBarView == null) return; 1040 mNavigationBarView.notifyScreenOn(screenOn); 1041 } 1042 1043 private WindowManager.LayoutParams getNavigationBarLayoutParams() { 1044 WindowManager.LayoutParams lp = new WindowManager.LayoutParams( 1045 LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, 1046 WindowManager.LayoutParams.TYPE_NAVIGATION_BAR, 1047 0 1048 | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING 1049 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 1050 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL 1051 | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH 1052 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, 1053 PixelFormat.TRANSLUCENT); 1054 // this will allow the navbar to run in an overlay on devices that support this 1055 if (ActivityManager.isHighEndGfx()) { 1056 lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; 1057 } 1058 1059 lp.setTitle("NavigationBar"); 1060 lp.windowAnimations = 0; 1061 return lp; 1062 } 1063 1064 private void addHeadsUpView() { 1065 WindowManager.LayoutParams lp = new WindowManager.LayoutParams( 1066 LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT, 1067 WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL, // above the status bar! 1068 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN 1069 | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS 1070 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL 1071 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 1072 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM 1073 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, 1074 PixelFormat.TRANSLUCENT); 1075 lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; 1076 lp.gravity = Gravity.TOP; 1077 lp.setTitle("Heads Up"); 1078 lp.packageName = mContext.getPackageName(); 1079 lp.windowAnimations = R.style.Animation_StatusBar_HeadsUp; 1080 1081 mWindowManager.addView(mHeadsUpNotificationView, lp); 1082 } 1083 1084 private void removeHeadsUpView() { 1085 mWindowManager.removeView(mHeadsUpNotificationView); 1086 } 1087 1088 public void refreshAllStatusBarIcons() { 1089 refreshAllIconsForLayout(mStatusIcons); 1090 refreshAllIconsForLayout(mNotificationIcons); 1091 } 1092 1093 private void refreshAllIconsForLayout(LinearLayout ll) { 1094 final int count = ll.getChildCount(); 1095 for (int n = 0; n < count; n++) { 1096 View child = ll.getChildAt(n); 1097 if (child instanceof StatusBarIconView) { 1098 ((StatusBarIconView) child).updateDrawable(); 1099 } 1100 } 1101 } 1102 1103 public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) { 1104 if (SPEW) Log.d(TAG, "addIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex 1105 + " icon=" + icon); 1106 StatusBarIconView view = new StatusBarIconView(mContext, slot, null); 1107 view.set(icon); 1108 mStatusIcons.addView(view, viewIndex, new LinearLayout.LayoutParams(mIconSize, mIconSize)); 1109 } 1110 1111 public void updateIcon(String slot, int index, int viewIndex, 1112 StatusBarIcon old, StatusBarIcon icon) { 1113 if (SPEW) Log.d(TAG, "updateIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex 1114 + " old=" + old + " icon=" + icon); 1115 StatusBarIconView view = (StatusBarIconView)mStatusIcons.getChildAt(viewIndex); 1116 view.set(icon); 1117 } 1118 1119 public void removeIcon(String slot, int index, int viewIndex) { 1120 if (SPEW) Log.d(TAG, "removeIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex); 1121 mStatusIcons.removeViewAt(viewIndex); 1122 } 1123 1124 public UserHandle getCurrentUserHandle() { 1125 return new UserHandle(mCurrentUserId); 1126 } 1127 1128 public void addNotification(IBinder key, StatusBarNotification notification) { 1129 if (DEBUG) Log.d(TAG, "addNotification score=" + notification.getScore()); 1130 Entry shadeEntry = createNotificationViews(key, notification); 1131 if (shadeEntry == null) { 1132 return; 1133 } 1134 if (mZenMode != Global.ZEN_MODE_OFF && mIntercepted.tryIntercept(key, notification)) { 1135 return; 1136 } 1137 if (mUseHeadsUp && shouldInterrupt(notification)) { 1138 if (DEBUG) Log.d(TAG, "launching notification in heads up mode"); 1139 Entry interruptionCandidate = new Entry(key, notification, null); 1140 ViewGroup holder = mHeadsUpNotificationView.getHolder(); 1141 if (inflateViewsForHeadsUp(interruptionCandidate, holder)) { 1142 mInterruptingNotificationTime = System.currentTimeMillis(); 1143 mInterruptingNotificationEntry = interruptionCandidate; 1144 shadeEntry.setInterruption(); 1145 1146 // 1. Populate mHeadsUpNotificationView 1147 mHeadsUpNotificationView.setNotification(mInterruptingNotificationEntry); 1148 1149 // 2. Animate mHeadsUpNotificationView in 1150 mHandler.sendEmptyMessage(MSG_SHOW_HEADS_UP); 1151 1152 // 3. Set alarm to age the notification off 1153 resetHeadsUpDecayTimer(); 1154 } 1155 } else if (notification.getNotification().fullScreenIntent != null) { 1156 // Stop screensaver if the notification has a full-screen intent. 1157 // (like an incoming phone call) 1158 awakenDreams(); 1159 1160 // not immersive & a full-screen alert should be shown 1161 if (DEBUG) Log.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent"); 1162 try { 1163 notification.getNotification().fullScreenIntent.send(); 1164 } catch (PendingIntent.CanceledException e) { 1165 } 1166 } else { 1167 // usual case: status bar visible & not immersive 1168 1169 // show the ticker if there isn't already a heads up 1170 if (mInterruptingNotificationEntry == null) { 1171 tick(null, notification, true); 1172 } 1173 } 1174 addNotificationViews(shadeEntry); 1175 // Recalculate the position of the sliding windows and the titles. 1176 setAreThereNotifications(); 1177 updateExpandedViewPos(EXPANDED_LEAVE_ALONE); 1178 } 1179 1180 @Override 1181 public void resetHeadsUpDecayTimer() { 1182 mHandler.removeMessages(MSG_HIDE_HEADS_UP); 1183 if (mUseHeadsUp && mHeadsUpNotificationDecay > 0 1184 && mHeadsUpNotificationView.isClearable()) { 1185 mHandler.sendEmptyMessageDelayed(MSG_HIDE_HEADS_UP, mHeadsUpNotificationDecay); 1186 } 1187 } 1188 1189 @Override 1190 public void updateNotification(IBinder key, StatusBarNotification notification) { 1191 super.updateNotification(key, notification); 1192 mIntercepted.update(key, notification); 1193 } 1194 1195 public void removeNotification(IBinder key) { 1196 StatusBarNotification old = removeNotificationViews(key); 1197 if (SPEW) Log.d(TAG, "removeNotification key=" + key + " old=" + old); 1198 1199 if (old != null) { 1200 // Cancel the ticker if it's still running 1201 mTicker.removeEntry(old); 1202 1203 // Recalculate the position of the sliding windows and the titles. 1204 updateExpandedViewPos(EXPANDED_LEAVE_ALONE); 1205 1206 if (ENABLE_HEADS_UP && mInterruptingNotificationEntry != null 1207 && old == mInterruptingNotificationEntry.notification) { 1208 mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP); 1209 } 1210 1211 if (CLOSE_PANEL_WHEN_EMPTIED && mNotificationData.size() == 0 1212 && !mNotificationPanel.isTracking() && !mOnKeyguard) { 1213 animateCollapsePanels(); 1214 } 1215 } 1216 mIntercepted.remove(key); 1217 setAreThereNotifications(); 1218 } 1219 1220 @Override 1221 protected void refreshLayout(int layoutDirection) { 1222 if (mNavigationBarView != null) { 1223 mNavigationBarView.setLayoutDirection(layoutDirection); 1224 } 1225 1226 if (mClearButton != null && mClearButton instanceof ImageView) { 1227 // Force asset reloading 1228 ((ImageView)mClearButton).setImageDrawable(null); 1229 ((ImageView)mClearButton).setImageResource(R.drawable.ic_notify_clear); 1230 } 1231 1232 mHeaderFlipper.refreshLayout(); 1233 mKeyguardFlipper.refreshLayout(); 1234 1235 refreshAllStatusBarIcons(); 1236 } 1237 1238 private void updateShowSearchHoldoff() { 1239 mShowSearchHoldoff = mContext.getResources().getInteger( 1240 R.integer.config_show_search_delay); 1241 } 1242 1243 private void loadNotificationShade() { 1244 if (mStackScroller == null) return; 1245 1246 int N = mNotificationData.size(); 1247 1248 ArrayList<View> toShow = new ArrayList<View>(); 1249 1250 final boolean provisioned = isDeviceProvisioned(); 1251 // If the device hasn't been through Setup, we only show system notifications 1252 for (int i=0; i<N; i++) { 1253 Entry ent = mNotificationData.get(N-i-1); 1254 if (!(provisioned || showNotificationEvenIfUnprovisioned(ent.notification))) continue; 1255 1256 // TODO How do we want to badge notifcations from profiles. 1257 if (!notificationIsForCurrentProfiles(ent.notification)) continue; 1258 1259 final int vis = ent.notification.getNotification().visibility; 1260 if (vis != Notification.VISIBILITY_SECRET) { 1261 // when isLockscreenPublicMode() we show the public form of VISIBILITY_PRIVATE notifications 1262 ent.row.setShowingPublic(isLockscreenPublicMode() 1263 && vis == Notification.VISIBILITY_PRIVATE 1264 && !userAllowsPrivateNotificationsInPublic(ent.notification.getUserId())); 1265 toShow.add(ent.row); 1266 } 1267 } 1268 1269 ArrayList<View> toRemove = new ArrayList<View>(); 1270 for (int i=0; i< mStackScroller.getChildCount(); i++) { 1271 View child = mStackScroller.getChildAt(i); 1272 if (!toShow.contains(child) && child != mKeyguardIconOverflowContainer) { 1273 toRemove.add(child); 1274 } 1275 } 1276 1277 for (View remove : toRemove) { 1278 mStackScroller.removeView(remove); 1279 } 1280 1281 for (int i=0; i<toShow.size(); i++) { 1282 View v = toShow.get(i); 1283 if (v.getParent() == null) { 1284 mStackScroller.addView(v, i); 1285 } 1286 } 1287 1288 mHeaderFlipper.provisionCheck(provisioned); 1289 mKeyguardFlipper.provisionCheck(provisioned); 1290 } 1291 1292 @Override 1293 protected void updateNotificationIcons() { 1294 if (mNotificationIcons == null) return; 1295 1296 loadNotificationShade(); 1297 1298 final LinearLayout.LayoutParams params 1299 = new LinearLayout.LayoutParams(mIconSize + 2*mIconHPadding, mNaturalBarHeight); 1300 1301 int N = mNotificationData.size(); 1302 1303 if (DEBUG) { 1304 Log.d(TAG, "refreshing icons: " + N + " notifications, mNotificationIcons=" + mNotificationIcons); 1305 } 1306 1307 ArrayList<View> toShow = new ArrayList<View>(); 1308 1309 final boolean provisioned = isDeviceProvisioned(); 1310 // If the device hasn't been through Setup, we only show system notifications 1311 for (int i=0; i<N; i++) { 1312 Entry ent = mNotificationData.get(N-i-1); 1313 if (!((provisioned && ent.notification.getScore() >= HIDE_ICONS_BELOW_SCORE) 1314 || showNotificationEvenIfUnprovisioned(ent.notification))) continue; 1315 if (!notificationIsForCurrentProfiles(ent.notification)) continue; 1316 if (isLockscreenPublicMode() 1317 && ent.notification.getNotification().visibility 1318 == Notification.VISIBILITY_SECRET 1319 && !userAllowsPrivateNotificationsInPublic(ent.notification.getUserId())) { 1320 // in "public" mode (atop a secure keyguard), secret notifs are totally hidden 1321 continue; 1322 } 1323 if (mIntercepted.isSyntheticEntry(ent)) { 1324 continue; 1325 } 1326 toShow.add(ent.icon); 1327 } 1328 1329 ArrayList<View> toRemove = new ArrayList<View>(); 1330 for (int i=0; i<mNotificationIcons.getChildCount(); i++) { 1331 View child = mNotificationIcons.getChildAt(i); 1332 if (!toShow.contains(child)) { 1333 toRemove.add(child); 1334 } 1335 } 1336 1337 for (View remove : toRemove) { 1338 mNotificationIcons.removeView(remove); 1339 } 1340 1341 for (int i=0; i<toShow.size(); i++) { 1342 View v = toShow.get(i); 1343 if (v.getParent() == null) { 1344 mNotificationIcons.addView(v, i, params); 1345 } 1346 } 1347 } 1348 1349 protected void updateCarrierLabelVisibility(boolean force) { 1350 // TODO: Handle this for the notification stack scroller as well 1351 if (!mShowCarrierInPanel) return; 1352 // The idea here is to only show the carrier label when there is enough room to see it, 1353 // i.e. when there aren't enough notifications to fill the panel. 1354 if (SPEW) { 1355 Log.d(TAG, String.format("stackScrollerh=%d scrollh=%d carrierh=%d", 1356 mStackScroller.getHeight(), mStackScroller.getHeight(), 1357 mCarrierLabelHeight)); 1358 } 1359 1360 final boolean emergencyCallsShownElsewhere = mEmergencyCallLabel != null; 1361 final boolean makeVisible = 1362 !(emergencyCallsShownElsewhere && mNetworkController.isEmergencyOnly()) 1363 && mStackScroller.getHeight() < (mNotificationPanel.getHeight() 1364 - mCarrierLabelHeight - mNotificationHeaderHeight) 1365 && mStackScroller.getVisibility() == View.VISIBLE; 1366 1367 if (force || mCarrierLabelVisible != makeVisible) { 1368 mCarrierLabelVisible = makeVisible; 1369 if (DEBUG) { 1370 Log.d(TAG, "making carrier label " + (makeVisible?"visible":"invisible")); 1371 } 1372 mCarrierLabel.animate().cancel(); 1373 if (makeVisible) { 1374 mCarrierLabel.setVisibility(View.VISIBLE); 1375 } 1376 mCarrierLabel.animate() 1377 .alpha(makeVisible ? 1f : 0f) 1378 //.setStartDelay(makeVisible ? 500 : 0) 1379 //.setDuration(makeVisible ? 750 : 100) 1380 .setDuration(150) 1381 .setListener(makeVisible ? null : new AnimatorListenerAdapter() { 1382 @Override 1383 public void onAnimationEnd(Animator animation) { 1384 if (!mCarrierLabelVisible) { // race 1385 mCarrierLabel.setVisibility(View.INVISIBLE); 1386 mCarrierLabel.setAlpha(0f); 1387 } 1388 } 1389 }) 1390 .start(); 1391 } 1392 } 1393 1394 @Override 1395 protected void setAreThereNotifications() { 1396 final boolean any = mNotificationData.size() > 0; 1397 1398 final boolean clearable = any && mNotificationData.hasClearableItems(); 1399 1400 if (SPEW) { 1401 Log.d(TAG, "setAreThereNotifications: N=" + mNotificationData.size() 1402 + " any=" + any + " clearable=" + clearable); 1403 } 1404 1405 if (mHasFlipSettings 1406 && mFlipSettingsView != null 1407 && mFlipSettingsView.getVisibility() == View.VISIBLE 1408 && mStackScroller.getVisibility() != View.VISIBLE) { 1409 // the flip settings panel is unequivocally showing; we should not be shown 1410 mClearButton.setVisibility(View.INVISIBLE); 1411 } else if (mClearButton.isShown()) { 1412 if (clearable != (mClearButton.getAlpha() == 1.0f)) { 1413 ObjectAnimator clearAnimation = ObjectAnimator.ofFloat( 1414 mClearButton, "alpha", clearable ? 1.0f : 0.0f).setDuration(250); 1415 clearAnimation.addListener(new AnimatorListenerAdapter() { 1416 @Override 1417 public void onAnimationEnd(Animator animation) { 1418 if (mClearButton.getAlpha() <= 0.0f) { 1419 mClearButton.setVisibility(View.INVISIBLE); 1420 } 1421 } 1422 1423 @Override 1424 public void onAnimationStart(Animator animation) { 1425 if (mClearButton.getAlpha() <= 0.0f) { 1426 mClearButton.setVisibility(View.VISIBLE); 1427 } 1428 } 1429 }); 1430 clearAnimation.start(); 1431 } 1432 } else { 1433 mClearButton.setAlpha(clearable ? 1.0f : 0.0f); 1434 mClearButton.setVisibility(clearable ? View.VISIBLE : View.INVISIBLE); 1435 } 1436 mClearButton.setEnabled(clearable); 1437 1438 final View nlo = mStatusBarView.findViewById(R.id.notification_lights_out); 1439 final boolean showDot = (any&&!areLightsOn()); 1440 if (showDot != (nlo.getAlpha() == 1.0f)) { 1441 if (showDot) { 1442 nlo.setAlpha(0f); 1443 nlo.setVisibility(View.VISIBLE); 1444 } 1445 nlo.animate() 1446 .alpha(showDot?1:0) 1447 .setDuration(showDot?750:250) 1448 .setInterpolator(new AccelerateInterpolator(2.0f)) 1449 .setListener(showDot ? null : new AnimatorListenerAdapter() { 1450 @Override 1451 public void onAnimationEnd(Animator _a) { 1452 nlo.setVisibility(View.GONE); 1453 } 1454 }) 1455 .start(); 1456 } 1457 1458 updateCarrierLabelVisibility(false); 1459 } 1460 1461 public void showClock(boolean show) { 1462 if (mStatusBarView == null) return; 1463 View clock = mStatusBarView.findViewById(R.id.clock); 1464 if (clock != null) { 1465 clock.setVisibility(show ? View.VISIBLE : View.GONE); 1466 } 1467 } 1468 1469 /** 1470 * State is one or more of the DISABLE constants from StatusBarManager. 1471 */ 1472 public void disable(int state) { 1473 final int old = mDisabled; 1474 final int diff = state ^ old; 1475 mDisabled = state; 1476 1477 if (DEBUG) { 1478 Log.d(TAG, String.format("disable: 0x%08x -> 0x%08x (diff: 0x%08x)", 1479 old, state, diff)); 1480 } 1481 1482 StringBuilder flagdbg = new StringBuilder(); 1483 flagdbg.append("disable: < "); 1484 flagdbg.append(((state & StatusBarManager.DISABLE_EXPAND) != 0) ? "EXPAND" : "expand"); 1485 flagdbg.append(((diff & StatusBarManager.DISABLE_EXPAND) != 0) ? "* " : " "); 1486 flagdbg.append(((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) ? "ICONS" : "icons"); 1487 flagdbg.append(((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) ? "* " : " "); 1488 flagdbg.append(((state & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) ? "ALERTS" : "alerts"); 1489 flagdbg.append(((diff & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) ? "* " : " "); 1490 flagdbg.append(((state & StatusBarManager.DISABLE_PRIVATE_NOTIFICATIONS) != 0) ? "PRIVATE" : "private"); 1491 flagdbg.append(((diff & StatusBarManager.DISABLE_PRIVATE_NOTIFICATIONS) != 0) ? "* " : " "); 1492 flagdbg.append(((state & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) ? "SYSTEM_INFO" : "system_info"); 1493 flagdbg.append(((diff & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) ? "* " : " "); 1494 flagdbg.append(((state & StatusBarManager.DISABLE_BACK) != 0) ? "BACK" : "back"); 1495 flagdbg.append(((diff & StatusBarManager.DISABLE_BACK) != 0) ? "* " : " "); 1496 flagdbg.append(((state & StatusBarManager.DISABLE_HOME) != 0) ? "HOME" : "home"); 1497 flagdbg.append(((diff & StatusBarManager.DISABLE_HOME) != 0) ? "* " : " "); 1498 flagdbg.append(((state & StatusBarManager.DISABLE_RECENT) != 0) ? "RECENT" : "recent"); 1499 flagdbg.append(((diff & StatusBarManager.DISABLE_RECENT) != 0) ? "* " : " "); 1500 flagdbg.append(((state & StatusBarManager.DISABLE_CLOCK) != 0) ? "CLOCK" : "clock"); 1501 flagdbg.append(((diff & StatusBarManager.DISABLE_CLOCK) != 0) ? "* " : " "); 1502 flagdbg.append(((state & StatusBarManager.DISABLE_SEARCH) != 0) ? "SEARCH" : "search"); 1503 flagdbg.append(((diff & StatusBarManager.DISABLE_SEARCH) != 0) ? "* " : " "); 1504 flagdbg.append(">"); 1505 Log.d(TAG, flagdbg.toString()); 1506 1507 if ((diff & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) { 1508 mSystemIconArea.animate().cancel(); 1509 if ((state & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) { 1510 mSystemIconArea.animate() 1511 .alpha(0f) 1512 .translationY(mNaturalBarHeight*0.5f) 1513 .setDuration(175) 1514 .setInterpolator(new DecelerateInterpolator(1.5f)) 1515 .setListener(mMakeIconsInvisible) 1516 .start(); 1517 } else { 1518 mSystemIconArea.setVisibility(View.VISIBLE); 1519 mSystemIconArea.animate() 1520 .alpha(1f) 1521 .translationY(0) 1522 .setStartDelay(0) 1523 .setInterpolator(new DecelerateInterpolator(1.5f)) 1524 .setDuration(175) 1525 .start(); 1526 } 1527 } 1528 1529 if ((diff & StatusBarManager.DISABLE_CLOCK) != 0) { 1530 boolean show = (state & StatusBarManager.DISABLE_CLOCK) == 0; 1531 showClock(show); 1532 } 1533 if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) { 1534 if ((state & StatusBarManager.DISABLE_EXPAND) != 0) { 1535 animateCollapsePanels(); 1536 } 1537 } 1538 1539 if ((diff & (StatusBarManager.DISABLE_HOME 1540 | StatusBarManager.DISABLE_RECENT 1541 | StatusBarManager.DISABLE_BACK 1542 | StatusBarManager.DISABLE_SEARCH)) != 0) { 1543 // the nav bar will take care of these 1544 if (mNavigationBarView != null) mNavigationBarView.setDisabledFlags(state); 1545 1546 if ((state & StatusBarManager.DISABLE_RECENT) != 0) { 1547 // close recents if it's visible 1548 mHandler.removeMessages(MSG_CLOSE_RECENTS_PANEL); 1549 mHandler.sendEmptyMessage(MSG_CLOSE_RECENTS_PANEL); 1550 } 1551 } 1552 1553 if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) { 1554 if ((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) { 1555 if (mTicking) { 1556 haltTicker(); 1557 } 1558 1559 mNotificationIcons.animate() 1560 .alpha(0f) 1561 .translationY(mNaturalBarHeight*0.5f) 1562 .setDuration(175) 1563 .setInterpolator(new DecelerateInterpolator(1.5f)) 1564 .setListener(mMakeIconsInvisible) 1565 .start(); 1566 } else { 1567 mNotificationIcons.setVisibility(View.VISIBLE); 1568 mNotificationIcons.animate() 1569 .alpha(1f) 1570 .translationY(0) 1571 .setStartDelay(0) 1572 .setInterpolator(new DecelerateInterpolator(1.5f)) 1573 .setDuration(175) 1574 .start(); 1575 } 1576 } else if ((diff & StatusBarManager.DISABLE_PRIVATE_NOTIFICATIONS) != 0) { 1577 if ((state & StatusBarManager.DISABLE_PRIVATE_NOTIFICATIONS) != 0) { 1578 // we are outside a secure keyguard, so we need to switch to "public" mode 1579 setLockscreenPublicMode(true); 1580 } else { 1581 // user has authenticated the device; full notifications may be shown 1582 setLockscreenPublicMode(false); 1583 } 1584 updateNotificationIcons(); 1585 } 1586 } 1587 1588 @Override 1589 protected BaseStatusBar.H createHandler() { 1590 return new PhoneStatusBar.H(); 1591 } 1592 1593 /** 1594 * All changes to the status bar and notifications funnel through here and are batched. 1595 */ 1596 private class H extends BaseStatusBar.H { 1597 public void handleMessage(Message m) { 1598 super.handleMessage(m); 1599 switch (m.what) { 1600 case MSG_OPEN_NOTIFICATION_PANEL: 1601 animateExpandNotificationsPanel(); 1602 break; 1603 case MSG_OPEN_SETTINGS_PANEL: 1604 animateExpandSettingsPanel(); 1605 break; 1606 case MSG_CLOSE_PANELS: 1607 animateCollapsePanels(); 1608 break; 1609 case MSG_SHOW_HEADS_UP: 1610 setHeadsUpVisibility(true); 1611 break; 1612 case MSG_HIDE_HEADS_UP: 1613 setHeadsUpVisibility(false); 1614 break; 1615 case MSG_ESCALATE_HEADS_UP: 1616 escalateHeadsUp(); 1617 setHeadsUpVisibility(false); 1618 break; 1619 } 1620 } 1621 } 1622 1623 /** if the interrupting notification had a fullscreen intent, fire it now. */ 1624 private void escalateHeadsUp() { 1625 if (mInterruptingNotificationEntry != null) { 1626 final StatusBarNotification sbn = mInterruptingNotificationEntry.notification; 1627 final Notification notification = sbn.getNotification(); 1628 if (notification.fullScreenIntent != null) { 1629 if (DEBUG) 1630 Log.d(TAG, "converting a heads up to fullScreen"); 1631 try { 1632 notification.fullScreenIntent.send(); 1633 } catch (PendingIntent.CanceledException e) { 1634 } 1635 } 1636 } 1637 } 1638 1639 public Handler getHandler() { 1640 return mHandler; 1641 } 1642 1643 View.OnFocusChangeListener mFocusChangeListener = new View.OnFocusChangeListener() { 1644 public void onFocusChange(View v, boolean hasFocus) { 1645 // Because 'v' is a ViewGroup, all its children will be (un)selected 1646 // too, which allows marqueeing to work. 1647 v.setSelected(hasFocus); 1648 } 1649 }; 1650 1651 boolean panelsEnabled() { 1652 return (mDisabled & StatusBarManager.DISABLE_EXPAND) == 0; 1653 } 1654 1655 void makeExpandedVisible() { 1656 if (SPEW) Log.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible); 1657 if (mExpandedVisible || !panelsEnabled()) { 1658 return; 1659 } 1660 1661 mExpandedVisible = true; 1662 if (mNavigationBarView != null) 1663 mNavigationBarView.setSlippery(true); 1664 1665 updateCarrierLabelVisibility(true); 1666 1667 updateExpandedViewPos(EXPANDED_LEAVE_ALONE); 1668 1669 // Expand the window to encompass the full screen in anticipation of the drag. 1670 // This is only possible to do atomically because the status bar is at the top of the screen! 1671 mStatusBarWindowManager.setStatusBarExpanded(true); 1672 1673 visibilityChanged(true); 1674 1675 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true); 1676 } 1677 1678 public void animateCollapsePanels() { 1679 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE); 1680 } 1681 1682 public void animateCollapsePanels(int flags) { 1683 if (SPEW) { 1684 Log.d(TAG, "animateCollapse():" 1685 + " mExpandedVisible=" + mExpandedVisible 1686 + " flags=" + flags); 1687 } 1688 1689 if ((flags & CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL) == 0) { 1690 mHandler.removeMessages(MSG_CLOSE_RECENTS_PANEL); 1691 mHandler.sendEmptyMessage(MSG_CLOSE_RECENTS_PANEL); 1692 } 1693 1694 if ((flags & CommandQueue.FLAG_EXCLUDE_SEARCH_PANEL) == 0) { 1695 mHandler.removeMessages(MSG_CLOSE_SEARCH_PANEL); 1696 mHandler.sendEmptyMessage(MSG_CLOSE_SEARCH_PANEL); 1697 } 1698 1699 if (mStatusBarWindow != null) { 1700 1701 // release focus immediately to kick off focus change transition 1702 mStatusBarWindowManager.setStatusBarFocusable(false); 1703 1704 mStatusBarWindow.cancelExpandHelper(); 1705 mStatusBarView.collapseAllPanels(true); 1706 if (isFlippedToSettings()) { 1707 flipToNotifications(); 1708 } 1709 } 1710 } 1711 1712 public ViewPropertyAnimator setVisibilityWhenDone( 1713 final ViewPropertyAnimator a, final View v, final int vis) { 1714 a.setListener(new AnimatorListenerAdapter() { 1715 @Override 1716 public void onAnimationEnd(Animator animation) { 1717 v.setVisibility(vis); 1718 a.setListener(null); // oneshot 1719 } 1720 }); 1721 return a; 1722 } 1723 1724 public Animator setVisibilityWhenDone( 1725 final Animator a, final View v, final int vis) { 1726 a.addListener(new AnimatorListenerAdapter() { 1727 @Override 1728 public void onAnimationEnd(Animator animation) { 1729 v.setVisibility(vis); 1730 } 1731 }); 1732 return a; 1733 } 1734 1735 public Animator interpolator(TimeInterpolator ti, Animator a) { 1736 a.setInterpolator(ti); 1737 return a; 1738 } 1739 1740 public Animator startDelay(int d, Animator a) { 1741 a.setStartDelay(d); 1742 return a; 1743 } 1744 1745 public Animator start(Animator a) { 1746 a.start(); 1747 return a; 1748 } 1749 1750 final TimeInterpolator mAccelerateInterpolator = new AccelerateInterpolator(); 1751 final TimeInterpolator mDecelerateInterpolator = new DecelerateInterpolator(); 1752 final int FLIP_DURATION_OUT = 125; 1753 final int FLIP_DURATION_IN = 225; 1754 final int FLIP_DURATION = (FLIP_DURATION_IN + FLIP_DURATION_OUT); 1755 1756 Animator mScrollViewAnim, mFlipSettingsViewAnim, mClearButtonAnim; 1757 1758 @Override 1759 public void animateExpandNotificationsPanel() { 1760 if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible); 1761 if (!panelsEnabled()) { 1762 return ; 1763 } 1764 1765 mNotificationPanel.expand(); 1766 if (mHasFlipSettings && mStackScroller.getVisibility() != View.VISIBLE) { 1767 flipToNotifications(); 1768 } 1769 1770 if (false) postStartTracing(); 1771 } 1772 1773 public void flipToNotifications() { 1774 if (mFlipSettingsViewAnim != null) mFlipSettingsViewAnim.cancel(); 1775 if (mScrollViewAnim != null) mScrollViewAnim.cancel(); 1776 mHeaderFlipper.cancel(); 1777 mKeyguardFlipper.cancel(); 1778 if (mClearButtonAnim != null) mClearButtonAnim.cancel(); 1779 mStackScroller.setVisibility(View.VISIBLE); 1780 final int h = mNotificationPanel.getMeasuredHeight(); 1781 final float settingsY = mSettingsTracker != null ? mFlipSettingsView.getTranslationY() : 0; 1782 final float scrollerY = mSettingsTracker != null ? mStackScroller.getTranslationY() : h; 1783 mScrollViewAnim = start( 1784 interpolator(mDecelerateInterpolator, 1785 ObjectAnimator.ofFloat(mStackScroller, View.TRANSLATION_Y, scrollerY, 0) 1786 .setDuration(FLIP_DURATION) 1787 )); 1788 mFlipSettingsViewAnim = start( 1789 setVisibilityWhenDone( 1790 interpolator(mDecelerateInterpolator, 1791 ObjectAnimator.ofFloat(mFlipSettingsView, View.TRANSLATION_Y, settingsY, -h) 1792 ) 1793 .setDuration(FLIP_DURATION), 1794 mFlipSettingsView, View.INVISIBLE)); 1795 mHeaderFlipper.flipToNotifications(); 1796 mKeyguardFlipper.flipToNotifications(); 1797 mClearButton.setVisibility(View.VISIBLE); 1798 mClearButton.setAlpha(0f); 1799 setAreThereNotifications(); // this will show/hide the button as necessary 1800 mNotificationPanel.postDelayed(new Runnable() { 1801 public void run() { 1802 updateCarrierLabelVisibility(false); 1803 } 1804 }, FLIP_DURATION - 150); 1805 if (mOnFlipRunnable != null) { 1806 mOnFlipRunnable.run(); 1807 } 1808 } 1809 1810 @Override 1811 public void animateExpandSettingsPanel() { 1812 if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible); 1813 if (!panelsEnabled()) { 1814 return; 1815 } 1816 1817 // Settings are not available in setup 1818 if (!mUserSetup) return; 1819 1820 if (mHasFlipSettings) { 1821 mNotificationPanel.expand(); 1822 if (mFlipSettingsView.getVisibility() != View.VISIBLE 1823 || mFlipSettingsView.getTranslationY() < 0) { 1824 flipToSettings(); 1825 } 1826 } else if (mSettingsPanel != null) { 1827 mSettingsPanel.expand(); 1828 } 1829 1830 if (false) postStartTracing(); 1831 } 1832 1833 public boolean isFlippedToSettings() { 1834 if (mFlipSettingsView != null) { 1835 return mFlipSettingsView.getVisibility() == View.VISIBLE; 1836 } 1837 return false; 1838 } 1839 1840 public void flipToSettings() { 1841 // Settings are not available in setup 1842 if (!mUserSetup) return; 1843 1844 if (mFlipSettingsViewAnim != null) mFlipSettingsViewAnim.cancel(); 1845 if (mScrollViewAnim != null) mScrollViewAnim.cancel(); 1846 mHeaderFlipper.cancel(); 1847 mKeyguardFlipper.cancel(); 1848 if (mClearButtonAnim != null) mClearButtonAnim.cancel(); 1849 1850 mFlipSettingsView.setVisibility(View.VISIBLE); 1851 final int h = mNotificationPanel.getMeasuredHeight(); 1852 final float settingsY = mSettingsTracker != null ? mFlipSettingsView.getTranslationY() : -h; 1853 final float scrollerY = mSettingsTracker != null ? mStackScroller.getTranslationY() : 0; 1854 mFlipSettingsViewAnim = start( 1855 startDelay(0, 1856 interpolator(mDecelerateInterpolator, 1857 ObjectAnimator.ofFloat(mFlipSettingsView, View.TRANSLATION_Y, settingsY, 0f) 1858 .setDuration(FLIP_DURATION) 1859 ))); 1860 mScrollViewAnim = start( 1861 setVisibilityWhenDone( 1862 interpolator(mDecelerateInterpolator, 1863 ObjectAnimator.ofFloat(mStackScroller, View.TRANSLATION_Y, scrollerY, h) 1864 ) 1865 .setDuration(FLIP_DURATION), 1866 mStackScroller, View.INVISIBLE)); 1867 mHeaderFlipper.flipToSettings(); 1868 mKeyguardFlipper.flipToSettings(); 1869 mClearButtonAnim = start( 1870 setVisibilityWhenDone( 1871 ObjectAnimator.ofFloat(mClearButton, View.ALPHA, 0f) 1872 .setDuration(FLIP_DURATION), 1873 mClearButton, View.INVISIBLE)); 1874 mNotificationPanel.postDelayed(new Runnable() { 1875 public void run() { 1876 updateCarrierLabelVisibility(false); 1877 } 1878 }, FLIP_DURATION - 150); 1879 if (mOnFlipRunnable != null) { 1880 mOnFlipRunnable.run(); 1881 } 1882 } 1883 1884 public void flipPanels() { 1885 if (mHasFlipSettings) { 1886 if (mFlipSettingsView.getVisibility() != View.VISIBLE) { 1887 flipToSettings(); 1888 } else { 1889 flipToNotifications(); 1890 } 1891 } 1892 } 1893 1894 public void animateCollapseQuickSettings() { 1895 mStatusBarView.collapseAllPanels(true); 1896 } 1897 1898 void makeExpandedInvisibleSoon() { 1899 mHandler.postDelayed(new Runnable() { public void run() { makeExpandedInvisible(); }}, 50); 1900 } 1901 1902 void makeExpandedInvisible() { 1903 if (SPEW) Log.d(TAG, "makeExpandedInvisible: mExpandedVisible=" + mExpandedVisible 1904 + " mExpandedVisible=" + mExpandedVisible); 1905 1906 if (!mExpandedVisible || mStatusBarWindow == null) { 1907 return; 1908 } 1909 1910 // Ensure the panel is fully collapsed (just in case; bug 6765842, 7260868) 1911 mStatusBarView.collapseAllPanels(/*animate=*/ false); 1912 1913 if (mHasFlipSettings) { 1914 // reset things to their proper state 1915 if (mFlipSettingsViewAnim != null) mFlipSettingsViewAnim.cancel(); 1916 if (mScrollViewAnim != null) mScrollViewAnim.cancel(); 1917 if (mClearButtonAnim != null) mClearButtonAnim.cancel(); 1918 1919 mStackScroller.setVisibility(View.VISIBLE); 1920 mNotificationPanel.setVisibility(View.GONE); 1921 mFlipSettingsView.setVisibility(View.GONE); 1922 1923 setAreThereNotifications(); // show the clear button 1924 1925 mHeaderFlipper.reset(); 1926 mKeyguardFlipper.reset(); 1927 } 1928 1929 mExpandedVisible = false; 1930 if (mNavigationBarView != null) 1931 mNavigationBarView.setSlippery(false); 1932 visibilityChanged(false); 1933 1934 // Shrink the window to the size of the status bar only 1935 mStatusBarWindowManager.setStatusBarExpanded(false); 1936 1937 if ((mDisabled & StatusBarManager.DISABLE_NOTIFICATION_ICONS) == 0) { 1938 setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in); 1939 } 1940 1941 // Close any "App info" popups that might have snuck on-screen 1942 dismissPopups(); 1943 1944 if (mPostCollapseCleanup != null) { 1945 mPostCollapseCleanup.run(); 1946 mPostCollapseCleanup = null; 1947 } 1948 1949 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false); 1950 1951 showBouncer(); 1952 } 1953 1954 public boolean interceptTouchEvent(MotionEvent event) { 1955 if (DEBUG_GESTURES) { 1956 if (event.getActionMasked() != MotionEvent.ACTION_MOVE) { 1957 EventLog.writeEvent(EventLogTags.SYSUI_STATUSBAR_TOUCH, 1958 event.getActionMasked(), (int) event.getX(), (int) event.getY(), mDisabled); 1959 } 1960 1961 } 1962 1963 if (SPEW) { 1964 Log.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled=" 1965 + mDisabled + " mTracking=" + mTracking); 1966 } else if (CHATTY) { 1967 if (event.getAction() != MotionEvent.ACTION_MOVE) { 1968 Log.d(TAG, String.format( 1969 "panel: %s at (%f, %f) mDisabled=0x%08x", 1970 MotionEvent.actionToString(event.getAction()), 1971 event.getRawX(), event.getRawY(), mDisabled)); 1972 } 1973 } 1974 1975 if (DEBUG_GESTURES) { 1976 mGestureRec.add(event); 1977 } 1978 1979 if (mStatusBarWindowState == WINDOW_STATE_SHOWING) { 1980 final boolean upOrCancel = 1981 event.getAction() == MotionEvent.ACTION_UP || 1982 event.getAction() == MotionEvent.ACTION_CANCEL; 1983 if (upOrCancel && !mExpandedVisible) { 1984 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false); 1985 } else { 1986 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true); 1987 } 1988 } 1989 return false; 1990 } 1991 1992 public GestureRecorder getGestureRecorder() { 1993 return mGestureRec; 1994 } 1995 1996 private void setNavigationIconHints(int hints) { 1997 if (hints == mNavigationIconHints) return; 1998 1999 mNavigationIconHints = hints; 2000 2001 if (mNavigationBarView != null) { 2002 mNavigationBarView.setNavigationIconHints(hints); 2003 } 2004 checkBarModes(); 2005 } 2006 2007 @Override // CommandQueue 2008 public void setWindowState(int window, int state) { 2009 boolean showing = state == WINDOW_STATE_SHOWING; 2010 if (mStatusBarWindow != null 2011 && window == StatusBarManager.WINDOW_STATUS_BAR 2012 && mStatusBarWindowState != state) { 2013 mStatusBarWindowState = state; 2014 if (DEBUG_WINDOW_STATE) Log.d(TAG, "Status bar " + windowStateToString(state)); 2015 if (!showing) { 2016 mStatusBarView.collapseAllPanels(false); 2017 } 2018 } 2019 if (mNavigationBarView != null 2020 && window == StatusBarManager.WINDOW_NAVIGATION_BAR 2021 && mNavigationBarWindowState != state) { 2022 mNavigationBarWindowState = state; 2023 if (DEBUG_WINDOW_STATE) Log.d(TAG, "Navigation bar " + windowStateToString(state)); 2024 } 2025 } 2026 2027 @Override // CommandQueue 2028 public void setSystemUiVisibility(int vis, int mask) { 2029 final int oldVal = mSystemUiVisibility; 2030 final int newVal = (oldVal&~mask) | (vis&mask); 2031 final int diff = newVal ^ oldVal; 2032 if (DEBUG) Log.d(TAG, String.format( 2033 "setSystemUiVisibility vis=%s mask=%s oldVal=%s newVal=%s diff=%s", 2034 Integer.toHexString(vis), Integer.toHexString(mask), 2035 Integer.toHexString(oldVal), Integer.toHexString(newVal), 2036 Integer.toHexString(diff))); 2037 if (diff != 0) { 2038 mSystemUiVisibility = newVal; 2039 2040 // update low profile 2041 if ((diff & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0) { 2042 final boolean lightsOut = (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0; 2043 if (lightsOut) { 2044 animateCollapsePanels(); 2045 if (mTicking) { 2046 haltTicker(); 2047 } 2048 } 2049 2050 setAreThereNotifications(); 2051 } 2052 2053 // update status bar mode 2054 final int sbMode = computeBarMode(oldVal, newVal, mStatusBarView.getBarTransitions(), 2055 View.STATUS_BAR_TRANSIENT, View.STATUS_BAR_TRANSLUCENT); 2056 2057 // update navigation bar mode 2058 final int nbMode = mNavigationBarView == null ? -1 : computeBarMode( 2059 oldVal, newVal, mNavigationBarView.getBarTransitions(), 2060 View.NAVIGATION_BAR_TRANSIENT, View.NAVIGATION_BAR_TRANSLUCENT); 2061 final boolean sbModeChanged = sbMode != -1; 2062 final boolean nbModeChanged = nbMode != -1; 2063 boolean checkBarModes = false; 2064 if (sbModeChanged && sbMode != mStatusBarMode) { 2065 mStatusBarMode = sbMode; 2066 checkBarModes = true; 2067 } 2068 if (nbModeChanged && nbMode != mNavigationBarMode) { 2069 mNavigationBarMode = nbMode; 2070 checkBarModes = true; 2071 } 2072 if (checkBarModes) { 2073 checkBarModes(); 2074 } 2075 if (sbModeChanged || nbModeChanged) { 2076 // update transient bar autohide 2077 if (mStatusBarMode == MODE_SEMI_TRANSPARENT || mNavigationBarMode == MODE_SEMI_TRANSPARENT) { 2078 scheduleAutohide(); 2079 } else { 2080 cancelAutohide(); 2081 } 2082 } 2083 2084 // ready to unhide 2085 if ((vis & View.STATUS_BAR_UNHIDE) != 0) { 2086 mSystemUiVisibility &= ~View.STATUS_BAR_UNHIDE; 2087 } 2088 if ((vis & View.NAVIGATION_BAR_UNHIDE) != 0) { 2089 mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE; 2090 } 2091 2092 // send updated sysui visibility to window manager 2093 notifyUiVisibilityChanged(mSystemUiVisibility); 2094 } 2095 } 2096 2097 private int computeBarMode(int oldVis, int newVis, BarTransitions transitions, 2098 int transientFlag, int translucentFlag) { 2099 final int oldMode = barMode(oldVis, transientFlag, translucentFlag); 2100 final int newMode = barMode(newVis, transientFlag, translucentFlag); 2101 if (oldMode == newMode) { 2102 return -1; // no mode change 2103 } 2104 return newMode; 2105 } 2106 2107 private int barMode(int vis, int transientFlag, int translucentFlag) { 2108 return (vis & transientFlag) != 0 ? MODE_SEMI_TRANSPARENT 2109 : (vis & translucentFlag) != 0 ? MODE_TRANSLUCENT 2110 : (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0 ? MODE_LIGHTS_OUT 2111 : MODE_OPAQUE; 2112 } 2113 2114 private void checkBarModes() { 2115 if (mDemoMode) return; 2116 int sbMode = mStatusBarMode; 2117 if (panelsEnabled() && (mInteractingWindows & StatusBarManager.WINDOW_STATUS_BAR) != 0) { 2118 // if panels are expandable, force the status bar opaque on any interaction 2119 sbMode = MODE_OPAQUE; 2120 } 2121 checkBarMode(sbMode, mStatusBarWindowState, mStatusBarView.getBarTransitions()); 2122 if (mNavigationBarView != null) { 2123 checkBarMode(mNavigationBarMode, 2124 mNavigationBarWindowState, mNavigationBarView.getBarTransitions()); 2125 } 2126 } 2127 2128 private void checkBarMode(int mode, int windowState, BarTransitions transitions) { 2129 final boolean anim = (mScreenOn == null || mScreenOn) && windowState != WINDOW_STATE_HIDDEN; 2130 transitions.transitionTo(mode, anim); 2131 } 2132 2133 private void finishBarAnimations() { 2134 mStatusBarView.getBarTransitions().finishAnimations(); 2135 if (mNavigationBarView != null) { 2136 mNavigationBarView.getBarTransitions().finishAnimations(); 2137 } 2138 } 2139 2140 private final Runnable mCheckBarModes = new Runnable() { 2141 @Override 2142 public void run() { 2143 checkBarModes(); 2144 }}; 2145 2146 @Override 2147 public void setInteracting(int barWindow, boolean interacting) { 2148 mInteractingWindows = interacting 2149 ? (mInteractingWindows | barWindow) 2150 : (mInteractingWindows & ~barWindow); 2151 if (mInteractingWindows != 0) { 2152 suspendAutohide(); 2153 } else { 2154 resumeSuspendedAutohide(); 2155 } 2156 checkBarModes(); 2157 } 2158 2159 private void resumeSuspendedAutohide() { 2160 if (mAutohideSuspended) { 2161 scheduleAutohide(); 2162 mHandler.postDelayed(mCheckBarModes, 500); // longer than home -> launcher 2163 } 2164 } 2165 2166 private void suspendAutohide() { 2167 mHandler.removeCallbacks(mAutohide); 2168 mHandler.removeCallbacks(mCheckBarModes); 2169 mAutohideSuspended = (mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0; 2170 } 2171 2172 private void cancelAutohide() { 2173 mAutohideSuspended = false; 2174 mHandler.removeCallbacks(mAutohide); 2175 } 2176 2177 private void scheduleAutohide() { 2178 cancelAutohide(); 2179 mHandler.postDelayed(mAutohide, AUTOHIDE_TIMEOUT_MS); 2180 } 2181 2182 private void checkUserAutohide(View v, MotionEvent event) { 2183 if ((mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0 // a transient bar is revealed 2184 && event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar 2185 && event.getX() == 0 && event.getY() == 0 // a touch outside both bars 2186 ) { 2187 userAutohide(); 2188 } 2189 } 2190 2191 private void userAutohide() { 2192 cancelAutohide(); 2193 mHandler.postDelayed(mAutohide, 350); // longer than app gesture -> flag clear 2194 } 2195 2196 private boolean areLightsOn() { 2197 return 0 == (mSystemUiVisibility & View.SYSTEM_UI_FLAG_LOW_PROFILE); 2198 } 2199 2200 public void setLightsOn(boolean on) { 2201 Log.v(TAG, "setLightsOn(" + on + ")"); 2202 if (on) { 2203 setSystemUiVisibility(0, View.SYSTEM_UI_FLAG_LOW_PROFILE); 2204 } else { 2205 setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE, View.SYSTEM_UI_FLAG_LOW_PROFILE); 2206 } 2207 } 2208 2209 private void notifyUiVisibilityChanged(int vis) { 2210 try { 2211 mWindowManagerService.statusBarVisibilityChanged(vis); 2212 } catch (RemoteException ex) { 2213 } 2214 } 2215 2216 public void topAppWindowChanged(boolean showMenu) { 2217 if (DEBUG) { 2218 Log.d(TAG, (showMenu?"showing":"hiding") + " the MENU button"); 2219 } 2220 if (mNavigationBarView != null) { 2221 mNavigationBarView.setMenuVisibility(showMenu); 2222 } 2223 2224 // See above re: lights-out policy for legacy apps. 2225 if (showMenu) setLightsOn(true); 2226 } 2227 2228 @Override 2229 public void setImeWindowStatus(IBinder token, int vis, int backDisposition) { 2230 boolean altBack = (backDisposition == InputMethodService.BACK_DISPOSITION_WILL_DISMISS) 2231 || ((vis & InputMethodService.IME_VISIBLE) != 0); 2232 2233 setNavigationIconHints( 2234 altBack ? (mNavigationIconHints | NAVIGATION_HINT_BACK_ALT) 2235 : (mNavigationIconHints & ~NAVIGATION_HINT_BACK_ALT)); 2236 if (mQS != null) mQS.setImeWindowStatus(vis > 0); 2237 } 2238 2239 @Override 2240 public void setHardKeyboardStatus(boolean available, boolean enabled) {} 2241 2242 @Override 2243 protected void tick(IBinder key, StatusBarNotification n, boolean firstTime) { 2244 // no ticking in lights-out mode 2245 if (!areLightsOn()) return; 2246 2247 // no ticking in Setup 2248 if (!isDeviceProvisioned()) return; 2249 2250 // not for you 2251 if (!notificationIsForCurrentProfiles(n)) return; 2252 2253 // Show the ticker if one is requested. Also don't do this 2254 // until status bar window is attached to the window manager, 2255 // because... well, what's the point otherwise? And trying to 2256 // run a ticker without being attached will crash! 2257 if (n.getNotification().tickerText != null && mStatusBarWindow != null 2258 && mStatusBarWindow.getWindowToken() != null) { 2259 if (0 == (mDisabled & (StatusBarManager.DISABLE_NOTIFICATION_ICONS 2260 | StatusBarManager.DISABLE_NOTIFICATION_TICKER))) { 2261 mTicker.addEntry(n); 2262 } 2263 } 2264 } 2265 2266 private class MyTicker extends Ticker { 2267 MyTicker(Context context, View sb) { 2268 super(context, sb); 2269 } 2270 2271 @Override 2272 public void tickerStarting() { 2273 mTicking = true; 2274 mStatusBarContents.setVisibility(View.GONE); 2275 mTickerView.setVisibility(View.VISIBLE); 2276 mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_up_in, null)); 2277 mStatusBarContents.startAnimation(loadAnim(com.android.internal.R.anim.push_up_out, null)); 2278 } 2279 2280 @Override 2281 public void tickerDone() { 2282 mStatusBarContents.setVisibility(View.VISIBLE); 2283 mTickerView.setVisibility(View.GONE); 2284 mStatusBarContents.startAnimation(loadAnim(com.android.internal.R.anim.push_down_in, null)); 2285 mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_down_out, 2286 mTickingDoneListener)); 2287 } 2288 2289 public void tickerHalting() { 2290 if (mStatusBarContents.getVisibility() != View.VISIBLE) { 2291 mStatusBarContents.setVisibility(View.VISIBLE); 2292 mStatusBarContents 2293 .startAnimation(loadAnim(com.android.internal.R.anim.fade_in, null)); 2294 } 2295 mTickerView.setVisibility(View.GONE); 2296 // we do not animate the ticker away at this point, just get rid of it (b/6992707) 2297 } 2298 } 2299 2300 Animation.AnimationListener mTickingDoneListener = new Animation.AnimationListener() {; 2301 public void onAnimationEnd(Animation animation) { 2302 mTicking = false; 2303 } 2304 public void onAnimationRepeat(Animation animation) { 2305 } 2306 public void onAnimationStart(Animation animation) { 2307 } 2308 }; 2309 2310 private Animation loadAnim(int id, Animation.AnimationListener listener) { 2311 Animation anim = AnimationUtils.loadAnimation(mContext, id); 2312 if (listener != null) { 2313 anim.setAnimationListener(listener); 2314 } 2315 return anim; 2316 } 2317 2318 public static String viewInfo(View v) { 2319 return "[(" + v.getLeft() + "," + v.getTop() + ")(" + v.getRight() + "," + v.getBottom() 2320 + ") " + v.getWidth() + "x" + v.getHeight() + "]"; 2321 } 2322 2323 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2324 synchronized (mQueueLock) { 2325 pw.println("Current Status Bar state:"); 2326 pw.println(" mExpandedVisible=" + mExpandedVisible 2327 + ", mTrackingPosition=" + mTrackingPosition); 2328 pw.println(" mTicking=" + mTicking); 2329 pw.println(" mTracking=" + mTracking); 2330 pw.println(" mDisplayMetrics=" + mDisplayMetrics); 2331 pw.println(" mStackScroller: " + viewInfo(mStackScroller)); 2332 pw.println(" mTickerView: " + viewInfo(mTickerView)); 2333 pw.println(" mStackScroller: " + viewInfo(mStackScroller) 2334 + " scroll " + mStackScroller.getScrollX() 2335 + "," + mStackScroller.getScrollY()); 2336 } 2337 2338 pw.print(" mInteractingWindows="); pw.println(mInteractingWindows); 2339 pw.print(" mStatusBarWindowState="); 2340 pw.println(windowStateToString(mStatusBarWindowState)); 2341 pw.print(" mStatusBarMode="); 2342 pw.println(BarTransitions.modeToString(mStatusBarMode)); 2343 pw.print(" mZenMode="); 2344 pw.println(Settings.Global.zenModeToString(mZenMode)); 2345 pw.print(" mUseHeadsUp="); 2346 pw.println(mUseHeadsUp); 2347 pw.print(" interrupting package: "); 2348 pw.println(hunStateToString(mInterruptingNotificationEntry)); 2349 dumpBarTransitions(pw, "mStatusBarView", mStatusBarView.getBarTransitions()); 2350 if (mNavigationBarView != null) { 2351 pw.print(" mNavigationBarWindowState="); 2352 pw.println(windowStateToString(mNavigationBarWindowState)); 2353 pw.print(" mNavigationBarMode="); 2354 pw.println(BarTransitions.modeToString(mNavigationBarMode)); 2355 dumpBarTransitions(pw, "mNavigationBarView", mNavigationBarView.getBarTransitions()); 2356 } 2357 2358 pw.print(" mNavigationBarView="); 2359 if (mNavigationBarView == null) { 2360 pw.println("null"); 2361 } else { 2362 mNavigationBarView.dump(fd, pw, args); 2363 } 2364 2365 pw.println(" Panels: "); 2366 if (mNotificationPanel != null) { 2367 pw.println(" mNotificationPanel=" + 2368 mNotificationPanel + " params=" + mNotificationPanel.getLayoutParams().debug("")); 2369 pw.print (" "); 2370 mNotificationPanel.dump(fd, pw, args); 2371 } 2372 if (mSettingsPanel != null) { 2373 pw.println(" mSettingsPanel=" + 2374 mSettingsPanel + " params=" + mSettingsPanel.getLayoutParams().debug("")); 2375 pw.print (" "); 2376 mSettingsPanel.dump(fd, pw, args); 2377 } 2378 2379 if (DUMPTRUCK) { 2380 synchronized (mNotificationData) { 2381 int N = mNotificationData.size(); 2382 pw.println(" notification icons: " + N); 2383 for (int i=0; i<N; i++) { 2384 NotificationData.Entry e = mNotificationData.get(i); 2385 pw.println(" [" + i + "] key=" + e.key + " icon=" + e.icon); 2386 StatusBarNotification n = e.notification; 2387 pw.println(" pkg=" + n.getPackageName() + " id=" + n.getId() + " score=" + n.getScore()); 2388 pw.println(" notification=" + n.getNotification()); 2389 pw.println(" tickerText=\"" + n.getNotification().tickerText + "\""); 2390 } 2391 } 2392 2393 int N = mStatusIcons.getChildCount(); 2394 pw.println(" system icons: " + N); 2395 for (int i=0; i<N; i++) { 2396 StatusBarIconView ic = (StatusBarIconView) mStatusIcons.getChildAt(i); 2397 pw.println(" [" + i + "] icon=" + ic); 2398 } 2399 2400 if (false) { 2401 pw.println("see the logcat for a dump of the views we have created."); 2402 // must happen on ui thread 2403 mHandler.post(new Runnable() { 2404 public void run() { 2405 mStatusBarView.getLocationOnScreen(mAbsPos); 2406 Log.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1] 2407 + ") " + mStatusBarView.getWidth() + "x" 2408 + getStatusBarHeight()); 2409 mStatusBarView.debug(); 2410 } 2411 }); 2412 } 2413 } 2414 2415 if (DEBUG_GESTURES) { 2416 pw.print(" status bar gestures: "); 2417 mGestureRec.dump(fd, pw, args); 2418 } 2419 2420 mNetworkController.dump(fd, pw, args); 2421 } 2422 2423 private String hunStateToString(Entry entry) { 2424 if (entry == null) return "null"; 2425 if (entry.notification == null) return "corrupt"; 2426 return entry.notification.getPackageName(); 2427 } 2428 2429 private static void dumpBarTransitions(PrintWriter pw, String var, BarTransitions transitions) { 2430 pw.print(" "); pw.print(var); pw.print(".BarTransitions.mMode="); 2431 pw.println(BarTransitions.modeToString(transitions.getMode())); 2432 } 2433 2434 @Override 2435 public void createAndAddWindows() { 2436 addStatusBarWindow(); 2437 } 2438 2439 private void addStatusBarWindow() { 2440 makeStatusBarView(); 2441 mStatusBarWindowManager = new StatusBarWindowManager(mContext); 2442 mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight()); 2443 } 2444 2445 void setNotificationIconVisibility(boolean visible, int anim) { 2446 int old = mNotificationIcons.getVisibility(); 2447 int v = visible ? View.VISIBLE : View.INVISIBLE; 2448 if (old != v) { 2449 mNotificationIcons.setVisibility(v); 2450 mNotificationIcons.startAnimation(loadAnim(anim, null)); 2451 } 2452 } 2453 2454 void updateExpandedInvisiblePosition() { 2455 mTrackingPosition = -mDisplayMetrics.heightPixels; 2456 } 2457 2458 static final float saturate(float a) { 2459 return a < 0f ? 0f : (a > 1f ? 1f : a); 2460 } 2461 2462 @Override 2463 protected int getExpandedViewMaxHeight() { 2464 return mDisplayMetrics.heightPixels - mNotificationPanelMarginBottomPx; 2465 } 2466 2467 @Override 2468 public void updateExpandedViewPos(int thingy) { 2469 if (SPEW) Log.v(TAG, "updateExpandedViewPos"); 2470 2471 // on larger devices, the notification panel is propped open a bit 2472 mNotificationPanel.setMinimumHeight( 2473 (int)(mNotificationPanelMinHeightFrac * mCurrentDisplaySize.y)); 2474 2475 FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mNotificationPanel.getLayoutParams(); 2476 lp.gravity = mNotificationPanelGravity; 2477 lp.setMarginStart(mNotificationPanelMarginPx); 2478 mNotificationPanel.setLayoutParams(lp); 2479 2480 if (mSettingsPanel != null) { 2481 lp = (FrameLayout.LayoutParams) mSettingsPanel.getLayoutParams(); 2482 lp.gravity = mSettingsPanelGravity; 2483 lp.setMarginEnd(mNotificationPanelMarginPx); 2484 mSettingsPanel.setLayoutParams(lp); 2485 } 2486 2487 if (ENABLE_HEADS_UP && mHeadsUpNotificationView != null) { 2488 mHeadsUpNotificationView.setMargin(mNotificationPanelMarginPx); 2489 mStackScroller.getLocationOnScreen(mStackScrollerPosition); 2490 mHeadsUpVerticalOffset = mStackScrollerPosition[1] - mNaturalBarHeight; 2491 } 2492 2493 updateCarrierLabelVisibility(false); 2494 } 2495 2496 // called by makeStatusbar and also by PhoneStatusBarView 2497 void updateDisplaySize() { 2498 mDisplay.getMetrics(mDisplayMetrics); 2499 mDisplay.getSize(mCurrentDisplaySize); 2500 if (DEBUG_GESTURES) { 2501 mGestureRec.tag("display", 2502 String.format("%dx%d", mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels)); 2503 } 2504 } 2505 2506 private View.OnClickListener mClearButtonListener = new View.OnClickListener() { 2507 public void onClick(View v) { 2508 synchronized (mNotificationData) { 2509 mPostCollapseCleanup = new Runnable() { 2510 @Override 2511 public void run() { 2512 if (DEBUG) { 2513 Log.v(TAG, "running post-collapse cleanup"); 2514 } 2515 try { 2516 mBarService.onClearAllNotifications(mCurrentUserId); 2517 } catch (Exception ex) { } 2518 } 2519 }; 2520 2521 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE); 2522 return; 2523 // TODO: Handle this better with notification stack scroller 2524 } 2525 } 2526 }; 2527 2528 public void startActivityDismissingKeyguard(Intent intent, boolean onlyProvisioned) { 2529 if (onlyProvisioned && !isDeviceProvisioned()) return; 2530 try { 2531 // Dismiss the lock screen when Settings starts. 2532 ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity(); 2533 } catch (RemoteException e) { 2534 } 2535 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); 2536 mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT)); 2537 animateCollapsePanels(); 2538 } 2539 2540 private View.OnClickListener mSettingsButtonListener = new View.OnClickListener() { 2541 public void onClick(View v) { 2542 if (mHasSettingsPanel) { 2543 animateExpandSettingsPanel(); 2544 } else { 2545 startActivityDismissingKeyguard( 2546 new Intent(android.provider.Settings.ACTION_SETTINGS), true); 2547 } 2548 } 2549 }; 2550 2551 private View.OnClickListener mClockClickListener = new View.OnClickListener() { 2552 public void onClick(View v) { 2553 startActivityDismissingKeyguard( 2554 new Intent(Intent.ACTION_QUICK_CLOCK), true); // have fun, everyone 2555 } 2556 }; 2557 2558 private View.OnClickListener mNotificationButtonListener = new View.OnClickListener() { 2559 public void onClick(View v) { 2560 animateExpandNotificationsPanel(); 2561 } 2562 }; 2563 2564 private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 2565 public void onReceive(Context context, Intent intent) { 2566 if (DEBUG) Log.v(TAG, "onReceive: " + intent); 2567 String action = intent.getAction(); 2568 if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) { 2569 int flags = CommandQueue.FLAG_EXCLUDE_NONE; 2570 if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) { 2571 String reason = intent.getStringExtra("reason"); 2572 if (reason != null && reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) { 2573 flags |= CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL; 2574 } 2575 } 2576 animateCollapsePanels(flags); 2577 } 2578 else if (Intent.ACTION_SCREEN_OFF.equals(action)) { 2579 mScreenOn = false; 2580 notifyNavigationBarScreenOn(false); 2581 notifyHeadsUpScreenOn(false); 2582 finishBarAnimations(); 2583 } 2584 else if (Intent.ACTION_SCREEN_ON.equals(action)) { 2585 mScreenOn = true; 2586 // work around problem where mDisplay.getRotation() is not stable while screen is off (bug 7086018) 2587 repositionNavigationBar(); 2588 notifyNavigationBarScreenOn(true); 2589 } 2590 else if (ACTION_DEMO.equals(action)) { 2591 Bundle bundle = intent.getExtras(); 2592 if (bundle != null) { 2593 String command = bundle.getString("command", "").trim().toLowerCase(); 2594 if (command.length() > 0) { 2595 try { 2596 dispatchDemoCommand(command, bundle); 2597 } catch (Throwable t) { 2598 Log.w(TAG, "Error running demo command, intent=" + intent, t); 2599 } 2600 } 2601 } 2602 } 2603 } 2604 }; 2605 2606 // SystemUIService notifies SystemBars of configuration changes, which then calls down here 2607 @Override 2608 protected void onConfigurationChanged(Configuration newConfig) { 2609 super.onConfigurationChanged(newConfig); // calls refreshLayout 2610 2611 if (DEBUG) { 2612 Log.v(TAG, "configuration changed: " + mContext.getResources().getConfiguration()); 2613 } 2614 updateDisplaySize(); // populates mDisplayMetrics 2615 2616 updateResources(); 2617 repositionNavigationBar(); 2618 updateExpandedViewPos(EXPANDED_LEAVE_ALONE); 2619 updateShowSearchHoldoff(); 2620 } 2621 2622 @Override 2623 public void userSwitched(int newUserId) { 2624 if (MULTIUSER_DEBUG) mNotificationPanelDebugText.setText("USER " + newUserId); 2625 animateCollapsePanels(); 2626 updateNotificationIcons(); 2627 resetUserSetupObserver(); 2628 } 2629 2630 private void resetUserSetupObserver() { 2631 mContext.getContentResolver().unregisterContentObserver(mUserSetupObserver); 2632 mUserSetupObserver.onChange(false); 2633 mContext.getContentResolver().registerContentObserver( 2634 Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE), true, 2635 mUserSetupObserver, 2636 mCurrentUserId); 2637 } 2638 2639 private void setHeadsUpVisibility(boolean vis) { 2640 if (!ENABLE_HEADS_UP) return; 2641 if (DEBUG) Log.v(TAG, (vis ? "showing" : "hiding") + " heads up window"); 2642 mHeadsUpNotificationView.setVisibility(vis ? View.VISIBLE : View.GONE); 2643 if (!vis) { 2644 if (DEBUG) Log.d(TAG, "setting heads up entry to null"); 2645 mInterruptingNotificationEntry = null; 2646 } 2647 } 2648 2649 public void animateHeadsUp(boolean animateInto, float frac) { 2650 if (!ENABLE_HEADS_UP || mHeadsUpNotificationView == null) return; 2651 frac = frac / 0.4f; 2652 frac = frac < 1.0f ? frac : 1.0f; 2653 float alpha = 1.0f - frac; 2654 float offset = mHeadsUpVerticalOffset * frac; 2655 offset = animateInto ? offset : 0f; 2656 mHeadsUpNotificationView.setAlpha(alpha); 2657 mHeadsUpNotificationView.setY(offset); 2658 } 2659 2660 public void onHeadsUpDismissed() { 2661 if (mInterruptingNotificationEntry == null) return; 2662 mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP); 2663 if (mHeadsUpNotificationView.isClearable()) { 2664 try { 2665 mBarService.onNotificationClear( 2666 mInterruptingNotificationEntry.notification.getPackageName(), 2667 mInterruptingNotificationEntry.notification.getTag(), 2668 mInterruptingNotificationEntry.notification.getId(), 2669 mInterruptingNotificationEntry.notification.getUserId()); 2670 } catch (android.os.RemoteException ex) { 2671 // oh well 2672 } 2673 } 2674 } 2675 2676 /** 2677 * Reload some of our resources when the configuration changes. 2678 * 2679 * We don't reload everything when the configuration changes -- we probably 2680 * should, but getting that smooth is tough. Someday we'll fix that. In the 2681 * meantime, just update the things that we know change. 2682 */ 2683 void updateResources() { 2684 final Context context = mContext; 2685 final Resources res = context.getResources(); 2686 2687 if (mClearButton instanceof TextView) { 2688 ((TextView)mClearButton).setText(context.getText(R.string.status_bar_clear_all_button)); 2689 } 2690 2691 // Update the QuickSettings container 2692 if (mQS != null) mQS.updateResources(); 2693 2694 loadDimens(); 2695 } 2696 2697 protected void loadDimens() { 2698 final Resources res = mContext.getResources(); 2699 2700 mNaturalBarHeight = res.getDimensionPixelSize( 2701 com.android.internal.R.dimen.status_bar_height); 2702 2703 int newIconSize = res.getDimensionPixelSize( 2704 com.android.internal.R.dimen.status_bar_icon_size); 2705 int newIconHPadding = res.getDimensionPixelSize( 2706 R.dimen.status_bar_icon_padding); 2707 2708 if (newIconHPadding != mIconHPadding || newIconSize != mIconSize) { 2709// Log.d(TAG, "size=" + newIconSize + " padding=" + newIconHPadding); 2710 mIconHPadding = newIconHPadding; 2711 mIconSize = newIconSize; 2712 //reloadAllNotificationIcons(); // reload the tray 2713 } 2714 2715 mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore); 2716 2717 mSelfExpandVelocityPx = res.getDimension(R.dimen.self_expand_velocity); 2718 mSelfCollapseVelocityPx = res.getDimension(R.dimen.self_collapse_velocity); 2719 mFlingExpandMinVelocityPx = res.getDimension(R.dimen.fling_expand_min_velocity); 2720 mFlingCollapseMinVelocityPx = res.getDimension(R.dimen.fling_collapse_min_velocity); 2721 2722 mCollapseMinDisplayFraction = res.getFraction(R.dimen.collapse_min_display_fraction, 1, 1); 2723 mExpandMinDisplayFraction = res.getFraction(R.dimen.expand_min_display_fraction, 1, 1); 2724 2725 mExpandAccelPx = res.getDimension(R.dimen.expand_accel); 2726 mCollapseAccelPx = res.getDimension(R.dimen.collapse_accel); 2727 2728 mFlingGestureMaxXVelocityPx = res.getDimension(R.dimen.fling_gesture_max_x_velocity); 2729 2730 mFlingGestureMaxOutputVelocityPx = res.getDimension(R.dimen.fling_gesture_max_output_velocity); 2731 2732 mNotificationPanelMarginBottomPx 2733 = (int) res.getDimension(R.dimen.notification_panel_margin_bottom); 2734 mNotificationPanelMarginPx 2735 = (int) res.getDimension(R.dimen.notification_panel_margin_left); 2736 mNotificationPanelGravity = res.getInteger(R.integer.notification_panel_layout_gravity); 2737 if (mNotificationPanelGravity <= 0) { 2738 mNotificationPanelGravity = Gravity.START | Gravity.TOP; 2739 } 2740 mSettingsPanelGravity = res.getInteger(R.integer.settings_panel_layout_gravity); 2741 Log.d(TAG, "mSettingsPanelGravity = " + mSettingsPanelGravity); 2742 if (mSettingsPanelGravity <= 0) { 2743 mSettingsPanelGravity = Gravity.END | Gravity.TOP; 2744 } 2745 2746 mCarrierLabelHeight = res.getDimensionPixelSize(R.dimen.carrier_label_height); 2747 mNotificationHeaderHeight = res.getDimensionPixelSize(R.dimen.notification_panel_header_height); 2748 2749 mNotificationPanelMinHeightFrac = res.getFraction(R.dimen.notification_panel_min_height_frac, 1, 1); 2750 if (mNotificationPanelMinHeightFrac < 0f || mNotificationPanelMinHeightFrac > 1f) { 2751 mNotificationPanelMinHeightFrac = 0f; 2752 } 2753 2754 mHeadsUpNotificationDecay = res.getInteger(R.integer.heads_up_notification_decay); 2755 mRowMinHeight = res.getDimensionPixelSize(R.dimen.notification_row_min_height); 2756 mRowMaxHeight = res.getDimensionPixelSize(R.dimen.notification_row_max_height); 2757 2758 mKeyguardMaxNotificationCount = res.getInteger(R.integer.keyguard_max_notification_count); 2759 2760 if (false) Log.v(TAG, "updateResources"); 2761 } 2762 2763 // Visibility reporting 2764 2765 @Override 2766 protected void visibilityChanged(boolean visible) { 2767 if (visible) { 2768 mStackScroller.setChildLocationsChangedListener(mNotificationLocationsChangedListener); 2769 } else { 2770 // Report all notifications as invisible and turn down the 2771 // reporter. 2772 if (!mCurrentlyVisibleNotifications.isEmpty()) { 2773 logNotificationVisibilityChanges( 2774 Collections.<String>emptyList(), mCurrentlyVisibleNotifications); 2775 mCurrentlyVisibleNotifications.clear(); 2776 } 2777 mHandler.removeCallbacks(mVisibilityReporter); 2778 mStackScroller.setChildLocationsChangedListener(null); 2779 } 2780 super.visibilityChanged(visible); 2781 } 2782 2783 private void logNotificationVisibilityChanges( 2784 Collection<String> newlyVisible, Collection<String> noLongerVisible) { 2785 if (newlyVisible.isEmpty() && noLongerVisible.isEmpty()) { 2786 return; 2787 } 2788 2789 String[] newlyVisibleAr = newlyVisible.toArray(new String[newlyVisible.size()]); 2790 String[] noLongerVisibleAr = noLongerVisible.toArray(new String[noLongerVisible.size()]); 2791 try { 2792 mBarService.onNotificationVisibilityChanged(newlyVisibleAr, noLongerVisibleAr); 2793 } catch (RemoteException e) { 2794 // Ignore. 2795 } 2796 } 2797 2798 // 2799 // tracing 2800 // 2801 2802 void postStartTracing() { 2803 mHandler.postDelayed(mStartTracing, 3000); 2804 } 2805 2806 void vibrate() { 2807 android.os.Vibrator vib = (android.os.Vibrator)mContext.getSystemService( 2808 Context.VIBRATOR_SERVICE); 2809 vib.vibrate(250, AudioManager.STREAM_SYSTEM); 2810 } 2811 2812 Runnable mStartTracing = new Runnable() { 2813 public void run() { 2814 vibrate(); 2815 SystemClock.sleep(250); 2816 Log.d(TAG, "startTracing"); 2817 android.os.Debug.startMethodTracing("/data/statusbar-traces/trace"); 2818 mHandler.postDelayed(mStopTracing, 10000); 2819 } 2820 }; 2821 2822 Runnable mStopTracing = new Runnable() { 2823 public void run() { 2824 android.os.Debug.stopMethodTracing(); 2825 Log.d(TAG, "stopTracing"); 2826 vibrate(); 2827 } 2828 }; 2829 2830 @Override 2831 protected void haltTicker() { 2832 mTicker.halt(); 2833 } 2834 2835 @Override 2836 protected boolean shouldDisableNavbarGestures() { 2837 return !isDeviceProvisioned() 2838 || mExpandedVisible 2839 || (mDisabled & StatusBarManager.DISABLE_SEARCH) != 0; 2840 } 2841 2842 public void startSettingsActivity(String action) { 2843 if (mQS != null) { 2844 mQS.startSettingsActivity(action); 2845 } 2846 } 2847 2848 private static class FastColorDrawable extends Drawable { 2849 private final int mColor; 2850 2851 public FastColorDrawable(int color) { 2852 mColor = 0xff000000 | color; 2853 } 2854 2855 @Override 2856 public void draw(Canvas canvas) { 2857 canvas.drawColor(mColor, PorterDuff.Mode.SRC); 2858 } 2859 2860 @Override 2861 public void setAlpha(int alpha) { 2862 } 2863 2864 @Override 2865 public void setColorFilter(ColorFilter cf) { 2866 } 2867 2868 @Override 2869 public int getOpacity() { 2870 return PixelFormat.OPAQUE; 2871 } 2872 2873 @Override 2874 public void setBounds(int left, int top, int right, int bottom) { 2875 } 2876 2877 @Override 2878 public void setBounds(Rect bounds) { 2879 } 2880 } 2881 2882 @Override 2883 public void destroy() { 2884 super.destroy(); 2885 if (mStatusBarWindow != null) { 2886 mWindowManager.removeViewImmediate(mStatusBarWindow); 2887 mStatusBarWindow = null; 2888 } 2889 if (mNavigationBarView != null) { 2890 mWindowManager.removeViewImmediate(mNavigationBarView); 2891 mNavigationBarView = null; 2892 } 2893 mContext.unregisterReceiver(mBroadcastReceiver); 2894 } 2895 2896 private boolean mDemoModeAllowed; 2897 private boolean mDemoMode; 2898 private DemoStatusIcons mDemoStatusIcons; 2899 2900 @Override 2901 public void dispatchDemoCommand(String command, Bundle args) { 2902 if (!mDemoModeAllowed) { 2903 mDemoModeAllowed = Settings.Global.getInt(mContext.getContentResolver(), 2904 "sysui_demo_allowed", 0) != 0; 2905 } 2906 if (!mDemoModeAllowed) return; 2907 if (command.equals(COMMAND_ENTER)) { 2908 mDemoMode = true; 2909 } else if (command.equals(COMMAND_EXIT)) { 2910 mDemoMode = false; 2911 checkBarModes(); 2912 } else if (!mDemoMode) { 2913 // automatically enter demo mode on first demo command 2914 dispatchDemoCommand(COMMAND_ENTER, new Bundle()); 2915 } 2916 boolean modeChange = command.equals(COMMAND_ENTER) || command.equals(COMMAND_EXIT); 2917 if (modeChange || command.equals(COMMAND_CLOCK)) { 2918 dispatchDemoCommandToView(command, args, R.id.clock); 2919 } 2920 if (modeChange || command.equals(COMMAND_BATTERY)) { 2921 dispatchDemoCommandToView(command, args, R.id.battery); 2922 } 2923 if (modeChange || command.equals(COMMAND_STATUS)) { 2924 if (mDemoStatusIcons == null) { 2925 mDemoStatusIcons = new DemoStatusIcons(mStatusIcons, mIconSize); 2926 } 2927 mDemoStatusIcons.dispatchDemoCommand(command, args); 2928 } 2929 if (mNetworkController != null && (modeChange || command.equals(COMMAND_NETWORK))) { 2930 mNetworkController.dispatchDemoCommand(command, args); 2931 } 2932 if (modeChange || command.equals(COMMAND_NOTIFICATIONS)) { 2933 View notifications = mStatusBarView == null ? null 2934 : mStatusBarView.findViewById(R.id.notification_icon_area); 2935 if (notifications != null) { 2936 String visible = args.getString("visible"); 2937 int vis = mDemoMode && "false".equals(visible) ? View.INVISIBLE : View.VISIBLE; 2938 notifications.setVisibility(vis); 2939 } 2940 } 2941 if (command.equals(COMMAND_BARS)) { 2942 String mode = args.getString("mode"); 2943 int barMode = "opaque".equals(mode) ? MODE_OPAQUE : 2944 "translucent".equals(mode) ? MODE_TRANSLUCENT : 2945 "semi-transparent".equals(mode) ? MODE_SEMI_TRANSPARENT : 2946 -1; 2947 if (barMode != -1) { 2948 boolean animate = true; 2949 if (mStatusBarView != null) { 2950 mStatusBarView.getBarTransitions().transitionTo(barMode, animate); 2951 } 2952 if (mNavigationBarView != null) { 2953 mNavigationBarView.getBarTransitions().transitionTo(barMode, animate); 2954 } 2955 } 2956 } 2957 } 2958 2959 private void dispatchDemoCommandToView(String command, Bundle args, int id) { 2960 if (mStatusBarView == null) return; 2961 View v = mStatusBarView.findViewById(id); 2962 if (v instanceof DemoMode) { 2963 ((DemoMode)v).dispatchDemoCommand(command, args); 2964 } 2965 } 2966 2967 public boolean isOnKeyguard() { 2968 return mOnKeyguard; 2969 } 2970 2971 public void showKeyguard() { 2972 mOnKeyguard = true; 2973 instantExpandNotificationsPanel(); 2974 if (isFlippedToSettings()) { 2975 flipToNotifications(); 2976 } 2977 mKeyguardStatusView.setVisibility(View.VISIBLE); 2978 mNotificationPanelHeader.setVisibility(View.GONE); 2979 2980 mKeyguardFlipper.setVisibility(View.VISIBLE); 2981 mSettingsContainer.setKeyguardShowing(true); 2982 updateRowStates(); 2983 } 2984 2985 public void hideKeyguard() { 2986 mOnKeyguard = false; 2987 mKeyguardStatusView.setVisibility(View.GONE); 2988 mNotificationPanelHeader.setVisibility(View.VISIBLE); 2989 2990 mKeyguardFlipper.setVisibility(View.GONE); 2991 mSettingsContainer.setKeyguardShowing(false); 2992 updateRowStates(); 2993 instantCollapseNotificationPanel(); 2994 } 2995 2996 public void userActivity() { 2997 if (mOnKeyguard) { 2998 mKeyguardViewMediatorCallback.userActivity(); 2999 } 3000 } 3001 3002 public boolean onMenuPressed() { 3003 return mOnKeyguard && mStatusBarKeyguardViewManager.onMenuPressed(); 3004 } 3005 3006 public boolean onBackPressed() { 3007 if (mOnKeyguard) { 3008 return mStatusBarKeyguardViewManager.onBackPressed(); 3009 } else { 3010 animateCollapsePanels(); 3011 return true; 3012 } 3013 } 3014 3015 private void showBouncer() { 3016 if (mOnKeyguard) { 3017 mStatusBarKeyguardViewManager.dismiss(); 3018 } 3019 } 3020 3021 private void instantExpandNotificationsPanel() { 3022 mExpandedVisible = true; 3023 mNotificationPanel.setExpandedFraction(1); 3024 } 3025 3026 private void instantCollapseNotificationPanel() { 3027 mNotificationPanel.setExpandedFraction(0); 3028 } 3029 3030 @Override 3031 public void onActivated(View view) { 3032 userActivity(); 3033 super.onActivated(view); 3034 } 3035 3036 @Override 3037 protected int getMaxKeyguardNotifications() { 3038 return mKeyguardMaxNotificationCount; 3039 } 3040 3041 /** 3042 * @return a ViewGroup that spans the entire panel which contains the quick settings 3043 */ 3044 public ViewGroup getQuickSettingsOverlayParent() { 3045 if (mHasSettingsPanel) { 3046 if (mHasFlipSettings) { 3047 return mNotificationPanel; 3048 } else { 3049 return mSettingsPanel; 3050 } 3051 } else { 3052 return null; 3053 } 3054 } 3055 3056 public static boolean inBounds(View view, MotionEvent event, boolean orAbove) { 3057 final int[] location = new int[2]; 3058 view.getLocationInWindow(location); 3059 final int rx = (int) event.getRawX(); 3060 final int ry = (int) event.getRawY(); 3061 return rx >= location[0] && rx <= location[0] + view.getMeasuredWidth() 3062 && (orAbove || ry >= location[1]) && ry <= location[1] + view.getMeasuredHeight(); 3063 } 3064 3065 private final class FlipperButton { 3066 private final View mHolder; 3067 3068 private ImageView mSettingsButton, mNotificationButton; 3069 private Animator mSettingsButtonAnim, mNotificationButtonAnim; 3070 3071 public FlipperButton(View holder) { 3072 mHolder = holder; 3073 mSettingsButton = (ImageView) holder.findViewById(R.id.settings_button); 3074 if (mSettingsButton != null) { 3075 mSettingsButton.setOnClickListener(mSettingsButtonListener); 3076 if (mHasSettingsPanel) { 3077 // the settings panel is hiding behind this button 3078 mSettingsButton.setImageResource(R.drawable.ic_notify_quicksettings); 3079 mSettingsButton.setVisibility(View.VISIBLE); 3080 } else { 3081 // no settings panel, go straight to settings 3082 mSettingsButton.setVisibility(View.VISIBLE); 3083 mSettingsButton.setImageResource(R.drawable.ic_notify_settings); 3084 } 3085 } 3086 if (mHasFlipSettings) { 3087 mNotificationButton = (ImageView) holder.findViewById(R.id.notification_button); 3088 if (mNotificationButton != null) { 3089 mNotificationButton.setOnClickListener(mNotificationButtonListener); 3090 } 3091 } 3092 } 3093 3094 public boolean inHolderBounds(MotionEvent event) { 3095 return inBounds(mHolder, event, false); 3096 } 3097 3098 public void provisionCheck(boolean provisioned) { 3099 if (mSettingsButton != null) { 3100 mSettingsButton.setEnabled(provisioned); 3101 } 3102 } 3103 3104 public void userSetup(boolean userSetup) { 3105 if (mSettingsButton != null && mHasFlipSettings) { 3106 mSettingsButton.setVisibility(userSetup ? View.VISIBLE : View.INVISIBLE); 3107 } 3108 } 3109 3110 public void reset() { 3111 cancel(); 3112 mSettingsButton.setVisibility(View.VISIBLE); 3113 mNotificationButton.setVisibility(View.GONE); 3114 } 3115 3116 public void refreshLayout() { 3117 if (mSettingsButton != null) { 3118 // Force asset reloading 3119 mSettingsButton.setImageDrawable(null); 3120 mSettingsButton.setImageResource(R.drawable.ic_notify_quicksettings); 3121 } 3122 3123 if (mNotificationButton != null) { 3124 // Force asset reloading 3125 mNotificationButton.setImageDrawable(null); 3126 mNotificationButton.setImageResource(R.drawable.ic_notifications); 3127 } 3128 } 3129 3130 public void flipToSettings() { 3131 mSettingsButtonAnim = start( 3132 setVisibilityWhenDone( 3133 ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 0f) 3134 .setDuration(FLIP_DURATION_OUT), 3135 mStackScroller, View.INVISIBLE)); 3136 mNotificationButton.setVisibility(View.VISIBLE); 3137 mNotificationButtonAnim = start( 3138 startDelay(FLIP_DURATION_OUT, 3139 ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 1f) 3140 .setDuration(FLIP_DURATION_IN))); 3141 } 3142 3143 public void flipToNotifications() { 3144 mNotificationButtonAnim = start( 3145 setVisibilityWhenDone( 3146 ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 0f) 3147 .setDuration(FLIP_DURATION_OUT), 3148 mNotificationButton, View.INVISIBLE)); 3149 3150 mSettingsButton.setVisibility(View.VISIBLE); 3151 mSettingsButtonAnim = start( 3152 startDelay(FLIP_DURATION_OUT, 3153 ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 1f) 3154 .setDuration(FLIP_DURATION_IN))); 3155 } 3156 3157 public void cancel() { 3158 if (mSettingsButtonAnim != null) mSettingsButtonAnim.cancel(); 3159 if (mNotificationButtonAnim != null) mNotificationButtonAnim.cancel(); 3160 } 3161 3162 public void setVisibility(int vis) { 3163 mHolder.setVisibility(vis); 3164 } 3165 } 3166} 3167