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