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