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