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