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