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