PhoneStatusBar.java revision 66ac133971f4e2f80cd7cfff89cc6f8a3f7e899f
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.systemui.statusbar.phone; 18 19 20import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT; 21import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN; 22import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN; 23import static android.app.StatusBarManager.WINDOW_STATE_SHOWING; 24import static android.app.StatusBarManager.windowStateToString; 25import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT; 26import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT; 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; 31import static com.android.systemui.statusbar.phone.BarTransitions.MODE_WARNING; 32 33import android.animation.Animator; 34import android.animation.AnimatorListenerAdapter; 35import android.annotation.NonNull; 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.ComponentCallbacks2; 44import android.content.Context; 45import android.content.Intent; 46import android.content.IntentFilter; 47import android.content.res.Configuration; 48import android.content.res.Resources; 49import android.database.ContentObserver; 50import android.graphics.Bitmap; 51import android.graphics.Canvas; 52import android.graphics.ColorFilter; 53import android.graphics.PixelFormat; 54import android.graphics.Point; 55import android.graphics.PointF; 56import android.graphics.PorterDuff; 57import android.graphics.PorterDuffXfermode; 58import android.graphics.Rect; 59import android.graphics.drawable.ColorDrawable; 60import android.graphics.drawable.Drawable; 61import android.inputmethodservice.InputMethodService; 62import android.media.AudioAttributes; 63import android.media.MediaMetadata; 64import android.media.session.MediaController; 65import android.media.session.MediaSession; 66import android.media.session.MediaSessionManager; 67import android.media.session.PlaybackState; 68import android.os.AsyncTask; 69import android.os.Bundle; 70import android.os.Handler; 71import android.os.HandlerThread; 72import android.os.IBinder; 73import android.os.Message; 74import android.os.PowerManager; 75import android.os.Process; 76import android.os.RemoteException; 77import android.os.SystemClock; 78import android.os.UserHandle; 79import android.os.UserManager; 80import android.provider.Settings; 81import android.service.notification.NotificationListenerService; 82import android.service.notification.NotificationListenerService.RankingMap; 83import android.service.notification.StatusBarNotification; 84import android.util.ArraySet; 85import android.util.DisplayMetrics; 86import android.util.EventLog; 87import android.util.Log; 88import android.view.Display; 89import android.view.Gravity; 90import android.view.KeyEvent; 91import android.view.LayoutInflater; 92import android.view.MotionEvent; 93import android.view.VelocityTracker; 94import android.view.View; 95import android.view.ViewGroup; 96import android.view.ViewGroup.LayoutParams; 97import android.view.ViewStub; 98import android.view.WindowManager; 99import android.view.WindowManagerGlobal; 100import android.view.accessibility.AccessibilityEvent; 101import android.view.animation.AccelerateDecelerateInterpolator; 102import android.view.animation.AccelerateInterpolator; 103import android.view.animation.AnimationUtils; 104import android.view.animation.Interpolator; 105import android.view.animation.LinearInterpolator; 106import android.view.animation.PathInterpolator; 107import android.widget.ImageView; 108import android.widget.TextView; 109 110import com.android.internal.statusbar.StatusBarIcon; 111import com.android.keyguard.KeyguardHostView.OnDismissAction; 112import com.android.keyguard.ViewMediatorCallback; 113import com.android.systemui.BatteryMeterView; 114import com.android.systemui.DemoMode; 115import com.android.systemui.EventLogConstants; 116import com.android.systemui.EventLogTags; 117import com.android.systemui.FontSizeUtils; 118import com.android.systemui.R; 119import com.android.systemui.doze.DozeHost; 120import com.android.systemui.doze.DozeLog; 121import com.android.systemui.keyguard.KeyguardViewMediator; 122import com.android.systemui.qs.QSPanel; 123import com.android.systemui.recents.ScreenPinningRequest; 124import com.android.systemui.statusbar.ActivatableNotificationView; 125import com.android.systemui.statusbar.BackDropView; 126import com.android.systemui.statusbar.BaseStatusBar; 127import com.android.systemui.statusbar.CommandQueue; 128import com.android.systemui.statusbar.DismissView; 129import com.android.systemui.statusbar.DragDownHelper; 130import com.android.systemui.statusbar.EmptyShadeView; 131import com.android.systemui.statusbar.ExpandableNotificationRow; 132import com.android.systemui.statusbar.GestureRecorder; 133import com.android.systemui.statusbar.KeyguardIndicationController; 134import com.android.systemui.statusbar.NotificationData; 135import com.android.systemui.statusbar.NotificationData.Entry; 136import com.android.systemui.statusbar.NotificationOverflowContainer; 137import com.android.systemui.statusbar.ScrimView; 138import com.android.systemui.statusbar.SignalClusterView; 139import com.android.systemui.statusbar.SpeedBumpView; 140import com.android.systemui.statusbar.StatusBarIconView; 141import com.android.systemui.statusbar.StatusBarState; 142import com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChangedListener; 143import com.android.systemui.statusbar.policy.AccessibilityController; 144import com.android.systemui.statusbar.policy.BatteryController; 145import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback; 146import com.android.systemui.statusbar.policy.BluetoothControllerImpl; 147import com.android.systemui.statusbar.policy.BrightnessMirrorController; 148import com.android.systemui.statusbar.policy.CastControllerImpl; 149import com.android.systemui.statusbar.policy.FlashlightController; 150import com.android.systemui.statusbar.policy.HeadsUpNotificationView; 151import com.android.systemui.statusbar.policy.HotspotControllerImpl; 152import com.android.systemui.statusbar.policy.KeyButtonView; 153import com.android.systemui.statusbar.policy.KeyguardMonitor; 154import com.android.systemui.statusbar.policy.KeyguardUserSwitcher; 155import com.android.systemui.statusbar.policy.LocationControllerImpl; 156import com.android.systemui.statusbar.policy.NetworkControllerImpl; 157import com.android.systemui.statusbar.policy.NextAlarmController; 158import com.android.systemui.statusbar.policy.PreviewInflater; 159import com.android.systemui.statusbar.policy.RotationLockControllerImpl; 160import com.android.systemui.statusbar.policy.SecurityControllerImpl; 161import com.android.systemui.statusbar.policy.UserInfoController; 162import com.android.systemui.statusbar.policy.UserSwitcherController; 163import com.android.systemui.statusbar.policy.ZenModeController; 164import com.android.systemui.statusbar.stack.NotificationStackScrollLayout; 165import com.android.systemui.statusbar.stack.NotificationStackScrollLayout.OnChildLocationsChangedListener; 166import com.android.systemui.statusbar.stack.StackScrollState.ViewState; 167import com.android.systemui.volume.VolumeComponent; 168 169import java.io.FileDescriptor; 170import java.io.PrintWriter; 171import java.util.ArrayList; 172import java.util.Collection; 173import java.util.Collections; 174import java.util.List; 175import java.util.Map; 176 177public class PhoneStatusBar extends BaseStatusBar implements DemoMode, 178 DragDownHelper.DragDownCallback, ActivityStarter, OnUnlockMethodChangedListener { 179 static final String TAG = "PhoneStatusBar"; 180 public static final boolean DEBUG = BaseStatusBar.DEBUG; 181 public static final boolean SPEW = false; 182 public static final boolean DUMPTRUCK = true; // extra dumpsys info 183 public static final boolean DEBUG_GESTURES = false; 184 public static final boolean DEBUG_MEDIA = false; 185 public static final boolean DEBUG_MEDIA_FAKE_ARTWORK = false; 186 187 public static final boolean DEBUG_WINDOW_STATE = false; 188 189 // additional instrumentation for testing purposes; intended to be left on during development 190 public static final boolean CHATTY = DEBUG; 191 192 public static final boolean SHOW_LOCKSCREEN_MEDIA_ARTWORK = true; 193 194 private static final int MSG_OPEN_NOTIFICATION_PANEL = 1000; 195 private static final int MSG_CLOSE_PANELS = 1001; 196 private static final int MSG_OPEN_SETTINGS_PANEL = 1002; 197 private static final int MSG_LAUNCH_TRANSITION_TIMEOUT = 1003; 198 // 1020-1040 reserved for BaseStatusBar 199 200 // Time after we abort the launch transition. 201 private static final long LAUNCH_TRANSITION_TIMEOUT_MS = 5000; 202 203 private static final boolean CLOSE_PANEL_WHEN_EMPTIED = true; 204 205 private static final int STATUS_OR_NAV_TRANSIENT = 206 View.STATUS_BAR_TRANSIENT | View.NAVIGATION_BAR_TRANSIENT; 207 private static final long AUTOHIDE_TIMEOUT_MS = 3000; 208 209 /** The minimum delay in ms between reports of notification visibility. */ 210 private static final int VISIBILITY_REPORT_MIN_DELAY_MS = 500; 211 212 /** 213 * The delay to reset the hint text when the hint animation is finished running. 214 */ 215 private static final int HINT_RESET_DELAY_MS = 1200; 216 217 private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder() 218 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) 219 .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION) 220 .build(); 221 222 public static final int FADE_KEYGUARD_START_DELAY = 100; 223 public static final int FADE_KEYGUARD_DURATION = 300; 224 225 /** Allow some time inbetween the long press for back and recents. */ 226 private static final int LOCK_TO_APP_GESTURE_TOLERENCE = 200; 227 228 PhoneStatusBarPolicy mIconPolicy; 229 230 // These are no longer handled by the policy, because we need custom strategies for them 231 BluetoothControllerImpl mBluetoothController; 232 SecurityControllerImpl mSecurityController; 233 BatteryController mBatteryController; 234 LocationControllerImpl mLocationController; 235 NetworkControllerImpl mNetworkController; 236 HotspotControllerImpl mHotspotController; 237 RotationLockControllerImpl mRotationLockController; 238 UserInfoController mUserInfoController; 239 ZenModeController mZenModeController; 240 CastControllerImpl mCastController; 241 VolumeComponent mVolumeComponent; 242 KeyguardUserSwitcher mKeyguardUserSwitcher; 243 FlashlightController mFlashlightController; 244 UserSwitcherController mUserSwitcherController; 245 NextAlarmController mNextAlarmController; 246 KeyguardMonitor mKeyguardMonitor; 247 BrightnessMirrorController mBrightnessMirrorController; 248 AccessibilityController mAccessibilityController; 249 250 int mNaturalBarHeight = -1; 251 252 Display mDisplay; 253 Point mCurrentDisplaySize = new Point(); 254 255 StatusBarWindowView mStatusBarWindow; 256 PhoneStatusBarView mStatusBarView; 257 private int mStatusBarWindowState = WINDOW_STATE_SHOWING; 258 private StatusBarWindowManager mStatusBarWindowManager; 259 private UnlockMethodCache mUnlockMethodCache; 260 private DozeServiceHost mDozeServiceHost; 261 private boolean mScreenOnComingFromTouch; 262 private PointF mScreenOnTouchLocation; 263 264 int mPixelFormat; 265 Object mQueueLock = new Object(); 266 267 StatusBarIconController mIconController; 268 269 // expanded notifications 270 NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window 271 View mExpandedContents; 272 TextView mNotificationPanelDebugText; 273 274 // settings 275 private QSPanel mQSPanel; 276 277 // top bar 278 StatusBarHeaderView mHeader; 279 KeyguardStatusBarView mKeyguardStatusBar; 280 View mKeyguardStatusView; 281 KeyguardBottomAreaView mKeyguardBottomArea; 282 boolean mLeaveOpenOnKeyguardHide; 283 KeyguardIndicationController mKeyguardIndicationController; 284 285 private boolean mKeyguardFadingAway; 286 private long mKeyguardFadingAwayDelay; 287 private long mKeyguardFadingAwayDuration; 288 289 int mKeyguardMaxNotificationCount; 290 291 boolean mExpandedVisible; 292 293 private int mNavigationBarWindowState = WINDOW_STATE_SHOWING; 294 295 // the tracker view 296 int mTrackingPosition; // the position of the top of the tracking view. 297 298 // Tracking finger for opening/closing. 299 int mEdgeBorder; // corresponds to R.dimen.status_bar_edge_ignore 300 boolean mTracking; 301 VelocityTracker mVelocityTracker; 302 303 int[] mAbsPos = new int[2]; 304 ArrayList<Runnable> mPostCollapseRunnables = new ArrayList<>(); 305 306 // for disabling the status bar 307 int mDisabled = 0; 308 309 // tracking calls to View.setSystemUiVisibility() 310 int mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE; 311 312 DisplayMetrics mDisplayMetrics = new DisplayMetrics(); 313 314 // XXX: gesture research 315 private final GestureRecorder mGestureRec = DEBUG_GESTURES 316 ? new GestureRecorder("/sdcard/statusbar_gestures.dat") 317 : null; 318 319 private ScreenPinningRequest mScreenPinningRequest; 320 321 private int mNavigationIconHints = 0; 322 private HandlerThread mHandlerThread; 323 324 // ensure quick settings is disabled until the current user makes it through the setup wizard 325 private boolean mUserSetup = false; 326 private ContentObserver mUserSetupObserver = new ContentObserver(new Handler()) { 327 @Override 328 public void onChange(boolean selfChange) { 329 final boolean userSetup = 0 != Settings.Secure.getIntForUser( 330 mContext.getContentResolver(), 331 Settings.Secure.USER_SETUP_COMPLETE, 332 0 /*default */, 333 mCurrentUserId); 334 if (MULTIUSER_DEBUG) Log.d(TAG, String.format("User setup changed: " + 335 "selfChange=%s userSetup=%s mUserSetup=%s", 336 selfChange, userSetup, mUserSetup)); 337 338 if (userSetup != mUserSetup) { 339 mUserSetup = userSetup; 340 if (!mUserSetup && mStatusBarView != null) 341 animateCollapseQuickSettings(); 342 } 343 } 344 }; 345 346 final private ContentObserver mHeadsUpObserver = new ContentObserver(mHandler) { 347 @Override 348 public void onChange(boolean selfChange) { 349 boolean wasUsing = mUseHeadsUp; 350 mUseHeadsUp = ENABLE_HEADS_UP && !mDisableNotificationAlerts 351 && Settings.Global.HEADS_UP_OFF != Settings.Global.getInt( 352 mContext.getContentResolver(), Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED, 353 Settings.Global.HEADS_UP_OFF); 354 mHeadsUpTicker = mUseHeadsUp && 0 != Settings.Global.getInt( 355 mContext.getContentResolver(), SETTING_HEADS_UP_TICKER, 0); 356 Log.d(TAG, "heads up is " + (mUseHeadsUp ? "enabled" : "disabled")); 357 if (wasUsing != mUseHeadsUp) { 358 if (!mUseHeadsUp) { 359 Log.d(TAG, "dismissing any existing heads up notification on disable event"); 360 setHeadsUpVisibility(false); 361 mHeadsUpNotificationView.release(); 362 removeHeadsUpView(); 363 } else { 364 addHeadsUpView(); 365 } 366 } 367 } 368 }; 369 370 private int mInteractingWindows; 371 private boolean mAutohideSuspended; 372 private int mStatusBarMode; 373 private int mNavigationBarMode; 374 375 private ViewMediatorCallback mKeyguardViewMediatorCallback; 376 private ScrimController mScrimController; 377 private DozeScrimController mDozeScrimController; 378 379 private final Runnable mAutohide = new Runnable() { 380 @Override 381 public void run() { 382 int requested = mSystemUiVisibility & ~STATUS_OR_NAV_TRANSIENT; 383 if (mSystemUiVisibility != requested) { 384 notifyUiVisibilityChanged(requested); 385 } 386 }}; 387 388 private boolean mWaitingForKeyguardExit; 389 private boolean mDozing; 390 private boolean mScrimSrcModeEnabled; 391 392 private Interpolator mLinearInterpolator = new LinearInterpolator(); 393 private Interpolator mBackdropInterpolator = new AccelerateDecelerateInterpolator(); 394 public static final Interpolator ALPHA_IN = new PathInterpolator(0.4f, 0f, 1f, 1f); 395 public static final Interpolator ALPHA_OUT = new PathInterpolator(0f, 0f, 0.8f, 1f); 396 397 private BackDropView mBackdrop; 398 private ImageView mBackdropFront, mBackdropBack; 399 private PorterDuffXfermode mSrcXferMode = new PorterDuffXfermode(PorterDuff.Mode.SRC); 400 private PorterDuffXfermode mSrcOverXferMode = new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER); 401 402 private MediaSessionManager mMediaSessionManager; 403 private MediaController mMediaController; 404 private String mMediaNotificationKey; 405 private MediaMetadata mMediaMetadata; 406 private MediaController.Callback mMediaListener 407 = new MediaController.Callback() { 408 @Override 409 public void onPlaybackStateChanged(PlaybackState state) { 410 super.onPlaybackStateChanged(state); 411 if (DEBUG_MEDIA) Log.v(TAG, "DEBUG_MEDIA: onPlaybackStateChanged: " + state); 412 } 413 414 @Override 415 public void onMetadataChanged(MediaMetadata metadata) { 416 super.onMetadataChanged(metadata); 417 if (DEBUG_MEDIA) Log.v(TAG, "DEBUG_MEDIA: onMetadataChanged: " + metadata); 418 mMediaMetadata = metadata; 419 updateMediaMetaData(true); 420 } 421 }; 422 423 private final OnChildLocationsChangedListener mOnChildLocationsChangedListener = 424 new OnChildLocationsChangedListener() { 425 @Override 426 public void onChildLocationsChanged(NotificationStackScrollLayout stackScrollLayout) { 427 userActivity(); 428 } 429 }; 430 431 private int mDisabledUnmodified; 432 433 /** Keys of notifications currently visible to the user. */ 434 private final ArraySet<String> mCurrentlyVisibleNotifications = new ArraySet<String>(); 435 private long mLastVisibilityReportUptimeMs; 436 437 private final ShadeUpdates mShadeUpdates = new ShadeUpdates(); 438 439 private int mDrawCount; 440 private Runnable mLaunchTransitionEndRunnable; 441 private boolean mLaunchTransitionFadingAway; 442 private ExpandableNotificationRow mDraggedDownRow; 443 444 // Fingerprint (as computed by getLoggingFingerprint() of the last logged state. 445 private int mLastLoggedStateFingerprint; 446 447 private static final int VISIBLE_LOCATIONS = ViewState.LOCATION_FIRST_CARD 448 | ViewState.LOCATION_TOP_STACK_PEEKING 449 | ViewState.LOCATION_MAIN_AREA 450 | ViewState.LOCATION_BOTTOM_STACK_PEEKING; 451 452 private final OnChildLocationsChangedListener mNotificationLocationsChangedListener = 453 new OnChildLocationsChangedListener() { 454 @Override 455 public void onChildLocationsChanged( 456 NotificationStackScrollLayout stackScrollLayout) { 457 if (mHandler.hasCallbacks(mVisibilityReporter)) { 458 // Visibilities will be reported when the existing 459 // callback is executed. 460 return; 461 } 462 // Calculate when we're allowed to run the visibility 463 // reporter. Note that this timestamp might already have 464 // passed. That's OK, the callback will just be executed 465 // ASAP. 466 long nextReportUptimeMs = 467 mLastVisibilityReportUptimeMs + VISIBILITY_REPORT_MIN_DELAY_MS; 468 mHandler.postAtTime(mVisibilityReporter, nextReportUptimeMs); 469 } 470 }; 471 472 // Tracks notifications currently visible in mNotificationStackScroller and 473 // emits visibility events via NoMan on changes. 474 private final Runnable mVisibilityReporter = new Runnable() { 475 private final ArrayList<String> mTmpNewlyVisibleNotifications = new ArrayList<String>(); 476 private final ArrayList<String> mTmpCurrentlyVisibleNotifications = new ArrayList<String>(); 477 478 @Override 479 public void run() { 480 mLastVisibilityReportUptimeMs = SystemClock.uptimeMillis(); 481 482 // 1. Loop over mNotificationData entries: 483 // A. Keep list of visible notifications. 484 // B. Keep list of previously hidden, now visible notifications. 485 // 2. Compute no-longer visible notifications by removing currently 486 // visible notifications from the set of previously visible 487 // notifications. 488 // 3. Report newly visible and no-longer visible notifications. 489 // 4. Keep currently visible notifications for next report. 490 ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications(); 491 int N = activeNotifications.size(); 492 for (int i = 0; i < N; i++) { 493 Entry entry = activeNotifications.get(i); 494 String key = entry.notification.getKey(); 495 boolean previouslyVisible = mCurrentlyVisibleNotifications.contains(key); 496 boolean currentlyVisible = 497 (mStackScroller.getChildLocation(entry.row) & VISIBLE_LOCATIONS) != 0; 498 if (currentlyVisible) { 499 // Build new set of visible notifications. 500 mTmpCurrentlyVisibleNotifications.add(key); 501 } 502 if (!previouslyVisible && currentlyVisible) { 503 mTmpNewlyVisibleNotifications.add(key); 504 } 505 } 506 ArraySet<String> noLongerVisibleNotifications = mCurrentlyVisibleNotifications; 507 noLongerVisibleNotifications.removeAll(mTmpCurrentlyVisibleNotifications); 508 509 logNotificationVisibilityChanges( 510 mTmpNewlyVisibleNotifications, noLongerVisibleNotifications); 511 512 mCurrentlyVisibleNotifications.clear(); 513 mCurrentlyVisibleNotifications.addAll(mTmpCurrentlyVisibleNotifications); 514 515 mTmpNewlyVisibleNotifications.clear(); 516 mTmpCurrentlyVisibleNotifications.clear(); 517 } 518 }; 519 520 private final View.OnClickListener mOverflowClickListener = new View.OnClickListener() { 521 @Override 522 public void onClick(View v) { 523 goToLockedShade(null); 524 } 525 }; 526 527 @Override 528 public void start() { 529 mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE)) 530 .getDefaultDisplay(); 531 updateDisplaySize(); 532 mScrimSrcModeEnabled = mContext.getResources().getBoolean( 533 R.bool.config_status_bar_scrim_behind_use_src); 534 super.start(); // calls createAndAddWindows() 535 536 mMediaSessionManager 537 = (MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE); 538 // TODO: use MediaSessionManager.SessionListener to hook us up to future updates 539 // in session state 540 541 addNavigationBar(); 542 543 // Lastly, call to the icon policy to install/update all the icons. 544 mIconPolicy = new PhoneStatusBarPolicy(mContext, mCastController, mHotspotController); 545 mSettingsObserver.onChange(false); // set up 546 547 mHeadsUpObserver.onChange(true); // set up 548 if (ENABLE_HEADS_UP) { 549 mContext.getContentResolver().registerContentObserver( 550 Settings.Global.getUriFor(Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED), true, 551 mHeadsUpObserver); 552 mContext.getContentResolver().registerContentObserver( 553 Settings.Global.getUriFor(SETTING_HEADS_UP_TICKER), true, 554 mHeadsUpObserver); 555 } 556 mUnlockMethodCache = UnlockMethodCache.getInstance(mContext); 557 mUnlockMethodCache.addListener(this); 558 startKeyguard(); 559 560 mDozeServiceHost = new DozeServiceHost(); 561 putComponent(DozeHost.class, mDozeServiceHost); 562 putComponent(PhoneStatusBar.class, this); 563 564 setControllerUsers(); 565 566 notifyUserAboutHiddenNotifications(); 567 568 mScreenPinningRequest = new ScreenPinningRequest(mContext); 569 } 570 571 // ================================================================================ 572 // Constructing the view 573 // ================================================================================ 574 protected PhoneStatusBarView makeStatusBarView() { 575 final Context context = mContext; 576 577 Resources res = context.getResources(); 578 579 updateDisplaySize(); // populates mDisplayMetrics 580 updateResources(); 581 582 mStatusBarWindow = (StatusBarWindowView) View.inflate(context, 583 R.layout.super_status_bar, null); 584 mStatusBarWindow.mService = this; 585 mStatusBarWindow.setOnTouchListener(new View.OnTouchListener() { 586 @Override 587 public boolean onTouch(View v, MotionEvent event) { 588 checkUserAutohide(v, event); 589 if (event.getAction() == MotionEvent.ACTION_DOWN) { 590 if (mExpandedVisible) { 591 animateCollapsePanels(); 592 } 593 } 594 return mStatusBarWindow.onTouchEvent(event); 595 }}); 596 597 mStatusBarView = (PhoneStatusBarView) mStatusBarWindow.findViewById(R.id.status_bar); 598 mStatusBarView.setBar(this); 599 600 PanelHolder holder = (PanelHolder) mStatusBarWindow.findViewById(R.id.panel_holder); 601 mStatusBarView.setPanelHolder(holder); 602 603 mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById( 604 R.id.notification_panel); 605 mNotificationPanel.setStatusBar(this); 606 607 if (!ActivityManager.isHighEndGfx()) { 608 mStatusBarWindow.setBackground(null); 609 mNotificationPanel.setBackground(new FastColorDrawable(context.getResources().getColor( 610 R.color.notification_panel_solid_background))); 611 } 612 if (ENABLE_HEADS_UP) { 613 mHeadsUpNotificationView = 614 (HeadsUpNotificationView) View.inflate(context, R.layout.heads_up, null); 615 mHeadsUpNotificationView.setVisibility(View.GONE); 616 mHeadsUpNotificationView.setBar(this); 617 } 618 if (MULTIUSER_DEBUG) { 619 mNotificationPanelDebugText = (TextView) mNotificationPanel.findViewById( 620 R.id.header_debug_info); 621 mNotificationPanelDebugText.setVisibility(View.VISIBLE); 622 } 623 624 updateShowSearchHoldoff(); 625 626 try { 627 boolean showNav = mWindowManagerService.hasNavigationBar(); 628 if (DEBUG) Log.v(TAG, "hasNavigationBar=" + showNav); 629 if (showNav) { 630 mNavigationBarView = 631 (NavigationBarView) View.inflate(context, R.layout.navigation_bar, null); 632 633 mNavigationBarView.setDisabledFlags(mDisabled); 634 mNavigationBarView.setBar(this); 635 mNavigationBarView.setOnVerticalChangedListener( 636 new NavigationBarView.OnVerticalChangedListener() { 637 @Override 638 public void onVerticalChanged(boolean isVertical) { 639 if (mSearchPanelView != null) { 640 mSearchPanelView.setHorizontal(isVertical); 641 } 642 mNotificationPanel.setQsScrimEnabled(!isVertical); 643 } 644 }); 645 mNavigationBarView.setOnTouchListener(new View.OnTouchListener() { 646 @Override 647 public boolean onTouch(View v, MotionEvent event) { 648 checkUserAutohide(v, event); 649 return false; 650 }}); 651 } 652 } catch (RemoteException ex) { 653 // no window manager? good luck with that 654 } 655 656 // figure out which pixel-format to use for the status bar. 657 mPixelFormat = PixelFormat.OPAQUE; 658 659 mStackScroller = (NotificationStackScrollLayout) mStatusBarWindow.findViewById( 660 R.id.notification_stack_scroller); 661 mStackScroller.setLongPressListener(getNotificationLongClicker()); 662 mStackScroller.setPhoneStatusBar(this); 663 664 mKeyguardIconOverflowContainer = 665 (NotificationOverflowContainer) LayoutInflater.from(mContext).inflate( 666 R.layout.status_bar_notification_keyguard_overflow, mStackScroller, false); 667 mKeyguardIconOverflowContainer.setOnActivatedListener(this); 668 mKeyguardIconOverflowContainer.setOnClickListener(mOverflowClickListener); 669 mStackScroller.addView(mKeyguardIconOverflowContainer); 670 671 SpeedBumpView speedBump = (SpeedBumpView) LayoutInflater.from(mContext).inflate( 672 R.layout.status_bar_notification_speed_bump, mStackScroller, false); 673 mStackScroller.setSpeedBumpView(speedBump); 674 mEmptyShadeView = (EmptyShadeView) LayoutInflater.from(mContext).inflate( 675 R.layout.status_bar_no_notifications, mStackScroller, false); 676 mStackScroller.setEmptyShadeView(mEmptyShadeView); 677 mDismissView = (DismissView) LayoutInflater.from(mContext).inflate( 678 R.layout.status_bar_notification_dismiss_all, mStackScroller, false); 679 mDismissView.setOnButtonClickListener(new View.OnClickListener() { 680 @Override 681 public void onClick(View v) { 682 clearAllNotifications(); 683 } 684 }); 685 mStackScroller.setDismissView(mDismissView); 686 mExpandedContents = mStackScroller; 687 688 mBackdrop = (BackDropView) mStatusBarWindow.findViewById(R.id.backdrop); 689 mBackdropFront = (ImageView) mBackdrop.findViewById(R.id.backdrop_front); 690 mBackdropBack = (ImageView) mBackdrop.findViewById(R.id.backdrop_back); 691 692 ScrimView scrimBehind = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_behind); 693 ScrimView scrimInFront = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_in_front); 694 mScrimController = new ScrimController(scrimBehind, scrimInFront, mScrimSrcModeEnabled); 695 mScrimController.setBackDropView(mBackdrop); 696 mStatusBarView.setScrimController(mScrimController); 697 mDozeScrimController = new DozeScrimController(mScrimController, context); 698 699 mHeader = (StatusBarHeaderView) mStatusBarWindow.findViewById(R.id.header); 700 mHeader.setActivityStarter(this); 701 mKeyguardStatusBar = (KeyguardStatusBarView) mStatusBarWindow.findViewById(R.id.keyguard_header); 702 mKeyguardStatusView = mStatusBarWindow.findViewById(R.id.keyguard_status_view); 703 mKeyguardBottomArea = 704 (KeyguardBottomAreaView) mStatusBarWindow.findViewById(R.id.keyguard_bottom_area); 705 mKeyguardBottomArea.setActivityStarter(this); 706 mKeyguardIndicationController = new KeyguardIndicationController(mContext, 707 (KeyguardIndicationTextView) mStatusBarWindow.findViewById( 708 R.id.keyguard_indication_text)); 709 mKeyguardBottomArea.setKeyguardIndicationController(mKeyguardIndicationController); 710 711 mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore); 712 713 // set the inital view visibility 714 setAreThereNotifications(); 715 716 mIconController = new StatusBarIconController( 717 mContext, mStatusBarView, mKeyguardStatusBar, this); 718 719 // Background thread for any controllers that need it. 720 mHandlerThread = new HandlerThread(TAG, Process.THREAD_PRIORITY_BACKGROUND); 721 mHandlerThread.start(); 722 723 // Other icons 724 mLocationController = new LocationControllerImpl(mContext); // will post a notification 725 mBatteryController = new BatteryController(mContext); 726 mBatteryController.addStateChangedCallback(new BatteryStateChangeCallback() { 727 @Override 728 public void onPowerSaveChanged() { 729 mHandler.post(mCheckBarModes); 730 if (mDozeServiceHost != null) { 731 mDozeServiceHost.firePowerSaveChanged(mBatteryController.isPowerSave()); 732 } 733 } 734 @Override 735 public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) { 736 // noop 737 } 738 }); 739 mNetworkController = new NetworkControllerImpl(mContext); 740 mHotspotController = new HotspotControllerImpl(mContext); 741 mBluetoothController = new BluetoothControllerImpl(mContext, mHandlerThread.getLooper()); 742 mSecurityController = new SecurityControllerImpl(mContext); 743 if (mContext.getResources().getBoolean(R.bool.config_showRotationLock)) { 744 mRotationLockController = new RotationLockControllerImpl(mContext); 745 } 746 mUserInfoController = new UserInfoController(mContext); 747 mVolumeComponent = getComponent(VolumeComponent.class); 748 if (mVolumeComponent != null) { 749 mZenModeController = mVolumeComponent.getZenController(); 750 } 751 mCastController = new CastControllerImpl(mContext); 752 final SignalClusterView signalCluster = 753 (SignalClusterView) mStatusBarView.findViewById(R.id.signal_cluster); 754 final SignalClusterView signalClusterKeyguard = 755 (SignalClusterView) mKeyguardStatusBar.findViewById(R.id.signal_cluster); 756 final SignalClusterView signalClusterQs = 757 (SignalClusterView) mHeader.findViewById(R.id.signal_cluster); 758 mNetworkController.addSignalCluster(signalCluster); 759 mNetworkController.addSignalCluster(signalClusterKeyguard); 760 mNetworkController.addSignalCluster(signalClusterQs); 761 signalCluster.setSecurityController(mSecurityController); 762 signalCluster.setNetworkController(mNetworkController); 763 signalClusterKeyguard.setSecurityController(mSecurityController); 764 signalClusterKeyguard.setNetworkController(mNetworkController); 765 signalClusterQs.setSecurityController(mSecurityController); 766 signalClusterQs.setNetworkController(mNetworkController); 767 final boolean isAPhone = mNetworkController.hasVoiceCallingFeature(); 768 if (isAPhone) { 769 mNetworkController.addEmergencyListener(new NetworkControllerImpl.EmergencyListener() { 770 @Override 771 public void setEmergencyCallsOnly(boolean emergencyOnly) { 772 mHeader.setShowEmergencyCallsOnly(emergencyOnly); 773 } 774 }); 775 } 776 777 mFlashlightController = new FlashlightController(mContext); 778 mKeyguardBottomArea.setFlashlightController(mFlashlightController); 779 mKeyguardBottomArea.setPhoneStatusBar(this); 780 mAccessibilityController = new AccessibilityController(mContext); 781 mKeyguardBottomArea.setAccessibilityController(mAccessibilityController); 782 mNextAlarmController = new NextAlarmController(mContext); 783 mKeyguardMonitor = new KeyguardMonitor(); 784 if (UserSwitcherController.isUserSwitcherAvailable(UserManager.get(mContext))) { 785 mUserSwitcherController = new UserSwitcherController(mContext, mKeyguardMonitor); 786 } 787 mKeyguardUserSwitcher = new KeyguardUserSwitcher(mContext, 788 (ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_user_switcher), 789 mKeyguardStatusBar, mNotificationPanel, mUserSwitcherController); 790 791 792 // Set up the quick settings tile panel 793 mQSPanel = (QSPanel) mStatusBarWindow.findViewById(R.id.quick_settings_panel); 794 if (mQSPanel != null) { 795 final QSTileHost qsh = new QSTileHost(mContext, this, 796 mBluetoothController, mLocationController, mRotationLockController, 797 mNetworkController, mZenModeController, mHotspotController, 798 mCastController, mFlashlightController, 799 mUserSwitcherController, mKeyguardMonitor, 800 mSecurityController); 801 mQSPanel.setHost(qsh); 802 mQSPanel.setTiles(qsh.getTiles()); 803 mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow); 804 mQSPanel.setBrightnessMirror(mBrightnessMirrorController); 805 mHeader.setQSPanel(mQSPanel); 806 qsh.setCallback(new QSTileHost.Callback() { 807 @Override 808 public void onTilesChanged() { 809 mQSPanel.setTiles(qsh.getTiles()); 810 } 811 }); 812 } 813 814 // User info. Trigger first load. 815 mHeader.setUserInfoController(mUserInfoController); 816 mKeyguardStatusBar.setUserInfoController(mUserInfoController); 817 mUserInfoController.reloadUserInfo(); 818 819 mHeader.setBatteryController(mBatteryController); 820 ((BatteryMeterView) mStatusBarView.findViewById(R.id.battery)).setBatteryController( 821 mBatteryController); 822 mKeyguardStatusBar.setBatteryController(mBatteryController); 823 mHeader.setNextAlarmController(mNextAlarmController); 824 825 PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 826 mBroadcastReceiver.onReceive(mContext, 827 new Intent(pm.isScreenOn() ? Intent.ACTION_SCREEN_ON : Intent.ACTION_SCREEN_OFF)); 828 829 // receive broadcasts 830 IntentFilter filter = new IntentFilter(); 831 filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); 832 filter.addAction(Intent.ACTION_SCREEN_OFF); 833 filter.addAction(Intent.ACTION_SCREEN_ON); 834 if (DEBUG_MEDIA_FAKE_ARTWORK) { 835 filter.addAction("fake_artwork"); 836 } 837 filter.addAction(ACTION_DEMO); 838 context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null); 839 840 // listen for USER_SETUP_COMPLETE setting (per-user) 841 resetUserSetupObserver(); 842 843 return mStatusBarView; 844 } 845 846 private void clearAllNotifications() { 847 848 // animate-swipe all dismissable notifications, then animate the shade closed 849 int numChildren = mStackScroller.getChildCount(); 850 851 final ArrayList<View> viewsToHide = new ArrayList<View>(numChildren); 852 for (int i = 0; i < numChildren; i++) { 853 final View child = mStackScroller.getChildAt(i); 854 if (mStackScroller.canChildBeDismissed(child)) { 855 if (child.getVisibility() == View.VISIBLE) { 856 viewsToHide.add(child); 857 } 858 } 859 } 860 if (viewsToHide.isEmpty()) { 861 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE); 862 return; 863 } 864 865 addPostCollapseAction(new Runnable() { 866 @Override 867 public void run() { 868 try { 869 mBarService.onClearAllNotifications(mCurrentUserId); 870 } catch (Exception ex) { } 871 } 872 }); 873 874 performDismissAllAnimations(viewsToHide); 875 876 } 877 878 private void performDismissAllAnimations(ArrayList<View> hideAnimatedList) { 879 Runnable animationFinishAction = new Runnable() { 880 @Override 881 public void run() { 882 mStackScroller.post(new Runnable() { 883 @Override 884 public void run() { 885 mStackScroller.setDismissAllInProgress(false); 886 } 887 }); 888 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE); 889 } 890 }; 891 892 // let's disable our normal animations 893 mStackScroller.setDismissAllInProgress(true); 894 895 // Decrease the delay for every row we animate to give the sense of 896 // accelerating the swipes 897 int rowDelayDecrement = 10; 898 int currentDelay = 140; 899 int totalDelay = 180; 900 int numItems = hideAnimatedList.size(); 901 for (int i = numItems - 1; i >= 0; i--) { 902 View view = hideAnimatedList.get(i); 903 Runnable endRunnable = null; 904 if (i == 0) { 905 endRunnable = animationFinishAction; 906 } 907 mStackScroller.dismissViewAnimated(view, endRunnable, totalDelay, 260); 908 currentDelay = Math.max(50, currentDelay - rowDelayDecrement); 909 totalDelay += currentDelay; 910 } 911 } 912 913 @Override 914 protected void setZenMode(int mode) { 915 super.setZenMode(mode); 916 if (mIconPolicy != null) { 917 mIconPolicy.setZenMode(mode); 918 } 919 } 920 921 private void startKeyguard() { 922 KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class); 923 mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this, 924 mStatusBarWindow, mStatusBarWindowManager, mScrimController); 925 mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback(); 926 } 927 928 @Override 929 protected View getStatusBarView() { 930 return mStatusBarView; 931 } 932 933 public StatusBarWindowView getStatusBarWindow() { 934 return mStatusBarWindow; 935 } 936 937 @Override 938 protected WindowManager.LayoutParams getSearchLayoutParams(LayoutParams layoutParams) { 939 boolean opaque = false; 940 WindowManager.LayoutParams lp = new WindowManager.LayoutParams( 941 LayoutParams.MATCH_PARENT, 942 LayoutParams.MATCH_PARENT, 943 WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL, 944 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN 945 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM 946 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, 947 (opaque ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT)); 948 if (ActivityManager.isHighEndGfx()) { 949 lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; 950 } 951 lp.gravity = Gravity.BOTTOM | Gravity.START; 952 lp.setTitle("SearchPanel"); 953 lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED 954 | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING; 955 return lp; 956 } 957 958 @Override 959 protected void updateSearchPanel() { 960 super.updateSearchPanel(); 961 if (mNavigationBarView != null) { 962 mNavigationBarView.setDelegateView(mSearchPanelView); 963 } 964 } 965 966 @Override 967 public void showSearchPanel() { 968 super.showSearchPanel(); 969 mHandler.removeCallbacks(mShowSearchPanel); 970 971 // we want to freeze the sysui state wherever it is 972 mSearchPanelView.setSystemUiVisibility(mSystemUiVisibility); 973 974 if (mNavigationBarView != null) { 975 WindowManager.LayoutParams lp = 976 (android.view.WindowManager.LayoutParams) mNavigationBarView.getLayoutParams(); 977 lp.flags &= ~WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; 978 mWindowManager.updateViewLayout(mNavigationBarView, lp); 979 } 980 } 981 982 @Override 983 public void hideSearchPanel() { 984 super.hideSearchPanel(); 985 if (mNavigationBarView != null) { 986 WindowManager.LayoutParams lp = 987 (android.view.WindowManager.LayoutParams) mNavigationBarView.getLayoutParams(); 988 lp.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; 989 mWindowManager.updateViewLayout(mNavigationBarView, lp); 990 } 991 } 992 993 public int getStatusBarHeight() { 994 if (mNaturalBarHeight < 0) { 995 final Resources res = mContext.getResources(); 996 mNaturalBarHeight = 997 res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height); 998 } 999 return mNaturalBarHeight; 1000 } 1001 1002 private View.OnClickListener mRecentsClickListener = new View.OnClickListener() { 1003 public void onClick(View v) { 1004 awakenDreams(); 1005 toggleRecentApps(); 1006 } 1007 }; 1008 1009 private long mLastLockToAppLongPress; 1010 private View.OnLongClickListener mLongPressBackRecentsListener = 1011 new View.OnLongClickListener() { 1012 @Override 1013 public boolean onLongClick(View v) { 1014 handleLongPressBackRecents(v); 1015 return true; 1016 } 1017 }; 1018 1019 private int mShowSearchHoldoff = 0; 1020 private Runnable mShowSearchPanel = new Runnable() { 1021 public void run() { 1022 showSearchPanel(); 1023 awakenDreams(); 1024 } 1025 }; 1026 1027 View.OnTouchListener mHomeActionListener = new View.OnTouchListener() { 1028 public boolean onTouch(View v, MotionEvent event) { 1029 switch(event.getAction()) { 1030 case MotionEvent.ACTION_DOWN: 1031 if (!shouldDisableNavbarGestures()) { 1032 mHandler.removeCallbacks(mShowSearchPanel); 1033 mHandler.postDelayed(mShowSearchPanel, mShowSearchHoldoff); 1034 } 1035 break; 1036 1037 case MotionEvent.ACTION_UP: 1038 case MotionEvent.ACTION_CANCEL: 1039 mHandler.removeCallbacks(mShowSearchPanel); 1040 awakenDreams(); 1041 break; 1042 } 1043 return false; 1044 } 1045 }; 1046 1047 private void awakenDreams() { 1048 if (mDreamManager != null) { 1049 try { 1050 mDreamManager.awaken(); 1051 } catch (RemoteException e) { 1052 // fine, stay asleep then 1053 } 1054 } 1055 } 1056 1057 private void prepareNavigationBarView() { 1058 mNavigationBarView.reorient(); 1059 1060 mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener); 1061 mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPreloadOnTouchListener); 1062 mNavigationBarView.getRecentsButton().setLongClickable(true); 1063 mNavigationBarView.getRecentsButton().setOnLongClickListener(mLongPressBackRecentsListener); 1064 mNavigationBarView.getBackButton().setLongClickable(true); 1065 mNavigationBarView.getBackButton().setOnLongClickListener(mLongPressBackRecentsListener); 1066 mNavigationBarView.getHomeButton().setOnTouchListener(mHomeActionListener); 1067 updateSearchPanel(); 1068 } 1069 1070 // For small-screen devices (read: phones) that lack hardware navigation buttons 1071 private void addNavigationBar() { 1072 if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + mNavigationBarView); 1073 if (mNavigationBarView == null) return; 1074 1075 prepareNavigationBarView(); 1076 1077 mWindowManager.addView(mNavigationBarView, getNavigationBarLayoutParams()); 1078 } 1079 1080 private void repositionNavigationBar() { 1081 if (mNavigationBarView == null || !mNavigationBarView.isAttachedToWindow()) return; 1082 1083 prepareNavigationBarView(); 1084 1085 mWindowManager.updateViewLayout(mNavigationBarView, getNavigationBarLayoutParams()); 1086 } 1087 1088 private void notifyNavigationBarScreenOn(boolean screenOn) { 1089 if (mNavigationBarView == null) return; 1090 mNavigationBarView.notifyScreenOn(screenOn); 1091 } 1092 1093 private WindowManager.LayoutParams getNavigationBarLayoutParams() { 1094 WindowManager.LayoutParams lp = new WindowManager.LayoutParams( 1095 LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, 1096 WindowManager.LayoutParams.TYPE_NAVIGATION_BAR, 1097 0 1098 | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING 1099 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 1100 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL 1101 | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH 1102 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, 1103 PixelFormat.TRANSLUCENT); 1104 // this will allow the navbar to run in an overlay on devices that support this 1105 if (ActivityManager.isHighEndGfx()) { 1106 lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; 1107 } 1108 1109 lp.setTitle("NavigationBar"); 1110 lp.windowAnimations = 0; 1111 return lp; 1112 } 1113 1114 private void addHeadsUpView() { 1115 int headsUpHeight = mContext.getResources() 1116 .getDimensionPixelSize(R.dimen.heads_up_window_height); 1117 WindowManager.LayoutParams lp = new WindowManager.LayoutParams( 1118 LayoutParams.MATCH_PARENT, headsUpHeight, 1119 WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL, // above the status bar! 1120 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN 1121 | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS 1122 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL 1123 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 1124 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM 1125 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, 1126 PixelFormat.TRANSLUCENT); 1127 lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; 1128 lp.gravity = Gravity.TOP; 1129 lp.setTitle("Heads Up"); 1130 lp.packageName = mContext.getPackageName(); 1131 lp.windowAnimations = R.style.Animation_StatusBar_HeadsUp; 1132 1133 mWindowManager.addView(mHeadsUpNotificationView, lp); 1134 } 1135 1136 private void removeHeadsUpView() { 1137 mWindowManager.removeView(mHeadsUpNotificationView); 1138 } 1139 1140 public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) { 1141 mIconController.addSystemIcon(slot, index, viewIndex, icon); 1142 } 1143 1144 public void updateIcon(String slot, int index, int viewIndex, 1145 StatusBarIcon old, StatusBarIcon icon) { 1146 mIconController.updateSystemIcon(slot, index, viewIndex, old, icon); 1147 } 1148 1149 public void removeIcon(String slot, int index, int viewIndex) { 1150 mIconController.removeSystemIcon(slot, index, viewIndex); 1151 } 1152 1153 public UserHandle getCurrentUserHandle() { 1154 return new UserHandle(mCurrentUserId); 1155 } 1156 1157 @Override 1158 public void addNotification(StatusBarNotification notification, RankingMap ranking) { 1159 if (DEBUG) Log.d(TAG, "addNotification key=" + notification.getKey()); 1160 if (mUseHeadsUp && shouldInterrupt(notification)) { 1161 if (DEBUG) Log.d(TAG, "launching notification in heads up mode"); 1162 Entry interruptionCandidate = new Entry(notification, null); 1163 ViewGroup holder = mHeadsUpNotificationView.getHolder(); 1164 if (inflateViewsForHeadsUp(interruptionCandidate, holder)) { 1165 // 1. Populate mHeadsUpNotificationView 1166 mHeadsUpNotificationView.showNotification(interruptionCandidate); 1167 1168 // do not show the notification in the shade, yet. 1169 return; 1170 } 1171 } 1172 1173 Entry shadeEntry = createNotificationViews(notification); 1174 if (shadeEntry == null) { 1175 return; 1176 } 1177 1178 if (notification.getNotification().fullScreenIntent != null) { 1179 // Stop screensaver if the notification has a full-screen intent. 1180 // (like an incoming phone call) 1181 awakenDreams(); 1182 1183 // not immersive & a full-screen alert should be shown 1184 if (DEBUG) Log.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent"); 1185 try { 1186 EventLog.writeEvent(EventLogTags.SYSUI_FULLSCREEN_NOTIFICATION, 1187 notification.getKey()); 1188 notification.getNotification().fullScreenIntent.send(); 1189 } catch (PendingIntent.CanceledException e) { 1190 } 1191 } 1192 addNotificationViews(shadeEntry, ranking); 1193 // Recalculate the position of the sliding windows and the titles. 1194 setAreThereNotifications(); 1195 } 1196 1197 public void displayNotificationFromHeadsUp(StatusBarNotification notification) { 1198 NotificationData.Entry shadeEntry = createNotificationViews(notification); 1199 if (shadeEntry == null) { 1200 return; 1201 } 1202 shadeEntry.setInterruption(); 1203 1204 addNotificationViews(shadeEntry, null); 1205 // Recalculate the position of the sliding windows and the titles. 1206 setAreThereNotifications(); 1207 } 1208 1209 @Override 1210 public void resetHeadsUpDecayTimer() { 1211 mHandler.removeMessages(MSG_DECAY_HEADS_UP); 1212 if (mUseHeadsUp && mHeadsUpNotificationDecay > 0 1213 && mHeadsUpNotificationView.isClearable()) { 1214 mHandler.sendEmptyMessageDelayed(MSG_DECAY_HEADS_UP, mHeadsUpNotificationDecay); 1215 } 1216 } 1217 1218 @Override 1219 public void scheduleHeadsUpOpen() { 1220 mHandler.removeMessages(MSG_SHOW_HEADS_UP); 1221 mHandler.sendEmptyMessage(MSG_SHOW_HEADS_UP); 1222 } 1223 1224 @Override 1225 public void scheduleHeadsUpClose() { 1226 mHandler.removeMessages(MSG_HIDE_HEADS_UP); 1227 mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP); 1228 } 1229 1230 @Override 1231 public void scheduleHeadsUpEscalation() { 1232 mHandler.removeMessages(MSG_ESCALATE_HEADS_UP); 1233 mHandler.sendEmptyMessage(MSG_ESCALATE_HEADS_UP); 1234 } 1235 1236 @Override 1237 protected void updateNotificationRanking(RankingMap ranking) { 1238 mNotificationData.updateRanking(ranking); 1239 updateNotifications(); 1240 } 1241 1242 @Override 1243 public void removeNotification(String key, RankingMap ranking) { 1244 if (ENABLE_HEADS_UP && mHeadsUpNotificationView.getEntry() != null 1245 && key.equals(mHeadsUpNotificationView.getEntry().notification.getKey())) { 1246 mHeadsUpNotificationView.clear(); 1247 } 1248 1249 StatusBarNotification old = removeNotificationViews(key, ranking); 1250 if (SPEW) Log.d(TAG, "removeNotification key=" + key + " old=" + old); 1251 1252 if (old != null) { 1253 if (CLOSE_PANEL_WHEN_EMPTIED && !hasActiveNotifications() 1254 && !mNotificationPanel.isTracking() && !mNotificationPanel.isQsExpanded()) { 1255 if (mState == StatusBarState.SHADE) { 1256 animateCollapsePanels(); 1257 } else if (mState == StatusBarState.SHADE_LOCKED) { 1258 goToKeyguard(); 1259 } 1260 } 1261 } 1262 setAreThereNotifications(); 1263 } 1264 1265 @Override 1266 protected void refreshLayout(int layoutDirection) { 1267 if (mNavigationBarView != null) { 1268 mNavigationBarView.setLayoutDirection(layoutDirection); 1269 } 1270 } 1271 1272 private void updateShowSearchHoldoff() { 1273 mShowSearchHoldoff = mContext.getResources().getInteger( 1274 R.integer.config_show_search_delay); 1275 } 1276 1277 private void updateNotificationShade() { 1278 if (mStackScroller == null) return; 1279 1280 // Do not modify the notifications during collapse. 1281 if (isCollapsing()) { 1282 addPostCollapseAction(new Runnable() { 1283 @Override 1284 public void run() { 1285 updateNotificationShade(); 1286 } 1287 }); 1288 return; 1289 } 1290 1291 ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications(); 1292 ArrayList<ExpandableNotificationRow> toShow = new ArrayList<>(activeNotifications.size()); 1293 final int N = activeNotifications.size(); 1294 for (int i=0; i<N; i++) { 1295 Entry ent = activeNotifications.get(i); 1296 int vis = ent.notification.getNotification().visibility; 1297 1298 // Display public version of the notification if we need to redact. 1299 final boolean hideSensitive = 1300 !userAllowsPrivateNotificationsInPublic(ent.notification.getUserId()); 1301 boolean sensitiveNote = vis == Notification.VISIBILITY_PRIVATE; 1302 boolean sensitivePackage = packageHasVisibilityOverride(ent.notification.getKey()); 1303 boolean sensitive = (sensitiveNote && hideSensitive) || sensitivePackage; 1304 boolean showingPublic = sensitive && isLockscreenPublicMode(); 1305 ent.row.setSensitive(sensitive); 1306 if (ent.autoRedacted && ent.legacy) { 1307 // TODO: Also fade this? Or, maybe easier (and better), provide a dark redacted form 1308 // for legacy auto redacted notifications. 1309 if (showingPublic) { 1310 ent.row.setShowingLegacyBackground(false); 1311 } else { 1312 ent.row.setShowingLegacyBackground(true); 1313 } 1314 } 1315 toShow.add(ent.row); 1316 } 1317 1318 ArrayList<View> toRemove = new ArrayList<View>(); 1319 for (int i=0; i< mStackScroller.getChildCount(); i++) { 1320 View child = mStackScroller.getChildAt(i); 1321 if (!toShow.contains(child) && child instanceof ExpandableNotificationRow) { 1322 toRemove.add(child); 1323 } 1324 } 1325 1326 for (View remove : toRemove) { 1327 mStackScroller.removeView(remove); 1328 } 1329 for (int i=0; i<toShow.size(); i++) { 1330 View v = toShow.get(i); 1331 if (v.getParent() == null) { 1332 mStackScroller.addView(v); 1333 } 1334 } 1335 1336 // So after all this work notifications still aren't sorted correctly. 1337 // Let's do that now by advancing through toShow and mStackScroller in 1338 // lock-step, making sure mStackScroller matches what we see in toShow. 1339 int j = 0; 1340 for (int i = 0; i < mStackScroller.getChildCount(); i++) { 1341 View child = mStackScroller.getChildAt(i); 1342 if (!(child instanceof ExpandableNotificationRow)) { 1343 // We don't care about non-notification views. 1344 continue; 1345 } 1346 1347 if (child == toShow.get(j)) { 1348 // Everything is well, advance both lists. 1349 j++; 1350 continue; 1351 } 1352 1353 // Oops, wrong notification at this position. Put the right one 1354 // here and advance both lists. 1355 mStackScroller.changeViewPosition(toShow.get(j), i); 1356 j++; 1357 } 1358 updateRowStates(); 1359 updateSpeedbump(); 1360 updateClearAll(); 1361 updateEmptyShadeView(); 1362 1363 // Disable QS if device not provisioned. 1364 // If the user switcher is simple then disable QS during setup because 1365 // the user intends to use the lock screen user switcher, QS in not needed. 1366 mNotificationPanel.setQsExpansionEnabled(isDeviceProvisioned() 1367 && (mUserSetup || mUserSwitcherController == null 1368 || !mUserSwitcherController.isSimpleUserSwitcher())); 1369 mShadeUpdates.check(); 1370 } 1371 1372 private boolean packageHasVisibilityOverride(String key) { 1373 return mNotificationData.getVisibilityOverride(key) 1374 != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE; 1375 } 1376 1377 private void updateClearAll() { 1378 boolean showDismissView = 1379 mState != StatusBarState.KEYGUARD && 1380 mNotificationData.hasActiveClearableNotifications(); 1381 mStackScroller.updateDismissView(showDismissView); 1382 } 1383 1384 private void updateEmptyShadeView() { 1385 boolean showEmptyShade = 1386 mState != StatusBarState.KEYGUARD && 1387 mNotificationData.getActiveNotifications().size() == 0; 1388 mNotificationPanel.setShadeEmpty(showEmptyShade); 1389 } 1390 1391 private void updateSpeedbump() { 1392 int speedbumpIndex = -1; 1393 int currentIndex = 0; 1394 ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications(); 1395 final int N = activeNotifications.size(); 1396 for (int i = 0; i < N; i++) { 1397 Entry entry = activeNotifications.get(i); 1398 if (entry.row.getVisibility() != View.GONE && 1399 mNotificationData.isAmbient(entry.key)) { 1400 speedbumpIndex = currentIndex; 1401 break; 1402 } 1403 currentIndex++; 1404 } 1405 mStackScroller.updateSpeedBumpIndex(speedbumpIndex); 1406 } 1407 1408 @Override 1409 protected void updateNotifications() { 1410 mNotificationData.filterAndSort(); 1411 1412 updateNotificationShade(); 1413 mIconController.updateNotificationIcons(mNotificationData); 1414 } 1415 1416 @Override 1417 protected void updateRowStates() { 1418 super.updateRowStates(); 1419 mNotificationPanel.notifyVisibleChildrenChanged(); 1420 } 1421 1422 @Override 1423 protected void setAreThereNotifications() { 1424 1425 if (SPEW) { 1426 final boolean clearable = hasActiveNotifications() && 1427 mNotificationData.hasActiveClearableNotifications(); 1428 Log.d(TAG, "setAreThereNotifications: N=" + 1429 mNotificationData.getActiveNotifications().size() + " any=" + 1430 hasActiveNotifications() + " clearable=" + clearable); 1431 } 1432 1433 final View nlo = mStatusBarView.findViewById(R.id.notification_lights_out); 1434 final boolean showDot = hasActiveNotifications() && !areLightsOn(); 1435 if (showDot != (nlo.getAlpha() == 1.0f)) { 1436 if (showDot) { 1437 nlo.setAlpha(0f); 1438 nlo.setVisibility(View.VISIBLE); 1439 } 1440 nlo.animate() 1441 .alpha(showDot?1:0) 1442 .setDuration(showDot?750:250) 1443 .setInterpolator(new AccelerateInterpolator(2.0f)) 1444 .setListener(showDot ? null : new AnimatorListenerAdapter() { 1445 @Override 1446 public void onAnimationEnd(Animator _a) { 1447 nlo.setVisibility(View.GONE); 1448 } 1449 }) 1450 .start(); 1451 } 1452 1453 findAndUpdateMediaNotifications(); 1454 } 1455 1456 public void findAndUpdateMediaNotifications() { 1457 boolean metaDataChanged = false; 1458 1459 synchronized (mNotificationData) { 1460 ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications(); 1461 final int N = activeNotifications.size(); 1462 Entry mediaNotification = null; 1463 MediaController controller = null; 1464 for (int i = 0; i < N; i++) { 1465 final Entry entry = activeNotifications.get(i); 1466 if (isMediaNotification(entry)) { 1467 final MediaSession.Token token = entry.notification.getNotification().extras 1468 .getParcelable(Notification.EXTRA_MEDIA_SESSION); 1469 if (token != null) { 1470 controller = new MediaController(mContext, token); 1471 if (controller != null) { 1472 // we've got a live one, here 1473 mediaNotification = entry; 1474 } 1475 } 1476 } 1477 } 1478 1479 if (mediaNotification == null) { 1480 // Still nothing? OK, let's just look for live media sessions and see if they match 1481 // one of our notifications. This will catch apps that aren't (yet!) using media 1482 // notifications. 1483 1484 if (mMediaSessionManager != null) { 1485 final List<MediaController> sessions 1486 = mMediaSessionManager.getActiveSessionsForUser( 1487 null, 1488 UserHandle.USER_ALL); 1489 1490 for (MediaController aController : sessions) { 1491 if (aController == null) continue; 1492 final PlaybackState state = aController.getPlaybackState(); 1493 if (state == null) continue; 1494 switch (state.getState()) { 1495 case PlaybackState.STATE_STOPPED: 1496 case PlaybackState.STATE_ERROR: 1497 continue; 1498 default: 1499 // now to see if we have one like this 1500 final String pkg = aController.getPackageName(); 1501 1502 for (int i = 0; i < N; i++) { 1503 final Entry entry = activeNotifications.get(i); 1504 if (entry.notification.getPackageName().equals(pkg)) { 1505 if (DEBUG_MEDIA) { 1506 Log.v(TAG, "DEBUG_MEDIA: found controller matching " 1507 + entry.notification.getKey()); 1508 } 1509 controller = aController; 1510 mediaNotification = entry; 1511 break; 1512 } 1513 } 1514 } 1515 } 1516 } 1517 } 1518 1519 if (!sameSessions(mMediaController, controller)) { 1520 // We have a new media session 1521 1522 if (mMediaController != null) { 1523 // something old was playing 1524 Log.v(TAG, "DEBUG_MEDIA: Disconnecting from old controller: " 1525 + mMediaController); 1526 mMediaController.unregisterCallback(mMediaListener); 1527 } 1528 mMediaController = controller; 1529 1530 if (mMediaController != null) { 1531 mMediaController.registerCallback(mMediaListener); 1532 mMediaMetadata = mMediaController.getMetadata(); 1533 if (DEBUG_MEDIA) { 1534 Log.v(TAG, "DEBUG_MEDIA: insert listener, receive metadata: " 1535 + mMediaMetadata); 1536 } 1537 1538 final String notificationKey = mediaNotification == null 1539 ? null 1540 : mediaNotification.notification.getKey(); 1541 1542 if (notificationKey == null || !notificationKey.equals(mMediaNotificationKey)) { 1543 // we have a new notification! 1544 if (DEBUG_MEDIA) { 1545 Log.v(TAG, "DEBUG_MEDIA: Found new media notification: key=" 1546 + notificationKey + " controller=" + controller); 1547 } 1548 mMediaNotificationKey = notificationKey; 1549 } 1550 } else { 1551 mMediaMetadata = null; 1552 mMediaNotificationKey = null; 1553 } 1554 1555 metaDataChanged = true; 1556 } else { 1557 // Media session unchanged 1558 1559 if (DEBUG_MEDIA) { 1560 Log.v(TAG, "DEBUG_MEDIA: Continuing media notification: key=" + mMediaNotificationKey); 1561 } 1562 } 1563 } 1564 1565 updateMediaMetaData(metaDataChanged); 1566 } 1567 1568 private boolean sameSessions(MediaController a, MediaController b) { 1569 if (a == b) return true; 1570 if (a == null) return false; 1571 return a.controlsSameSession(b); 1572 } 1573 1574 /** 1575 * Hide the album artwork that is fading out and release its bitmap. 1576 */ 1577 private Runnable mHideBackdropFront = new Runnable() { 1578 @Override 1579 public void run() { 1580 if (DEBUG_MEDIA) { 1581 Log.v(TAG, "DEBUG_MEDIA: removing fade layer"); 1582 } 1583 mBackdropFront.setVisibility(View.INVISIBLE); 1584 mBackdropFront.animate().cancel(); 1585 mBackdropFront.setImageDrawable(null); 1586 } 1587 }; 1588 1589 /** 1590 * Refresh or remove lockscreen artwork from media metadata. 1591 */ 1592 public void updateMediaMetaData(boolean metaDataChanged) { 1593 if (!SHOW_LOCKSCREEN_MEDIA_ARTWORK) return; 1594 1595 if (mBackdrop == null) return; // called too early 1596 1597 if (DEBUG_MEDIA) { 1598 Log.v(TAG, "DEBUG_MEDIA: updating album art for notification " + mMediaNotificationKey 1599 + " metadata=" + mMediaMetadata 1600 + " metaDataChanged=" + metaDataChanged 1601 + " state=" + mState); 1602 } 1603 1604 Bitmap artworkBitmap = null; 1605 if (mMediaMetadata != null) { 1606 artworkBitmap = mMediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ART); 1607 if (artworkBitmap == null) { 1608 artworkBitmap = mMediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART); 1609 // might still be null 1610 } 1611 } 1612 1613 final boolean hasArtwork = artworkBitmap != null; 1614 1615 if ((hasArtwork || DEBUG_MEDIA_FAKE_ARTWORK) 1616 && (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)) { 1617 // time to show some art! 1618 if (mBackdrop.getVisibility() != View.VISIBLE) { 1619 mBackdrop.setVisibility(View.VISIBLE); 1620 mBackdrop.animate().alpha(1f); 1621 metaDataChanged = true; 1622 if (DEBUG_MEDIA) { 1623 Log.v(TAG, "DEBUG_MEDIA: Fading in album artwork"); 1624 } 1625 } 1626 if (metaDataChanged) { 1627 if (mBackdropBack.getDrawable() != null) { 1628 Drawable drawable = mBackdropBack.getDrawable(); 1629 mBackdropFront.setImageDrawable(drawable); 1630 if (mScrimSrcModeEnabled) { 1631 mBackdropFront.getDrawable().mutate().setXfermode(mSrcOverXferMode); 1632 } 1633 mBackdropFront.setAlpha(1f); 1634 mBackdropFront.setVisibility(View.VISIBLE); 1635 } else { 1636 mBackdropFront.setVisibility(View.INVISIBLE); 1637 } 1638 1639 if (DEBUG_MEDIA_FAKE_ARTWORK) { 1640 final int c = 0xFF000000 | (int)(Math.random() * 0xFFFFFF); 1641 Log.v(TAG, String.format("DEBUG_MEDIA: setting new color: 0x%08x", c)); 1642 mBackdropBack.setBackgroundColor(0xFFFFFFFF); 1643 mBackdropBack.setImageDrawable(new ColorDrawable(c)); 1644 } else { 1645 mBackdropBack.setImageBitmap(artworkBitmap); 1646 } 1647 if (mScrimSrcModeEnabled) { 1648 mBackdropBack.getDrawable().mutate().setXfermode(mSrcXferMode); 1649 } 1650 1651 if (mBackdropFront.getVisibility() == View.VISIBLE) { 1652 if (DEBUG_MEDIA) { 1653 Log.v(TAG, "DEBUG_MEDIA: Crossfading album artwork from " 1654 + mBackdropFront.getDrawable() 1655 + " to " 1656 + mBackdropBack.getDrawable()); 1657 } 1658 mBackdropFront.animate() 1659 .setDuration(250) 1660 .alpha(0f).withEndAction(mHideBackdropFront); 1661 } 1662 } 1663 } else { 1664 // need to hide the album art, either because we are unlocked or because 1665 // the metadata isn't there to support it 1666 if (mBackdrop.getVisibility() != View.GONE) { 1667 if (DEBUG_MEDIA) { 1668 Log.v(TAG, "DEBUG_MEDIA: Fading out album artwork"); 1669 } 1670 mBackdrop.animate() 1671 .alpha(0f) 1672 .setInterpolator(mBackdropInterpolator) 1673 .setDuration(300) 1674 .setStartDelay(0) 1675 .withEndAction(new Runnable() { 1676 @Override 1677 public void run() { 1678 mBackdrop.setVisibility(View.GONE); 1679 mBackdropFront.animate().cancel(); 1680 mBackdropBack.animate().cancel(); 1681 mHandler.post(mHideBackdropFront); 1682 } 1683 }); 1684 if (mKeyguardFadingAway) { 1685 mBackdrop.animate() 1686 1687 // Make it disappear faster, as the focus should be on the activity behind. 1688 .setDuration(mKeyguardFadingAwayDuration / 2) 1689 .setStartDelay(mKeyguardFadingAwayDelay) 1690 .setInterpolator(mLinearInterpolator) 1691 .start(); 1692 } 1693 } 1694 } 1695 } 1696 1697 private int adjustDisableFlags(int state) { 1698 if (!mLaunchTransitionFadingAway 1699 && (mExpandedVisible || mBouncerShowing || mWaitingForKeyguardExit)) { 1700 state |= StatusBarManager.DISABLE_NOTIFICATION_ICONS; 1701 state |= StatusBarManager.DISABLE_SYSTEM_INFO; 1702 } 1703 return state; 1704 } 1705 1706 /** 1707 * State is one or more of the DISABLE constants from StatusBarManager. 1708 */ 1709 public void disable(int state, boolean animate) { 1710 mDisabledUnmodified = state; 1711 state = adjustDisableFlags(state); 1712 final int old = mDisabled; 1713 final int diff = state ^ old; 1714 mDisabled = state; 1715 1716 if (DEBUG) { 1717 Log.d(TAG, String.format("disable: 0x%08x -> 0x%08x (diff: 0x%08x)", 1718 old, state, diff)); 1719 } 1720 1721 StringBuilder flagdbg = new StringBuilder(); 1722 flagdbg.append("disable: < "); 1723 flagdbg.append(((state & StatusBarManager.DISABLE_EXPAND) != 0) ? "EXPAND" : "expand"); 1724 flagdbg.append(((diff & StatusBarManager.DISABLE_EXPAND) != 0) ? "* " : " "); 1725 flagdbg.append(((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) ? "ICONS" : "icons"); 1726 flagdbg.append(((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) ? "* " : " "); 1727 flagdbg.append(((state & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) ? "ALERTS" : "alerts"); 1728 flagdbg.append(((diff & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) ? "* " : " "); 1729 flagdbg.append(((state & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) ? "SYSTEM_INFO" : "system_info"); 1730 flagdbg.append(((diff & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) ? "* " : " "); 1731 flagdbg.append(((state & StatusBarManager.DISABLE_BACK) != 0) ? "BACK" : "back"); 1732 flagdbg.append(((diff & StatusBarManager.DISABLE_BACK) != 0) ? "* " : " "); 1733 flagdbg.append(((state & StatusBarManager.DISABLE_HOME) != 0) ? "HOME" : "home"); 1734 flagdbg.append(((diff & StatusBarManager.DISABLE_HOME) != 0) ? "* " : " "); 1735 flagdbg.append(((state & StatusBarManager.DISABLE_RECENT) != 0) ? "RECENT" : "recent"); 1736 flagdbg.append(((diff & StatusBarManager.DISABLE_RECENT) != 0) ? "* " : " "); 1737 flagdbg.append(((state & StatusBarManager.DISABLE_CLOCK) != 0) ? "CLOCK" : "clock"); 1738 flagdbg.append(((diff & StatusBarManager.DISABLE_CLOCK) != 0) ? "* " : " "); 1739 flagdbg.append(((state & StatusBarManager.DISABLE_SEARCH) != 0) ? "SEARCH" : "search"); 1740 flagdbg.append(((diff & StatusBarManager.DISABLE_SEARCH) != 0) ? "* " : " "); 1741 flagdbg.append(">"); 1742 Log.d(TAG, flagdbg.toString()); 1743 1744 if ((diff & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) { 1745 if ((state & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) { 1746 mIconController.hideSystemIconArea(animate); 1747 } else { 1748 mIconController.showSystemIconArea(animate); 1749 } 1750 } 1751 1752 if ((diff & StatusBarManager.DISABLE_CLOCK) != 0) { 1753 boolean visible = (state & StatusBarManager.DISABLE_CLOCK) == 0; 1754 mIconController.setClockVisibility(visible); 1755 } 1756 if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) { 1757 if ((state & StatusBarManager.DISABLE_EXPAND) != 0) { 1758 animateCollapsePanels(); 1759 } 1760 } 1761 1762 if ((diff & (StatusBarManager.DISABLE_HOME 1763 | StatusBarManager.DISABLE_RECENT 1764 | StatusBarManager.DISABLE_BACK 1765 | StatusBarManager.DISABLE_SEARCH)) != 0) { 1766 // the nav bar will take care of these 1767 if (mNavigationBarView != null) mNavigationBarView.setDisabledFlags(state); 1768 1769 if ((state & StatusBarManager.DISABLE_RECENT) != 0) { 1770 // close recents if it's visible 1771 mHandler.removeMessages(MSG_HIDE_RECENT_APPS); 1772 mHandler.sendEmptyMessage(MSG_HIDE_RECENT_APPS); 1773 } 1774 } 1775 1776 if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) { 1777 if ((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) { 1778 mIconController.hideNotificationIconArea(animate); 1779 } else { 1780 mIconController.showNotificationIconArea(animate); 1781 } 1782 } 1783 1784 if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) { 1785 mDisableNotificationAlerts = 1786 (state & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0; 1787 mHeadsUpObserver.onChange(true); 1788 } 1789 } 1790 1791 @Override 1792 protected BaseStatusBar.H createHandler() { 1793 return new PhoneStatusBar.H(); 1794 } 1795 1796 @Override 1797 public void startActivity(Intent intent, boolean dismissShade) { 1798 startActivityDismissingKeyguard(intent, false, dismissShade); 1799 } 1800 1801 public void setQsExpanded(boolean expanded) { 1802 mStatusBarWindowManager.setQsExpanded(expanded); 1803 } 1804 1805 public boolean isGoingToNotificationShade() { 1806 return mLeaveOpenOnKeyguardHide; 1807 } 1808 1809 public boolean isQsExpanded() { 1810 return mNotificationPanel.isQsExpanded(); 1811 } 1812 1813 public boolean isScreenOnComingFromTouch() { 1814 return mScreenOnComingFromTouch; 1815 } 1816 1817 public boolean isFalsingThresholdNeeded() { 1818 boolean onKeyguard = getBarState() == StatusBarState.KEYGUARD; 1819 boolean isCurrentlyInsecure = mUnlockMethodCache.isCurrentlyInsecure(); 1820 return onKeyguard && (isCurrentlyInsecure || mDozing || mScreenOnComingFromTouch); 1821 } 1822 1823 public boolean isDozing() { 1824 return mDozing; 1825 } 1826 1827 @Override // NotificationData.Environment 1828 public String getCurrentMediaNotificationKey() { 1829 return mMediaNotificationKey; 1830 } 1831 1832 public boolean isScrimSrcModeEnabled() { 1833 return mScrimSrcModeEnabled; 1834 } 1835 1836 /** 1837 * To be called when there's a state change in StatusBarKeyguardViewManager. 1838 */ 1839 public void onKeyguardViewManagerStatesUpdated() { 1840 logStateToEventlog(); 1841 } 1842 1843 @Override // UnlockMethodCache.OnUnlockMethodChangedListener 1844 public void onUnlockMethodStateChanged() { 1845 logStateToEventlog(); 1846 } 1847 1848 /** 1849 * All changes to the status bar and notifications funnel through here and are batched. 1850 */ 1851 private class H extends BaseStatusBar.H { 1852 public void handleMessage(Message m) { 1853 super.handleMessage(m); 1854 switch (m.what) { 1855 case MSG_OPEN_NOTIFICATION_PANEL: 1856 animateExpandNotificationsPanel(); 1857 break; 1858 case MSG_OPEN_SETTINGS_PANEL: 1859 animateExpandSettingsPanel(); 1860 break; 1861 case MSG_CLOSE_PANELS: 1862 animateCollapsePanels(); 1863 break; 1864 case MSG_SHOW_HEADS_UP: 1865 setHeadsUpVisibility(true); 1866 break; 1867 case MSG_DECAY_HEADS_UP: 1868 mHeadsUpNotificationView.release(); 1869 setHeadsUpVisibility(false); 1870 break; 1871 case MSG_HIDE_HEADS_UP: 1872 mHeadsUpNotificationView.release(); 1873 setHeadsUpVisibility(false); 1874 break; 1875 case MSG_ESCALATE_HEADS_UP: 1876 escalateHeadsUp(); 1877 setHeadsUpVisibility(false); 1878 break; 1879 case MSG_LAUNCH_TRANSITION_TIMEOUT: 1880 onLaunchTransitionTimeout(); 1881 break; 1882 } 1883 } 1884 } 1885 1886 /** if the interrupting notification had a fullscreen intent, fire it now. */ 1887 private void escalateHeadsUp() { 1888 if (mHeadsUpNotificationView.getEntry() != null) { 1889 final StatusBarNotification sbn = mHeadsUpNotificationView.getEntry().notification; 1890 mHeadsUpNotificationView.release(); 1891 final Notification notification = sbn.getNotification(); 1892 if (notification.fullScreenIntent != null) { 1893 if (DEBUG) 1894 Log.d(TAG, "converting a heads up to fullScreen"); 1895 try { 1896 EventLog.writeEvent(EventLogTags.SYSUI_HEADS_UP_ESCALATION, 1897 sbn.getKey()); 1898 notification.fullScreenIntent.send(); 1899 } catch (PendingIntent.CanceledException e) { 1900 } 1901 } 1902 } 1903 } 1904 1905 boolean panelsEnabled() { 1906 return (mDisabled & StatusBarManager.DISABLE_EXPAND) == 0; 1907 } 1908 1909 void makeExpandedVisible(boolean force) { 1910 if (SPEW) Log.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible); 1911 if (!force && (mExpandedVisible || !panelsEnabled())) { 1912 return; 1913 } 1914 1915 mExpandedVisible = true; 1916 if (mNavigationBarView != null) 1917 mNavigationBarView.setSlippery(true); 1918 1919 // Expand the window to encompass the full screen in anticipation of the drag. 1920 // This is only possible to do atomically because the status bar is at the top of the screen! 1921 mStatusBarWindowManager.setStatusBarExpanded(true); 1922 mStatusBarView.setFocusable(false); 1923 1924 visibilityChanged(true); 1925 mWaitingForKeyguardExit = false; 1926 disable(mDisabledUnmodified, !force /* animate */); 1927 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true); 1928 } 1929 1930 public void animateCollapsePanels() { 1931 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE); 1932 } 1933 1934 private final Runnable mAnimateCollapsePanels = new Runnable() { 1935 @Override 1936 public void run() { 1937 animateCollapsePanels(); 1938 } 1939 }; 1940 1941 public void postAnimateCollapsePanels() { 1942 mHandler.post(mAnimateCollapsePanels); 1943 } 1944 1945 public void animateCollapsePanels(int flags) { 1946 animateCollapsePanels(flags, false /* force */); 1947 } 1948 1949 public void animateCollapsePanels(int flags, boolean force) { 1950 if (!force && 1951 (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)) { 1952 runPostCollapseRunnables(); 1953 return; 1954 } 1955 if (SPEW) { 1956 Log.d(TAG, "animateCollapse():" 1957 + " mExpandedVisible=" + mExpandedVisible 1958 + " flags=" + flags); 1959 } 1960 1961 if ((flags & CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL) == 0) { 1962 if (!mHandler.hasMessages(MSG_HIDE_RECENT_APPS)) { 1963 mHandler.removeMessages(MSG_HIDE_RECENT_APPS); 1964 mHandler.sendEmptyMessage(MSG_HIDE_RECENT_APPS); 1965 } 1966 } 1967 1968 if ((flags & CommandQueue.FLAG_EXCLUDE_SEARCH_PANEL) == 0) { 1969 mHandler.removeMessages(MSG_CLOSE_SEARCH_PANEL); 1970 mHandler.sendEmptyMessage(MSG_CLOSE_SEARCH_PANEL); 1971 } 1972 1973 if (mStatusBarWindow != null) { 1974 // release focus immediately to kick off focus change transition 1975 mStatusBarWindowManager.setStatusBarFocusable(false); 1976 1977 mStatusBarWindow.cancelExpandHelper(); 1978 mStatusBarView.collapseAllPanels(true); 1979 } 1980 } 1981 1982 private void runPostCollapseRunnables() { 1983 int size = mPostCollapseRunnables.size(); 1984 for (int i = 0; i < size; i++) { 1985 mPostCollapseRunnables.get(i).run(); 1986 } 1987 mPostCollapseRunnables.clear(); 1988 } 1989 1990 Animator mScrollViewAnim, mClearButtonAnim; 1991 1992 @Override 1993 public void animateExpandNotificationsPanel() { 1994 if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible); 1995 if (!panelsEnabled()) { 1996 return ; 1997 } 1998 1999 mNotificationPanel.expand(); 2000 2001 if (false) postStartTracing(); 2002 } 2003 2004 @Override 2005 public void animateExpandSettingsPanel() { 2006 if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible); 2007 if (!panelsEnabled()) { 2008 return; 2009 } 2010 2011 // Settings are not available in setup 2012 if (!mUserSetup) return; 2013 2014 mNotificationPanel.expandWithQs(); 2015 2016 if (false) postStartTracing(); 2017 } 2018 2019 public void animateCollapseQuickSettings() { 2020 if (mState == StatusBarState.SHADE) { 2021 mStatusBarView.collapseAllPanels(true); 2022 } 2023 } 2024 2025 void makeExpandedInvisible() { 2026 if (SPEW) Log.d(TAG, "makeExpandedInvisible: mExpandedVisible=" + mExpandedVisible 2027 + " mExpandedVisible=" + mExpandedVisible); 2028 2029 if (!mExpandedVisible || mStatusBarWindow == null) { 2030 return; 2031 } 2032 2033 // Ensure the panel is fully collapsed (just in case; bug 6765842, 7260868) 2034 mStatusBarView.collapseAllPanels(/*animate=*/ false); 2035 2036 // reset things to their proper state 2037 mStackScroller.setVisibility(View.VISIBLE); 2038 mNotificationPanel.setVisibility(View.GONE); 2039 2040 mNotificationPanel.closeQs(); 2041 2042 mExpandedVisible = false; 2043 if (mNavigationBarView != null) 2044 mNavigationBarView.setSlippery(false); 2045 visibilityChanged(false); 2046 2047 // Shrink the window to the size of the status bar only 2048 mStatusBarWindowManager.setStatusBarExpanded(false); 2049 mStatusBarView.setFocusable(true); 2050 2051 // Close any "App info" popups that might have snuck on-screen 2052 dismissPopups(); 2053 2054 runPostCollapseRunnables(); 2055 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false); 2056 showBouncer(); 2057 disable(mDisabledUnmodified, true /* animate */); 2058 2059 // Trimming will happen later if Keyguard is showing - doing it here might cause a jank in 2060 // the bouncer appear animation. 2061 if (!mStatusBarKeyguardViewManager.isShowing()) { 2062 WindowManagerGlobal.getInstance().trimMemory(ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN); 2063 } 2064 } 2065 2066 public boolean interceptTouchEvent(MotionEvent event) { 2067 if (DEBUG_GESTURES) { 2068 if (event.getActionMasked() != MotionEvent.ACTION_MOVE) { 2069 EventLog.writeEvent(EventLogTags.SYSUI_STATUSBAR_TOUCH, 2070 event.getActionMasked(), (int) event.getX(), (int) event.getY(), mDisabled); 2071 } 2072 2073 } 2074 2075 if (SPEW) { 2076 Log.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled=" 2077 + mDisabled + " mTracking=" + mTracking); 2078 } else if (CHATTY) { 2079 if (event.getAction() != MotionEvent.ACTION_MOVE) { 2080 Log.d(TAG, String.format( 2081 "panel: %s at (%f, %f) mDisabled=0x%08x", 2082 MotionEvent.actionToString(event.getAction()), 2083 event.getRawX(), event.getRawY(), mDisabled)); 2084 } 2085 } 2086 2087 if (DEBUG_GESTURES) { 2088 mGestureRec.add(event); 2089 } 2090 2091 if (mStatusBarWindowState == WINDOW_STATE_SHOWING) { 2092 final boolean upOrCancel = 2093 event.getAction() == MotionEvent.ACTION_UP || 2094 event.getAction() == MotionEvent.ACTION_CANCEL; 2095 if (upOrCancel && !mExpandedVisible) { 2096 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false); 2097 } else { 2098 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true); 2099 } 2100 } 2101 return false; 2102 } 2103 2104 public GestureRecorder getGestureRecorder() { 2105 return mGestureRec; 2106 } 2107 2108 private void setNavigationIconHints(int hints) { 2109 if (hints == mNavigationIconHints) return; 2110 2111 mNavigationIconHints = hints; 2112 2113 if (mNavigationBarView != null) { 2114 mNavigationBarView.setNavigationIconHints(hints); 2115 } 2116 checkBarModes(); 2117 } 2118 2119 @Override // CommandQueue 2120 public void setWindowState(int window, int state) { 2121 boolean showing = state == WINDOW_STATE_SHOWING; 2122 if (mStatusBarWindow != null 2123 && window == StatusBarManager.WINDOW_STATUS_BAR 2124 && mStatusBarWindowState != state) { 2125 mStatusBarWindowState = state; 2126 if (DEBUG_WINDOW_STATE) Log.d(TAG, "Status bar " + windowStateToString(state)); 2127 if (!showing && mState == StatusBarState.SHADE) { 2128 mStatusBarView.collapseAllPanels(false); 2129 } 2130 } 2131 if (mNavigationBarView != null 2132 && window == StatusBarManager.WINDOW_NAVIGATION_BAR 2133 && mNavigationBarWindowState != state) { 2134 mNavigationBarWindowState = state; 2135 if (DEBUG_WINDOW_STATE) Log.d(TAG, "Navigation bar " + windowStateToString(state)); 2136 } 2137 } 2138 2139 @Override // CommandQueue 2140 public void buzzBeepBlinked() { 2141 if (mDozeServiceHost != null) { 2142 mDozeServiceHost.fireBuzzBeepBlinked(); 2143 } 2144 } 2145 2146 @Override 2147 public void notificationLightOff() { 2148 if (mDozeServiceHost != null) { 2149 mDozeServiceHost.fireNotificationLight(false); 2150 } 2151 } 2152 2153 @Override 2154 public void notificationLightPulse(int argb, int onMillis, int offMillis) { 2155 if (mDozeServiceHost != null) { 2156 mDozeServiceHost.fireNotificationLight(true); 2157 } 2158 } 2159 2160 @Override // CommandQueue 2161 public void setSystemUiVisibility(int vis, int mask) { 2162 final int oldVal = mSystemUiVisibility; 2163 final int newVal = (oldVal&~mask) | (vis&mask); 2164 final int diff = newVal ^ oldVal; 2165 if (DEBUG) Log.d(TAG, String.format( 2166 "setSystemUiVisibility vis=%s mask=%s oldVal=%s newVal=%s diff=%s", 2167 Integer.toHexString(vis), Integer.toHexString(mask), 2168 Integer.toHexString(oldVal), Integer.toHexString(newVal), 2169 Integer.toHexString(diff))); 2170 if (diff != 0) { 2171 // we never set the recents bit via this method, so save the prior state to prevent 2172 // clobbering the bit below 2173 final boolean wasRecentsVisible = (mSystemUiVisibility & View.RECENT_APPS_VISIBLE) > 0; 2174 2175 mSystemUiVisibility = newVal; 2176 2177 // update low profile 2178 if ((diff & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0) { 2179 final boolean lightsOut = (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0; 2180 if (lightsOut) { 2181 animateCollapsePanels(); 2182 } 2183 2184 setAreThereNotifications(); 2185 } 2186 2187 // update status bar mode 2188 final int sbMode = computeBarMode(oldVal, newVal, mStatusBarView.getBarTransitions(), 2189 View.STATUS_BAR_TRANSIENT, View.STATUS_BAR_TRANSLUCENT); 2190 2191 // update navigation bar mode 2192 final int nbMode = mNavigationBarView == null ? -1 : computeBarMode( 2193 oldVal, newVal, mNavigationBarView.getBarTransitions(), 2194 View.NAVIGATION_BAR_TRANSIENT, View.NAVIGATION_BAR_TRANSLUCENT); 2195 final boolean sbModeChanged = sbMode != -1; 2196 final boolean nbModeChanged = nbMode != -1; 2197 boolean checkBarModes = false; 2198 if (sbModeChanged && sbMode != mStatusBarMode) { 2199 mStatusBarMode = sbMode; 2200 checkBarModes = true; 2201 } 2202 if (nbModeChanged && nbMode != mNavigationBarMode) { 2203 mNavigationBarMode = nbMode; 2204 checkBarModes = true; 2205 } 2206 if (checkBarModes) { 2207 checkBarModes(); 2208 } 2209 if (sbModeChanged || nbModeChanged) { 2210 // update transient bar autohide 2211 if (mStatusBarMode == MODE_SEMI_TRANSPARENT || mNavigationBarMode == MODE_SEMI_TRANSPARENT) { 2212 scheduleAutohide(); 2213 } else { 2214 cancelAutohide(); 2215 } 2216 } 2217 2218 // ready to unhide 2219 if ((vis & View.STATUS_BAR_UNHIDE) != 0) { 2220 mSystemUiVisibility &= ~View.STATUS_BAR_UNHIDE; 2221 } 2222 if ((vis & View.NAVIGATION_BAR_UNHIDE) != 0) { 2223 mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE; 2224 } 2225 2226 // restore the recents bit 2227 if (wasRecentsVisible) { 2228 mSystemUiVisibility |= View.RECENT_APPS_VISIBLE; 2229 } 2230 2231 // send updated sysui visibility to window manager 2232 notifyUiVisibilityChanged(mSystemUiVisibility); 2233 } 2234 } 2235 2236 private int computeBarMode(int oldVis, int newVis, BarTransitions transitions, 2237 int transientFlag, int translucentFlag) { 2238 final int oldMode = barMode(oldVis, transientFlag, translucentFlag); 2239 final int newMode = barMode(newVis, transientFlag, translucentFlag); 2240 if (oldMode == newMode) { 2241 return -1; // no mode change 2242 } 2243 return newMode; 2244 } 2245 2246 private int barMode(int vis, int transientFlag, int translucentFlag) { 2247 int lightsOutTransparent = View.SYSTEM_UI_FLAG_LOW_PROFILE | View.SYSTEM_UI_TRANSPARENT; 2248 return (vis & transientFlag) != 0 ? MODE_SEMI_TRANSPARENT 2249 : (vis & translucentFlag) != 0 ? MODE_TRANSLUCENT 2250 : (vis & lightsOutTransparent) == lightsOutTransparent ? MODE_LIGHTS_OUT_TRANSPARENT 2251 : (vis & View.SYSTEM_UI_TRANSPARENT) != 0 ? MODE_TRANSPARENT 2252 : (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0 ? MODE_LIGHTS_OUT 2253 : MODE_OPAQUE; 2254 } 2255 2256 private void checkBarModes() { 2257 if (mDemoMode) return; 2258 checkBarMode(mStatusBarMode, mStatusBarWindowState, mStatusBarView.getBarTransitions()); 2259 if (mNavigationBarView != null) { 2260 checkBarMode(mNavigationBarMode, 2261 mNavigationBarWindowState, mNavigationBarView.getBarTransitions()); 2262 } 2263 } 2264 2265 private void checkBarMode(int mode, int windowState, BarTransitions transitions) { 2266 final boolean powerSave = mBatteryController.isPowerSave(); 2267 final boolean anim = (mScreenOn == null || mScreenOn) && windowState != WINDOW_STATE_HIDDEN 2268 && !powerSave; 2269 if (powerSave && getBarState() == StatusBarState.SHADE) { 2270 mode = MODE_WARNING; 2271 } 2272 transitions.transitionTo(mode, anim); 2273 } 2274 2275 private void finishBarAnimations() { 2276 mStatusBarView.getBarTransitions().finishAnimations(); 2277 if (mNavigationBarView != null) { 2278 mNavigationBarView.getBarTransitions().finishAnimations(); 2279 } 2280 } 2281 2282 private final Runnable mCheckBarModes = new Runnable() { 2283 @Override 2284 public void run() { 2285 checkBarModes(); 2286 } 2287 }; 2288 2289 @Override 2290 public void setInteracting(int barWindow, boolean interacting) { 2291 final boolean changing = ((mInteractingWindows & barWindow) != 0) != interacting; 2292 mInteractingWindows = interacting 2293 ? (mInteractingWindows | barWindow) 2294 : (mInteractingWindows & ~barWindow); 2295 if (mInteractingWindows != 0) { 2296 suspendAutohide(); 2297 } else { 2298 resumeSuspendedAutohide(); 2299 } 2300 // manually dismiss the volume panel when interacting with the nav bar 2301 if (changing && interacting && barWindow == StatusBarManager.WINDOW_NAVIGATION_BAR) { 2302 if (mVolumeComponent != null) { 2303 mVolumeComponent.dismissNow(); 2304 } 2305 } 2306 checkBarModes(); 2307 } 2308 2309 private void resumeSuspendedAutohide() { 2310 if (mAutohideSuspended) { 2311 scheduleAutohide(); 2312 mHandler.postDelayed(mCheckBarModes, 500); // longer than home -> launcher 2313 } 2314 } 2315 2316 private void suspendAutohide() { 2317 mHandler.removeCallbacks(mAutohide); 2318 mHandler.removeCallbacks(mCheckBarModes); 2319 mAutohideSuspended = (mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0; 2320 } 2321 2322 private void cancelAutohide() { 2323 mAutohideSuspended = false; 2324 mHandler.removeCallbacks(mAutohide); 2325 } 2326 2327 private void scheduleAutohide() { 2328 cancelAutohide(); 2329 mHandler.postDelayed(mAutohide, AUTOHIDE_TIMEOUT_MS); 2330 } 2331 2332 private void checkUserAutohide(View v, MotionEvent event) { 2333 if ((mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0 // a transient bar is revealed 2334 && event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar 2335 && event.getX() == 0 && event.getY() == 0 // a touch outside both bars 2336 ) { 2337 userAutohide(); 2338 } 2339 } 2340 2341 private void userAutohide() { 2342 cancelAutohide(); 2343 mHandler.postDelayed(mAutohide, 350); // longer than app gesture -> flag clear 2344 } 2345 2346 private boolean areLightsOn() { 2347 return 0 == (mSystemUiVisibility & View.SYSTEM_UI_FLAG_LOW_PROFILE); 2348 } 2349 2350 public void setLightsOn(boolean on) { 2351 Log.v(TAG, "setLightsOn(" + on + ")"); 2352 if (on) { 2353 setSystemUiVisibility(0, View.SYSTEM_UI_FLAG_LOW_PROFILE); 2354 } else { 2355 setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE, View.SYSTEM_UI_FLAG_LOW_PROFILE); 2356 } 2357 } 2358 2359 private void notifyUiVisibilityChanged(int vis) { 2360 try { 2361 mWindowManagerService.statusBarVisibilityChanged(vis); 2362 } catch (RemoteException ex) { 2363 } 2364 } 2365 2366 public void topAppWindowChanged(boolean showMenu) { 2367 if (DEBUG) { 2368 Log.d(TAG, (showMenu?"showing":"hiding") + " the MENU button"); 2369 } 2370 if (mNavigationBarView != null) { 2371 mNavigationBarView.setMenuVisibility(showMenu); 2372 } 2373 2374 // See above re: lights-out policy for legacy apps. 2375 if (showMenu) setLightsOn(true); 2376 } 2377 2378 @Override 2379 public void setImeWindowStatus(IBinder token, int vis, int backDisposition, 2380 boolean showImeSwitcher) { 2381 boolean imeShown = (vis & InputMethodService.IME_VISIBLE) != 0; 2382 int flags = mNavigationIconHints; 2383 if ((backDisposition == InputMethodService.BACK_DISPOSITION_WILL_DISMISS) || imeShown) { 2384 flags |= NAVIGATION_HINT_BACK_ALT; 2385 } else { 2386 flags &= ~NAVIGATION_HINT_BACK_ALT; 2387 } 2388 if (showImeSwitcher) { 2389 flags |= NAVIGATION_HINT_IME_SHOWN; 2390 } else { 2391 flags &= ~NAVIGATION_HINT_IME_SHOWN; 2392 } 2393 2394 setNavigationIconHints(flags); 2395 } 2396 2397 public static String viewInfo(View v) { 2398 return "[(" + v.getLeft() + "," + v.getTop() + ")(" + v.getRight() + "," + v.getBottom() 2399 + ") " + v.getWidth() + "x" + v.getHeight() + "]"; 2400 } 2401 2402 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2403 synchronized (mQueueLock) { 2404 pw.println("Current Status Bar state:"); 2405 pw.println(" mExpandedVisible=" + mExpandedVisible 2406 + ", mTrackingPosition=" + mTrackingPosition); 2407 pw.println(" mTracking=" + mTracking); 2408 pw.println(" mDisplayMetrics=" + mDisplayMetrics); 2409 pw.println(" mStackScroller: " + viewInfo(mStackScroller)); 2410 pw.println(" mStackScroller: " + viewInfo(mStackScroller) 2411 + " scroll " + mStackScroller.getScrollX() 2412 + "," + mStackScroller.getScrollY()); 2413 } 2414 2415 pw.print(" mInteractingWindows="); pw.println(mInteractingWindows); 2416 pw.print(" mStatusBarWindowState="); 2417 pw.println(windowStateToString(mStatusBarWindowState)); 2418 pw.print(" mStatusBarMode="); 2419 pw.println(BarTransitions.modeToString(mStatusBarMode)); 2420 pw.print(" mDozing="); pw.println(mDozing); 2421 pw.print(" mZenMode="); 2422 pw.println(Settings.Global.zenModeToString(mZenMode)); 2423 pw.print(" mUseHeadsUp="); 2424 pw.println(mUseHeadsUp); 2425 pw.print(" interrupting package: "); 2426 pw.println(hunStateToString(mHeadsUpNotificationView.getEntry())); 2427 dumpBarTransitions(pw, "mStatusBarView", mStatusBarView.getBarTransitions()); 2428 if (mNavigationBarView != null) { 2429 pw.print(" mNavigationBarWindowState="); 2430 pw.println(windowStateToString(mNavigationBarWindowState)); 2431 pw.print(" mNavigationBarMode="); 2432 pw.println(BarTransitions.modeToString(mNavigationBarMode)); 2433 dumpBarTransitions(pw, "mNavigationBarView", mNavigationBarView.getBarTransitions()); 2434 } 2435 2436 pw.print(" mNavigationBarView="); 2437 if (mNavigationBarView == null) { 2438 pw.println("null"); 2439 } else { 2440 mNavigationBarView.dump(fd, pw, args); 2441 } 2442 2443 pw.print(" mMediaSessionManager="); 2444 pw.println(mMediaSessionManager); 2445 pw.print(" mMediaNotificationKey="); 2446 pw.println(mMediaNotificationKey); 2447 pw.print(" mMediaController="); 2448 pw.print(mMediaController); 2449 if (mMediaController != null) { 2450 pw.print(" state=" + mMediaController.getPlaybackState()); 2451 } 2452 pw.println(); 2453 pw.print(" mMediaMetadata="); 2454 pw.print(mMediaMetadata); 2455 if (mMediaMetadata != null) { 2456 pw.print(" title=" + mMediaMetadata.getText(MediaMetadata.METADATA_KEY_TITLE)); 2457 } 2458 pw.println(); 2459 2460 pw.println(" Panels: "); 2461 if (mNotificationPanel != null) { 2462 pw.println(" mNotificationPanel=" + 2463 mNotificationPanel + " params=" + mNotificationPanel.getLayoutParams().debug("")); 2464 pw.print (" "); 2465 mNotificationPanel.dump(fd, pw, args); 2466 } 2467 2468 DozeLog.dump(pw); 2469 2470 if (DUMPTRUCK) { 2471 synchronized (mNotificationData) { 2472 mNotificationData.dump(pw, " "); 2473 } 2474 2475 mIconController.dump(pw); 2476 2477 if (false) { 2478 pw.println("see the logcat for a dump of the views we have created."); 2479 // must happen on ui thread 2480 mHandler.post(new Runnable() { 2481 public void run() { 2482 mStatusBarView.getLocationOnScreen(mAbsPos); 2483 Log.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1] 2484 + ") " + mStatusBarView.getWidth() + "x" 2485 + getStatusBarHeight()); 2486 mStatusBarView.debug(); 2487 } 2488 }); 2489 } 2490 } 2491 2492 if (DEBUG_GESTURES) { 2493 pw.print(" status bar gestures: "); 2494 mGestureRec.dump(fd, pw, args); 2495 } 2496 2497 if (mNetworkController != null) { 2498 mNetworkController.dump(fd, pw, args); 2499 } 2500 if (mBluetoothController != null) { 2501 mBluetoothController.dump(fd, pw, args); 2502 } 2503 if (mCastController != null) { 2504 mCastController.dump(fd, pw, args); 2505 } 2506 if (mUserSwitcherController != null) { 2507 mUserSwitcherController.dump(fd, pw, args); 2508 } 2509 if (mBatteryController != null) { 2510 mBatteryController.dump(fd, pw, args); 2511 } 2512 if (mNextAlarmController != null) { 2513 mNextAlarmController.dump(fd, pw, args); 2514 } 2515 if (mSecurityController != null) { 2516 mSecurityController.dump(fd, pw, args); 2517 } 2518 pw.println("SharedPreferences:"); 2519 for (Map.Entry<String, ?> entry : mContext.getSharedPreferences(mContext.getPackageName(), 2520 Context.MODE_PRIVATE).getAll().entrySet()) { 2521 pw.print(" "); pw.print(entry.getKey()); pw.print("="); pw.println(entry.getValue()); 2522 } 2523 } 2524 2525 private String hunStateToString(Entry entry) { 2526 if (entry == null) return "null"; 2527 if (entry.notification == null) return "corrupt"; 2528 return entry.notification.getPackageName(); 2529 } 2530 2531 private static void dumpBarTransitions(PrintWriter pw, String var, BarTransitions transitions) { 2532 pw.print(" "); pw.print(var); pw.print(".BarTransitions.mMode="); 2533 pw.println(BarTransitions.modeToString(transitions.getMode())); 2534 } 2535 2536 @Override 2537 public void createAndAddWindows() { 2538 addStatusBarWindow(); 2539 } 2540 2541 private void addStatusBarWindow() { 2542 makeStatusBarView(); 2543 mStatusBarWindowManager = new StatusBarWindowManager(mContext); 2544 mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight()); 2545 } 2546 2547 // called by makeStatusbar and also by PhoneStatusBarView 2548 void updateDisplaySize() { 2549 mDisplay.getMetrics(mDisplayMetrics); 2550 mDisplay.getSize(mCurrentDisplaySize); 2551 if (DEBUG_GESTURES) { 2552 mGestureRec.tag("display", 2553 String.format("%dx%d", mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels)); 2554 } 2555 } 2556 2557 float getDisplayDensity() { 2558 return mDisplayMetrics.density; 2559 } 2560 2561 public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned, 2562 final boolean dismissShade) { 2563 if (onlyProvisioned && !isDeviceProvisioned()) return; 2564 2565 final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity( 2566 mContext, intent, mCurrentUserId); 2567 final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing(); 2568 dismissKeyguardThenExecute(new OnDismissAction() { 2569 @Override 2570 public boolean onDismiss() { 2571 AsyncTask.execute(new Runnable() { 2572 public void run() { 2573 try { 2574 if (keyguardShowing && !afterKeyguardGone) { 2575 ActivityManagerNative.getDefault() 2576 .keyguardWaitingForActivityDrawn(); 2577 } 2578 intent.setFlags( 2579 Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); 2580 mContext.startActivityAsUser( 2581 intent, new UserHandle(UserHandle.USER_CURRENT)); 2582 overrideActivityPendingAppTransition( 2583 keyguardShowing && !afterKeyguardGone); 2584 } catch (RemoteException e) { 2585 } 2586 } 2587 }); 2588 if (dismissShade) { 2589 animateCollapsePanels( 2590 CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */); 2591 } 2592 return true; 2593 } 2594 }, afterKeyguardGone); 2595 } 2596 2597 private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 2598 public void onReceive(Context context, Intent intent) { 2599 if (DEBUG) Log.v(TAG, "onReceive: " + intent); 2600 String action = intent.getAction(); 2601 if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) { 2602 if (isCurrentProfile(getSendingUserId())) { 2603 int flags = CommandQueue.FLAG_EXCLUDE_NONE; 2604 String reason = intent.getStringExtra("reason"); 2605 if (reason != null && reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) { 2606 flags |= CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL; 2607 } 2608 animateCollapsePanels(flags); 2609 } 2610 } 2611 else if (Intent.ACTION_SCREEN_OFF.equals(action)) { 2612 mScreenOn = false; 2613 notifyNavigationBarScreenOn(false); 2614 notifyHeadsUpScreenOn(false); 2615 finishBarAnimations(); 2616 resetUserExpandedStates(); 2617 } 2618 else if (Intent.ACTION_SCREEN_ON.equals(action)) { 2619 mScreenOn = true; 2620 notifyNavigationBarScreenOn(true); 2621 } 2622 else if (ACTION_DEMO.equals(action)) { 2623 Bundle bundle = intent.getExtras(); 2624 if (bundle != null) { 2625 String command = bundle.getString("command", "").trim().toLowerCase(); 2626 if (command.length() > 0) { 2627 try { 2628 dispatchDemoCommand(command, bundle); 2629 } catch (Throwable t) { 2630 Log.w(TAG, "Error running demo command, intent=" + intent, t); 2631 } 2632 } 2633 } 2634 } else if ("fake_artwork".equals(action)) { 2635 if (DEBUG_MEDIA_FAKE_ARTWORK) { 2636 updateMediaMetaData(true); 2637 } 2638 } 2639 } 2640 }; 2641 2642 private void resetUserExpandedStates() { 2643 ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications(); 2644 final int notificationCount = activeNotifications.size(); 2645 for (int i = 0; i < notificationCount; i++) { 2646 NotificationData.Entry entry = activeNotifications.get(i); 2647 if (entry.row != null) { 2648 entry.row.resetUserExpansion(); 2649 } 2650 } 2651 } 2652 2653 @Override 2654 protected void dismissKeyguardThenExecute(final OnDismissAction action, 2655 boolean afterKeyguardGone) { 2656 if (mStatusBarKeyguardViewManager.isShowing()) { 2657 mStatusBarKeyguardViewManager.dismissWithAction(action, afterKeyguardGone); 2658 } else { 2659 action.onDismiss(); 2660 } 2661 } 2662 2663 // SystemUIService notifies SystemBars of configuration changes, which then calls down here 2664 @Override 2665 protected void onConfigurationChanged(Configuration newConfig) { 2666 super.onConfigurationChanged(newConfig); // calls refreshLayout 2667 2668 if (DEBUG) { 2669 Log.v(TAG, "configuration changed: " + mContext.getResources().getConfiguration()); 2670 } 2671 updateDisplaySize(); // populates mDisplayMetrics 2672 2673 updateResources(); 2674 repositionNavigationBar(); 2675 updateShowSearchHoldoff(); 2676 updateRowStates(); 2677 mIconController.updateResources(); 2678 mScreenPinningRequest.onConfigurationChanged(); 2679 } 2680 2681 @Override 2682 public void userSwitched(int newUserId) { 2683 super.userSwitched(newUserId); 2684 if (MULTIUSER_DEBUG) mNotificationPanelDebugText.setText("USER " + newUserId); 2685 animateCollapsePanels(); 2686 updatePublicMode(); 2687 updateNotifications(); 2688 resetUserSetupObserver(); 2689 setControllerUsers(); 2690 } 2691 2692 private void setControllerUsers() { 2693 if (mZenModeController != null) { 2694 mZenModeController.setUserId(mCurrentUserId); 2695 } 2696 } 2697 2698 private void resetUserSetupObserver() { 2699 mContext.getContentResolver().unregisterContentObserver(mUserSetupObserver); 2700 mUserSetupObserver.onChange(false); 2701 mContext.getContentResolver().registerContentObserver( 2702 Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE), true, 2703 mUserSetupObserver, mCurrentUserId); 2704 } 2705 2706 private void setHeadsUpVisibility(boolean vis) { 2707 if (!ENABLE_HEADS_UP) return; 2708 if (DEBUG) Log.v(TAG, (vis ? "showing" : "hiding") + " heads up window"); 2709 EventLog.writeEvent(EventLogTags.SYSUI_HEADS_UP_STATUS, 2710 vis ? mHeadsUpNotificationView.getKey() : "", 2711 vis ? 1 : 0); 2712 mHeadsUpNotificationView.setVisibility(vis ? View.VISIBLE : View.GONE); 2713 } 2714 2715 public void onHeadsUpDismissed() { 2716 mHeadsUpNotificationView.dismiss(); 2717 } 2718 2719 /** 2720 * Reload some of our resources when the configuration changes. 2721 * 2722 * We don't reload everything when the configuration changes -- we probably 2723 * should, but getting that smooth is tough. Someday we'll fix that. In the 2724 * meantime, just update the things that we know change. 2725 */ 2726 void updateResources() { 2727 // Update the quick setting tiles 2728 if (mQSPanel != null) { 2729 mQSPanel.updateResources(); 2730 } 2731 2732 loadDimens(); 2733 2734 if (mNotificationPanel != null) { 2735 mNotificationPanel.updateResources(); 2736 } 2737 if (mHeadsUpNotificationView != null) { 2738 mHeadsUpNotificationView.updateResources(); 2739 } 2740 if (mBrightnessMirrorController != null) { 2741 mBrightnessMirrorController.updateResources(); 2742 } 2743 } 2744 2745 protected void loadDimens() { 2746 final Resources res = mContext.getResources(); 2747 2748 mNaturalBarHeight = res.getDimensionPixelSize( 2749 com.android.internal.R.dimen.status_bar_height); 2750 2751 mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore); 2752 2753 mHeadsUpNotificationDecay = res.getInteger(R.integer.heads_up_notification_decay); 2754 mRowMinHeight = res.getDimensionPixelSize(R.dimen.notification_min_height); 2755 mRowMaxHeight = res.getDimensionPixelSize(R.dimen.notification_max_height); 2756 2757 mKeyguardMaxNotificationCount = res.getInteger(R.integer.keyguard_max_notification_count); 2758 2759 if (DEBUG) Log.v(TAG, "updateResources"); 2760 } 2761 2762 // Visibility reporting 2763 2764 @Override 2765 protected void handleVisibleToUserChanged(boolean visibleToUser) { 2766 if (visibleToUser) { 2767 super.handleVisibleToUserChanged(visibleToUser); 2768 startNotificationLogging(); 2769 } else { 2770 stopNotificationLogging(); 2771 super.handleVisibleToUserChanged(visibleToUser); 2772 } 2773 } 2774 2775 private void stopNotificationLogging() { 2776 // Report all notifications as invisible and turn down the 2777 // reporter. 2778 if (!mCurrentlyVisibleNotifications.isEmpty()) { 2779 logNotificationVisibilityChanges( 2780 Collections.<String>emptyList(), mCurrentlyVisibleNotifications); 2781 mCurrentlyVisibleNotifications.clear(); 2782 } 2783 mHandler.removeCallbacks(mVisibilityReporter); 2784 mStackScroller.setChildLocationsChangedListener(null); 2785 } 2786 2787 private void startNotificationLogging() { 2788 mStackScroller.setChildLocationsChangedListener(mNotificationLocationsChangedListener); 2789 // Some transitions like mVisibleToUser=false -> mVisibleToUser=true don't 2790 // cause the scroller to emit child location events. Hence generate 2791 // one ourselves to guarantee that we're reporting visible 2792 // notifications. 2793 // (Note that in cases where the scroller does emit events, this 2794 // additional event doesn't break anything.) 2795 mNotificationLocationsChangedListener.onChildLocationsChanged(mStackScroller); 2796 } 2797 2798 private void logNotificationVisibilityChanges( 2799 Collection<String> newlyVisible, Collection<String> noLongerVisible) { 2800 if (newlyVisible.isEmpty() && noLongerVisible.isEmpty()) { 2801 return; 2802 } 2803 String[] newlyVisibleAr = newlyVisible.toArray(new String[newlyVisible.size()]); 2804 String[] noLongerVisibleAr = noLongerVisible.toArray(new String[noLongerVisible.size()]); 2805 try { 2806 mBarService.onNotificationVisibilityChanged(newlyVisibleAr, noLongerVisibleAr); 2807 } catch (RemoteException e) { 2808 // Ignore. 2809 } 2810 } 2811 2812 // State logging 2813 2814 private void logStateToEventlog() { 2815 boolean isShowing = mStatusBarKeyguardViewManager.isShowing(); 2816 boolean isOccluded = mStatusBarKeyguardViewManager.isOccluded(); 2817 boolean isBouncerShowing = mStatusBarKeyguardViewManager.isBouncerShowing(); 2818 boolean isSecure = mUnlockMethodCache.isMethodSecure(); 2819 boolean isCurrentlyInsecure = mUnlockMethodCache.isCurrentlyInsecure(); 2820 int stateFingerprint = getLoggingFingerprint(mState, 2821 isShowing, 2822 isOccluded, 2823 isBouncerShowing, 2824 isSecure, 2825 isCurrentlyInsecure); 2826 if (stateFingerprint != mLastLoggedStateFingerprint) { 2827 EventLogTags.writeSysuiStatusBarState(mState, 2828 isShowing ? 1 : 0, 2829 isOccluded ? 1 : 0, 2830 isBouncerShowing ? 1 : 0, 2831 isSecure ? 1 : 0, 2832 isCurrentlyInsecure ? 1 : 0); 2833 mLastLoggedStateFingerprint = stateFingerprint; 2834 } 2835 } 2836 2837 /** 2838 * Returns a fingerprint of fields logged to eventlog 2839 */ 2840 private static int getLoggingFingerprint(int statusBarState, boolean keyguardShowing, 2841 boolean keyguardOccluded, boolean bouncerShowing, boolean secure, 2842 boolean currentlyInsecure) { 2843 // Reserve 8 bits for statusBarState. We'll never go higher than 2844 // that, right? Riiiight. 2845 return (statusBarState & 0xFF) 2846 | ((keyguardShowing ? 1 : 0) << 8) 2847 | ((keyguardOccluded ? 1 : 0) << 9) 2848 | ((bouncerShowing ? 1 : 0) << 10) 2849 | ((secure ? 1 : 0) << 11) 2850 | ((currentlyInsecure ? 1 : 0) << 12); 2851 } 2852 2853 // 2854 // tracing 2855 // 2856 2857 void postStartTracing() { 2858 mHandler.postDelayed(mStartTracing, 3000); 2859 } 2860 2861 void vibrate() { 2862 android.os.Vibrator vib = (android.os.Vibrator)mContext.getSystemService( 2863 Context.VIBRATOR_SERVICE); 2864 vib.vibrate(250, VIBRATION_ATTRIBUTES); 2865 } 2866 2867 Runnable mStartTracing = new Runnable() { 2868 public void run() { 2869 vibrate(); 2870 SystemClock.sleep(250); 2871 Log.d(TAG, "startTracing"); 2872 android.os.Debug.startMethodTracing("/data/statusbar-traces/trace"); 2873 mHandler.postDelayed(mStopTracing, 10000); 2874 } 2875 }; 2876 2877 Runnable mStopTracing = new Runnable() { 2878 public void run() { 2879 android.os.Debug.stopMethodTracing(); 2880 Log.d(TAG, "stopTracing"); 2881 vibrate(); 2882 } 2883 }; 2884 2885 @Override 2886 protected boolean shouldDisableNavbarGestures() { 2887 return !isDeviceProvisioned() 2888 || mExpandedVisible 2889 || (mDisabled & StatusBarManager.DISABLE_SEARCH) != 0; 2890 } 2891 2892 public void postStartSettingsActivity(final Intent intent, int delay) { 2893 mHandler.postDelayed(new Runnable() { 2894 @Override 2895 public void run() { 2896 handleStartSettingsActivity(intent, true /*onlyProvisioned*/); 2897 } 2898 }, delay); 2899 } 2900 2901 private void handleStartSettingsActivity(Intent intent, boolean onlyProvisioned) { 2902 startActivityDismissingKeyguard(intent, onlyProvisioned, true /* dismissShade */); 2903 } 2904 2905 private static class FastColorDrawable extends Drawable { 2906 private final int mColor; 2907 2908 public FastColorDrawable(int color) { 2909 mColor = 0xff000000 | color; 2910 } 2911 2912 @Override 2913 public void draw(Canvas canvas) { 2914 canvas.drawColor(mColor, PorterDuff.Mode.SRC); 2915 } 2916 2917 @Override 2918 public void setAlpha(int alpha) { 2919 } 2920 2921 @Override 2922 public void setColorFilter(ColorFilter cf) { 2923 } 2924 2925 @Override 2926 public int getOpacity() { 2927 return PixelFormat.OPAQUE; 2928 } 2929 2930 @Override 2931 public void setBounds(int left, int top, int right, int bottom) { 2932 } 2933 2934 @Override 2935 public void setBounds(Rect bounds) { 2936 } 2937 } 2938 2939 @Override 2940 public void destroy() { 2941 super.destroy(); 2942 if (mStatusBarWindow != null) { 2943 mWindowManager.removeViewImmediate(mStatusBarWindow); 2944 mStatusBarWindow = null; 2945 } 2946 if (mNavigationBarView != null) { 2947 mWindowManager.removeViewImmediate(mNavigationBarView); 2948 mNavigationBarView = null; 2949 } 2950 if (mHandlerThread != null) { 2951 mHandlerThread.quitSafely(); 2952 mHandlerThread = null; 2953 } 2954 mContext.unregisterReceiver(mBroadcastReceiver); 2955 } 2956 2957 private boolean mDemoModeAllowed; 2958 private boolean mDemoMode; 2959 2960 @Override 2961 public void dispatchDemoCommand(String command, Bundle args) { 2962 if (!mDemoModeAllowed) { 2963 mDemoModeAllowed = Settings.Global.getInt(mContext.getContentResolver(), 2964 "sysui_demo_allowed", 0) != 0; 2965 } 2966 if (!mDemoModeAllowed) return; 2967 if (command.equals(COMMAND_ENTER)) { 2968 mDemoMode = true; 2969 } else if (command.equals(COMMAND_EXIT)) { 2970 mDemoMode = false; 2971 checkBarModes(); 2972 } else if (!mDemoMode) { 2973 // automatically enter demo mode on first demo command 2974 dispatchDemoCommand(COMMAND_ENTER, new Bundle()); 2975 } 2976 boolean modeChange = command.equals(COMMAND_ENTER) || command.equals(COMMAND_EXIT); 2977 if ((modeChange || command.equals(COMMAND_VOLUME)) && mVolumeComponent != null) { 2978 mVolumeComponent.dispatchDemoCommand(command, args); 2979 } 2980 if (modeChange || command.equals(COMMAND_CLOCK)) { 2981 dispatchDemoCommandToView(command, args, R.id.clock); 2982 } 2983 if (modeChange || command.equals(COMMAND_BATTERY)) { 2984 dispatchDemoCommandToView(command, args, R.id.battery); 2985 } 2986 if (modeChange || command.equals(COMMAND_STATUS)) { 2987 mIconController.dispatchDemoCommand(command, args); 2988 2989 } 2990 if (mNetworkController != null && (modeChange || command.equals(COMMAND_NETWORK))) { 2991 mNetworkController.dispatchDemoCommand(command, args); 2992 } 2993 if (modeChange || command.equals(COMMAND_NOTIFICATIONS)) { 2994 View notifications = mStatusBarView == null ? null 2995 : mStatusBarView.findViewById(R.id.notification_icon_area); 2996 if (notifications != null) { 2997 String visible = args.getString("visible"); 2998 int vis = mDemoMode && "false".equals(visible) ? View.INVISIBLE : View.VISIBLE; 2999 notifications.setVisibility(vis); 3000 } 3001 } 3002 if (command.equals(COMMAND_BARS)) { 3003 String mode = args.getString("mode"); 3004 int barMode = "opaque".equals(mode) ? MODE_OPAQUE : 3005 "translucent".equals(mode) ? MODE_TRANSLUCENT : 3006 "semi-transparent".equals(mode) ? MODE_SEMI_TRANSPARENT : 3007 "transparent".equals(mode) ? MODE_TRANSPARENT : 3008 "warning".equals(mode) ? MODE_WARNING : 3009 -1; 3010 if (barMode != -1) { 3011 boolean animate = true; 3012 if (mStatusBarView != null) { 3013 mStatusBarView.getBarTransitions().transitionTo(barMode, animate); 3014 } 3015 if (mNavigationBarView != null) { 3016 mNavigationBarView.getBarTransitions().transitionTo(barMode, animate); 3017 } 3018 } 3019 } 3020 } 3021 3022 private void dispatchDemoCommandToView(String command, Bundle args, int id) { 3023 if (mStatusBarView == null) return; 3024 View v = mStatusBarView.findViewById(id); 3025 if (v instanceof DemoMode) { 3026 ((DemoMode)v).dispatchDemoCommand(command, args); 3027 } 3028 } 3029 3030 /** 3031 * @return The {@link StatusBarState} the status bar is in. 3032 */ 3033 public int getBarState() { 3034 return mState; 3035 } 3036 3037 public void showKeyguard() { 3038 if (mLaunchTransitionFadingAway) { 3039 mNotificationPanel.animate().cancel(); 3040 mNotificationPanel.setAlpha(1f); 3041 runLaunchTransitionEndRunnable(); 3042 mLaunchTransitionFadingAway = false; 3043 } 3044 mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT); 3045 setBarState(StatusBarState.KEYGUARD); 3046 updateKeyguardState(false /* goingToFullShade */, false /* fromShadeLocked */); 3047 if (!mScreenOnFromKeyguard) { 3048 3049 // If the screen is off already, we need to disable touch events because these might 3050 // collapse the panel after we expanded it, and thus we would end up with a blank 3051 // Keyguard. 3052 mNotificationPanel.setTouchDisabled(true); 3053 } 3054 instantExpandNotificationsPanel(); 3055 mLeaveOpenOnKeyguardHide = false; 3056 if (mDraggedDownRow != null) { 3057 mDraggedDownRow.setUserLocked(false); 3058 mDraggedDownRow.notifyHeightChanged(); 3059 mDraggedDownRow = null; 3060 } 3061 } 3062 3063 public boolean isCollapsing() { 3064 return mNotificationPanel.isCollapsing(); 3065 } 3066 3067 public void addPostCollapseAction(Runnable r) { 3068 mPostCollapseRunnables.add(r); 3069 } 3070 3071 public boolean isInLaunchTransition() { 3072 return mNotificationPanel.isLaunchTransitionRunning() 3073 || mNotificationPanel.isLaunchTransitionFinished(); 3074 } 3075 3076 /** 3077 * Fades the content of the keyguard away after the launch transition is done. 3078 * 3079 * @param beforeFading the runnable to be run when the circle is fully expanded and the fading 3080 * starts 3081 * @param endRunnable the runnable to be run when the transition is done 3082 */ 3083 public void fadeKeyguardAfterLaunchTransition(final Runnable beforeFading, 3084 Runnable endRunnable) { 3085 mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT); 3086 mLaunchTransitionEndRunnable = endRunnable; 3087 Runnable hideRunnable = new Runnable() { 3088 @Override 3089 public void run() { 3090 mLaunchTransitionFadingAway = true; 3091 if (beforeFading != null) { 3092 beforeFading.run(); 3093 } 3094 mNotificationPanel.setAlpha(1); 3095 mNotificationPanel.animate() 3096 .alpha(0) 3097 .setStartDelay(FADE_KEYGUARD_START_DELAY) 3098 .setDuration(FADE_KEYGUARD_DURATION) 3099 .withLayer() 3100 .withEndAction(new Runnable() { 3101 @Override 3102 public void run() { 3103 mNotificationPanel.setAlpha(1); 3104 runLaunchTransitionEndRunnable(); 3105 mLaunchTransitionFadingAway = false; 3106 } 3107 }); 3108 } 3109 }; 3110 if (mNotificationPanel.isLaunchTransitionRunning()) { 3111 mNotificationPanel.setLaunchTransitionEndRunnable(hideRunnable); 3112 } else { 3113 hideRunnable.run(); 3114 } 3115 } 3116 3117 /** 3118 * Starts the timeout when we try to start the affordances on Keyguard. We usually rely that 3119 * Keyguard goes away via fadeKeyguardAfterLaunchTransition, however, that might not happen 3120 * because the launched app crashed or something else went wrong. 3121 */ 3122 public void startLaunchTransitionTimeout() { 3123 mHandler.sendEmptyMessageDelayed(MSG_LAUNCH_TRANSITION_TIMEOUT, 3124 LAUNCH_TRANSITION_TIMEOUT_MS); 3125 } 3126 3127 private void onLaunchTransitionTimeout() { 3128 Log.w(TAG, "Launch transition: Timeout!"); 3129 mNotificationPanel.resetViews(); 3130 } 3131 3132 private void runLaunchTransitionEndRunnable() { 3133 if (mLaunchTransitionEndRunnable != null) { 3134 Runnable r = mLaunchTransitionEndRunnable; 3135 3136 // mLaunchTransitionEndRunnable might call showKeyguard, which would execute it again, 3137 // which would lead to infinite recursion. Protect against it. 3138 mLaunchTransitionEndRunnable = null; 3139 r.run(); 3140 } 3141 } 3142 3143 /** 3144 * @return true if we would like to stay in the shade, false if it should go away entirely 3145 */ 3146 public boolean hideKeyguard() { 3147 boolean staying = mLeaveOpenOnKeyguardHide; 3148 setBarState(StatusBarState.SHADE); 3149 if (mLeaveOpenOnKeyguardHide) { 3150 mLeaveOpenOnKeyguardHide = false; 3151 mNotificationPanel.animateToFullShade(calculateGoingToFullShadeDelay()); 3152 if (mDraggedDownRow != null) { 3153 mDraggedDownRow.setUserLocked(false); 3154 mDraggedDownRow = null; 3155 } 3156 } else { 3157 instantCollapseNotificationPanel(); 3158 } 3159 updateKeyguardState(staying, false /* fromShadeLocked */); 3160 3161 // Keyguard state has changed, but QS is not listening anymore. Make sure to update the tile 3162 // visibilities so next time we open the panel we know the correct height already. 3163 if (mQSPanel != null) { 3164 mQSPanel.refreshAllTiles(); 3165 } 3166 mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT); 3167 return staying; 3168 } 3169 3170 public long calculateGoingToFullShadeDelay() { 3171 return mKeyguardFadingAwayDelay + mKeyguardFadingAwayDuration; 3172 } 3173 3174 /** 3175 * Notifies the status bar the Keyguard is fading away with the specified timings. 3176 * 3177 * @param delay the animation delay in miliseconds 3178 * @param fadeoutDuration the duration of the exit animation, in milliseconds 3179 */ 3180 public void setKeyguardFadingAway(long delay, long fadeoutDuration) { 3181 mKeyguardFadingAway = true; 3182 mKeyguardFadingAwayDelay = delay; 3183 mKeyguardFadingAwayDuration = fadeoutDuration; 3184 mWaitingForKeyguardExit = false; 3185 disable(mDisabledUnmodified, true /* animate */); 3186 } 3187 3188 public boolean isKeyguardFadingAway() { 3189 return mKeyguardFadingAway; 3190 } 3191 3192 /** 3193 * Notifies that the Keyguard fading away animation is done. 3194 */ 3195 public void finishKeyguardFadingAway() { 3196 mKeyguardFadingAway = false; 3197 } 3198 3199 private void updatePublicMode() { 3200 setLockscreenPublicMode(mStatusBarKeyguardViewManager.isShowing() 3201 && mStatusBarKeyguardViewManager.isSecure(mCurrentUserId)); 3202 } 3203 3204 private void updateKeyguardState(boolean goingToFullShade, boolean fromShadeLocked) { 3205 if (mState == StatusBarState.KEYGUARD) { 3206 mKeyguardIndicationController.setVisible(true); 3207 mNotificationPanel.resetViews(); 3208 mKeyguardUserSwitcher.setKeyguard(true, fromShadeLocked); 3209 } else { 3210 mKeyguardIndicationController.setVisible(false); 3211 mKeyguardUserSwitcher.setKeyguard(false, 3212 goingToFullShade || mState == StatusBarState.SHADE_LOCKED || fromShadeLocked); 3213 } 3214 if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) { 3215 mScrimController.setKeyguardShowing(true); 3216 } else { 3217 mScrimController.setKeyguardShowing(false); 3218 } 3219 mNotificationPanel.setBarState(mState, mKeyguardFadingAway, goingToFullShade); 3220 updateDozingState(); 3221 updatePublicMode(); 3222 updateStackScrollerState(goingToFullShade); 3223 updateNotifications(); 3224 checkBarModes(); 3225 updateMediaMetaData(false); 3226 mKeyguardMonitor.notifyKeyguardState(mStatusBarKeyguardViewManager.isShowing(), 3227 mStatusBarKeyguardViewManager.isSecure()); 3228 } 3229 3230 private void updateDozingState() { 3231 if (mState != StatusBarState.KEYGUARD && !mNotificationPanel.isDozing()) { 3232 return; 3233 } 3234 boolean animate = !mDozing && mDozeScrimController.isPulsing(); 3235 mNotificationPanel.setDozing(mDozing, animate); 3236 mStackScroller.setDark(mDozing, animate, mScreenOnTouchLocation); 3237 mScrimController.setDozing(mDozing); 3238 mDozeScrimController.setDozing(mDozing, animate); 3239 } 3240 3241 public void updateStackScrollerState(boolean goingToFullShade) { 3242 if (mStackScroller == null) return; 3243 boolean onKeyguard = mState == StatusBarState.KEYGUARD; 3244 mStackScroller.setHideSensitive(isLockscreenPublicMode(), goingToFullShade); 3245 mStackScroller.setDimmed(onKeyguard, false /* animate */); 3246 mStackScroller.setExpandingEnabled(!onKeyguard); 3247 ActivatableNotificationView activatedChild = mStackScroller.getActivatedChild(); 3248 mStackScroller.setActivatedChild(null); 3249 if (activatedChild != null) { 3250 activatedChild.makeInactive(false /* animate */); 3251 } 3252 } 3253 3254 public void userActivity() { 3255 if (mState == StatusBarState.KEYGUARD) { 3256 mKeyguardViewMediatorCallback.userActivity(); 3257 } 3258 } 3259 3260 public boolean interceptMediaKey(KeyEvent event) { 3261 return mState == StatusBarState.KEYGUARD 3262 && mStatusBarKeyguardViewManager.interceptMediaKey(event); 3263 } 3264 3265 public boolean onMenuPressed() { 3266 return mState == StatusBarState.KEYGUARD && mStatusBarKeyguardViewManager.onMenuPressed(); 3267 } 3268 3269 public boolean onBackPressed() { 3270 if (mStatusBarKeyguardViewManager.onBackPressed()) { 3271 return true; 3272 } 3273 if (mNotificationPanel.isQsExpanded()) { 3274 if (mNotificationPanel.isQsDetailShowing()) { 3275 mNotificationPanel.closeQsDetail(); 3276 } else { 3277 mNotificationPanel.animateCloseQs(); 3278 } 3279 return true; 3280 } 3281 if (mState != StatusBarState.KEYGUARD && mState != StatusBarState.SHADE_LOCKED) { 3282 animateCollapsePanels(); 3283 return true; 3284 } 3285 return false; 3286 } 3287 3288 public boolean onSpacePressed() { 3289 if (mScreenOn != null && mScreenOn 3290 && (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)) { 3291 animateCollapsePanels( 3292 CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL /* flags */, true /* force */); 3293 return true; 3294 } 3295 return false; 3296 } 3297 3298 private void showBouncer() { 3299 if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) { 3300 mWaitingForKeyguardExit = mStatusBarKeyguardViewManager.isShowing(); 3301 mStatusBarKeyguardViewManager.dismiss(); 3302 } 3303 } 3304 3305 private void instantExpandNotificationsPanel() { 3306 3307 // Make our window larger and the panel expanded. 3308 makeExpandedVisible(true); 3309 mNotificationPanel.instantExpand(); 3310 } 3311 3312 private void instantCollapseNotificationPanel() { 3313 mNotificationPanel.instantCollapse(); 3314 } 3315 3316 @Override 3317 public void onActivated(ActivatableNotificationView view) { 3318 EventLogTags.writeSysuiLockscreenGesture( 3319 EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_TAP_NOTIFICATION_ACTIVATE, 3320 0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */); 3321 mKeyguardIndicationController.showTransientIndication(R.string.notification_tap_again); 3322 ActivatableNotificationView previousView = mStackScroller.getActivatedChild(); 3323 if (previousView != null) { 3324 previousView.makeInactive(true /* animate */); 3325 } 3326 mStackScroller.setActivatedChild(view); 3327 } 3328 3329 /** 3330 * @param state The {@link StatusBarState} to set. 3331 */ 3332 public void setBarState(int state) { 3333 // If we're visible and switched to SHADE_LOCKED (the user dragged 3334 // down on the lockscreen), clear notification LED, vibration, 3335 // ringing. 3336 // Other transitions are covered in handleVisibleToUserChanged(). 3337 if (state != mState && mVisible && state == StatusBarState.SHADE_LOCKED) { 3338 try { 3339 mBarService.clearNotificationEffects(); 3340 } catch (RemoteException e) { 3341 // Ignore. 3342 } 3343 } 3344 mState = state; 3345 mStatusBarWindowManager.setStatusBarState(state); 3346 } 3347 3348 @Override 3349 public void onActivationReset(ActivatableNotificationView view) { 3350 if (view == mStackScroller.getActivatedChild()) { 3351 mKeyguardIndicationController.hideTransientIndication(); 3352 mStackScroller.setActivatedChild(null); 3353 } 3354 } 3355 3356 public void onTrackingStarted() { 3357 runPostCollapseRunnables(); 3358 } 3359 3360 public void onClosingFinished() { 3361 runPostCollapseRunnables(); 3362 } 3363 3364 public void onUnlockHintStarted() { 3365 mKeyguardIndicationController.showTransientIndication(R.string.keyguard_unlock); 3366 } 3367 3368 public void onHintFinished() { 3369 // Delay the reset a bit so the user can read the text. 3370 mKeyguardIndicationController.hideTransientIndicationDelayed(HINT_RESET_DELAY_MS); 3371 } 3372 3373 public void onCameraHintStarted() { 3374 mKeyguardIndicationController.showTransientIndication(R.string.camera_hint); 3375 } 3376 3377 public void onPhoneHintStarted() { 3378 mKeyguardIndicationController.showTransientIndication(R.string.phone_hint); 3379 } 3380 3381 public void onTrackingStopped(boolean expand) { 3382 if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) { 3383 if (!expand && !mUnlockMethodCache.isCurrentlyInsecure()) { 3384 showBouncer(); 3385 } 3386 } 3387 } 3388 3389 @Override 3390 protected int getMaxKeyguardNotifications() { 3391 return mKeyguardMaxNotificationCount; 3392 } 3393 3394 public NavigationBarView getNavigationBarView() { 3395 return mNavigationBarView; 3396 } 3397 3398 // ---------------------- DragDownHelper.OnDragDownListener ------------------------------------ 3399 3400 @Override 3401 public boolean onDraggedDown(View startingChild, int dragLengthY) { 3402 if (hasActiveNotifications()) { 3403 EventLogTags.writeSysuiLockscreenGesture( 3404 EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_SWIPE_DOWN_FULL_SHADE, 3405 (int) (dragLengthY / mDisplayMetrics.density), 3406 0 /* velocityDp - N/A */); 3407 3408 // We have notifications, go to locked shade. 3409 goToLockedShade(startingChild); 3410 return true; 3411 } else { 3412 3413 // No notifications - abort gesture. 3414 return false; 3415 } 3416 } 3417 3418 @Override 3419 public void onDragDownReset() { 3420 mStackScroller.setDimmed(true /* dimmed */, true /* animated */); 3421 } 3422 3423 @Override 3424 public void onThresholdReached() { 3425 mStackScroller.setDimmed(false /* dimmed */, true /* animate */); 3426 } 3427 3428 @Override 3429 public void onTouchSlopExceeded() { 3430 mStackScroller.removeLongPressCallback(); 3431 } 3432 3433 @Override 3434 public void setEmptyDragAmount(float amount) { 3435 mNotificationPanel.setEmptyDragAmount(amount); 3436 } 3437 3438 /** 3439 * If secure with redaction: Show bouncer, go to unlocked shade. 3440 * 3441 * <p>If secure without redaction or no security: Go to {@link StatusBarState#SHADE_LOCKED}.</p> 3442 * 3443 * @param expandView The view to expand after going to the shade. 3444 */ 3445 public void goToLockedShade(View expandView) { 3446 ExpandableNotificationRow row = null; 3447 if (expandView instanceof ExpandableNotificationRow) { 3448 row = (ExpandableNotificationRow) expandView; 3449 row.setUserExpanded(true); 3450 } 3451 boolean fullShadeNeedsBouncer = !userAllowsPrivateNotificationsInPublic(mCurrentUserId) 3452 || !mShowLockscreenNotifications; 3453 if (isLockscreenPublicMode() && fullShadeNeedsBouncer) { 3454 mLeaveOpenOnKeyguardHide = true; 3455 showBouncer(); 3456 mDraggedDownRow = row; 3457 } else { 3458 mNotificationPanel.animateToFullShade(0 /* delay */); 3459 setBarState(StatusBarState.SHADE_LOCKED); 3460 updateKeyguardState(false /* goingToFullShade */, false /* fromShadeLocked */); 3461 if (row != null) { 3462 row.setUserLocked(false); 3463 } 3464 } 3465 } 3466 3467 /** 3468 * Goes back to the keyguard after hanging around in {@link StatusBarState#SHADE_LOCKED}. 3469 */ 3470 public void goToKeyguard() { 3471 if (mState == StatusBarState.SHADE_LOCKED) { 3472 mStackScroller.onGoToKeyguard(); 3473 setBarState(StatusBarState.KEYGUARD); 3474 updateKeyguardState(false /* goingToFullShade */, true /* fromShadeLocked*/); 3475 } 3476 } 3477 3478 public long getKeyguardFadingAwayDelay() { 3479 return mKeyguardFadingAwayDelay; 3480 } 3481 3482 public long getKeyguardFadingAwayDuration() { 3483 return mKeyguardFadingAwayDuration; 3484 } 3485 3486 @Override 3487 public void setBouncerShowing(boolean bouncerShowing) { 3488 super.setBouncerShowing(bouncerShowing); 3489 disable(mDisabledUnmodified, true /* animate */); 3490 } 3491 3492 public void onScreenTurnedOff() { 3493 mScreenOnFromKeyguard = false; 3494 mScreenOnComingFromTouch = false; 3495 mScreenOnTouchLocation = null; 3496 mStackScroller.setAnimationsEnabled(false); 3497 updateVisibleToUser(); 3498 } 3499 3500 public void onScreenTurnedOn() { 3501 mScreenOnFromKeyguard = true; 3502 mStackScroller.setAnimationsEnabled(true); 3503 mNotificationPanel.onScreenTurnedOn(); 3504 mNotificationPanel.setTouchDisabled(false); 3505 updateVisibleToUser(); 3506 } 3507 3508 /** 3509 * This handles long-press of both back and recents. They are 3510 * handled together to capture them both being long-pressed 3511 * at the same time to exit screen pinning (lock task). 3512 * 3513 * When accessibility mode is on, only a long-press from recents 3514 * is required to exit. 3515 * 3516 * In all other circumstances we try to pass through long-press events 3517 * for Back, so that apps can still use it. Which can be from two things. 3518 * 1) Not currently in screen pinning (lock task). 3519 * 2) Back is long-pressed without recents. 3520 */ 3521 private void handleLongPressBackRecents(View v) { 3522 try { 3523 boolean sendBackLongPress = false; 3524 IActivityManager activityManager = ActivityManagerNative.getDefault(); 3525 boolean isAccessiblityEnabled = mAccessibilityManager.isEnabled(); 3526 if (activityManager.isInLockTaskMode() && !isAccessiblityEnabled) { 3527 long time = System.currentTimeMillis(); 3528 // If we recently long-pressed the other button then they were 3529 // long-pressed 'together' 3530 if ((time - mLastLockToAppLongPress) < LOCK_TO_APP_GESTURE_TOLERENCE) { 3531 activityManager.stopLockTaskModeOnCurrent(); 3532 // When exiting refresh disabled flags. 3533 mNavigationBarView.setDisabledFlags(mDisabled, true); 3534 } else if ((v.getId() == R.id.back) 3535 && !mNavigationBarView.getRecentsButton().isPressed()) { 3536 // If we aren't pressing recents right now then they presses 3537 // won't be together, so send the standard long-press action. 3538 sendBackLongPress = true; 3539 } 3540 mLastLockToAppLongPress = time; 3541 } else { 3542 // If this is back still need to handle sending the long-press event. 3543 if (v.getId() == R.id.back) { 3544 sendBackLongPress = true; 3545 } else if (isAccessiblityEnabled && activityManager.isInLockTaskMode()) { 3546 // When in accessibility mode a long press that is recents (not back) 3547 // should stop lock task. 3548 activityManager.stopLockTaskModeOnCurrent(); 3549 // When exiting refresh disabled flags. 3550 mNavigationBarView.setDisabledFlags(mDisabled, true); 3551 } 3552 } 3553 if (sendBackLongPress) { 3554 KeyButtonView keyButtonView = (KeyButtonView) v; 3555 keyButtonView.sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.FLAG_LONG_PRESS); 3556 keyButtonView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); 3557 } 3558 } catch (RemoteException e) { 3559 Log.d(TAG, "Unable to reach activity manager", e); 3560 } 3561 } 3562 3563 // Recents 3564 3565 @Override 3566 protected void showRecents(boolean triggeredFromAltTab) { 3567 // Set the recents visibility flag 3568 mSystemUiVisibility |= View.RECENT_APPS_VISIBLE; 3569 notifyUiVisibilityChanged(mSystemUiVisibility); 3570 super.showRecents(triggeredFromAltTab); 3571 } 3572 3573 @Override 3574 protected void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) { 3575 // Unset the recents visibility flag 3576 mSystemUiVisibility &= ~View.RECENT_APPS_VISIBLE; 3577 notifyUiVisibilityChanged(mSystemUiVisibility); 3578 super.hideRecents(triggeredFromAltTab, triggeredFromHomeKey); 3579 } 3580 3581 @Override 3582 protected void toggleRecents() { 3583 // Toggle the recents visibility flag 3584 mSystemUiVisibility ^= View.RECENT_APPS_VISIBLE; 3585 notifyUiVisibilityChanged(mSystemUiVisibility); 3586 super.toggleRecents(); 3587 } 3588 3589 @Override 3590 public void onVisibilityChanged(boolean visible) { 3591 // Update the recents visibility flag 3592 if (visible) { 3593 mSystemUiVisibility |= View.RECENT_APPS_VISIBLE; 3594 } else { 3595 mSystemUiVisibility &= ~View.RECENT_APPS_VISIBLE; 3596 } 3597 notifyUiVisibilityChanged(mSystemUiVisibility); 3598 } 3599 3600 @Override 3601 public void showScreenPinningRequest() { 3602 if (mKeyguardMonitor.isShowing()) { 3603 // Don't allow apps to trigger this from keyguard. 3604 return; 3605 } 3606 // Show screen pinning request, since this comes from an app, show 'no thanks', button. 3607 showScreenPinningRequest(true); 3608 } 3609 3610 public void showScreenPinningRequest(boolean allowCancel) { 3611 mScreenPinningRequest.showPrompt(allowCancel); 3612 } 3613 3614 public boolean hasActiveNotifications() { 3615 return !mNotificationData.getActiveNotifications().isEmpty(); 3616 } 3617 3618 public void wakeUpIfDozing(long time, MotionEvent event) { 3619 if (mDozing && mDozeScrimController.isPulsing()) { 3620 PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 3621 pm.wakeUp(time); 3622 mScreenOnComingFromTouch = true; 3623 mScreenOnTouchLocation = new PointF(event.getX(), event.getY()); 3624 mNotificationPanel.setTouchDisabled(false); 3625 } 3626 } 3627 3628 private final class ShadeUpdates { 3629 private final ArraySet<String> mVisibleNotifications = new ArraySet<String>(); 3630 private final ArraySet<String> mNewVisibleNotifications = new ArraySet<String>(); 3631 3632 public void check() { 3633 mNewVisibleNotifications.clear(); 3634 ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications(); 3635 for (int i = 0; i < activeNotifications.size(); i++) { 3636 final Entry entry = activeNotifications.get(i); 3637 final boolean visible = entry.row != null 3638 && entry.row.getVisibility() == View.VISIBLE; 3639 if (visible) { 3640 mNewVisibleNotifications.add(entry.key + entry.notification.getPostTime()); 3641 } 3642 } 3643 final boolean updates = !mVisibleNotifications.containsAll(mNewVisibleNotifications); 3644 mVisibleNotifications.clear(); 3645 mVisibleNotifications.addAll(mNewVisibleNotifications); 3646 3647 // We have new notifications 3648 if (updates && mDozeServiceHost != null) { 3649 mDozeServiceHost.fireNewNotifications(); 3650 } 3651 } 3652 } 3653 3654 private final class DozeServiceHost implements DozeHost { 3655 // Amount of time to allow to update the time shown on the screen before releasing 3656 // the wakelock. This timeout is design to compensate for the fact that we don't 3657 // currently have a way to know when time display contents have actually been 3658 // refreshed once we've finished rendering a new frame. 3659 private static final long PROCESSING_TIME = 500; 3660 3661 private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>(); 3662 private final H mHandler = new H(); 3663 3664 // Keeps the last reported state by fireNotificationLight. 3665 private boolean mNotificationLightOn; 3666 3667 @Override 3668 public String toString() { 3669 return "PSB.DozeServiceHost[mCallbacks=" + mCallbacks.size() + "]"; 3670 } 3671 3672 public void firePowerSaveChanged(boolean active) { 3673 for (Callback callback : mCallbacks) { 3674 callback.onPowerSaveChanged(active); 3675 } 3676 } 3677 3678 public void fireBuzzBeepBlinked() { 3679 for (Callback callback : mCallbacks) { 3680 callback.onBuzzBeepBlinked(); 3681 } 3682 } 3683 3684 public void fireNotificationLight(boolean on) { 3685 mNotificationLightOn = on; 3686 for (Callback callback : mCallbacks) { 3687 callback.onNotificationLight(on); 3688 } 3689 } 3690 3691 public void fireNewNotifications() { 3692 for (Callback callback : mCallbacks) { 3693 callback.onNewNotifications(); 3694 } 3695 } 3696 3697 @Override 3698 public void addCallback(@NonNull Callback callback) { 3699 mCallbacks.add(callback); 3700 } 3701 3702 @Override 3703 public void removeCallback(@NonNull Callback callback) { 3704 mCallbacks.remove(callback); 3705 } 3706 3707 @Override 3708 public void startDozing(@NonNull Runnable ready) { 3709 mHandler.obtainMessage(H.MSG_START_DOZING, ready).sendToTarget(); 3710 } 3711 3712 @Override 3713 public void pulseWhileDozing(@NonNull PulseCallback callback, int reason) { 3714 mHandler.obtainMessage(H.MSG_PULSE_WHILE_DOZING, reason, 0, callback).sendToTarget(); 3715 } 3716 3717 @Override 3718 public void stopDozing() { 3719 mHandler.obtainMessage(H.MSG_STOP_DOZING).sendToTarget(); 3720 } 3721 3722 @Override 3723 public boolean isPowerSaveActive() { 3724 return mBatteryController != null && mBatteryController.isPowerSave(); 3725 } 3726 3727 @Override 3728 public boolean isNotificationLightOn() { 3729 return mNotificationLightOn; 3730 } 3731 3732 private void handleStartDozing(@NonNull Runnable ready) { 3733 if (!mDozing) { 3734 mDozing = true; 3735 DozeLog.traceDozing(mContext, mDozing); 3736 updateDozingState(); 3737 } 3738 ready.run(); 3739 } 3740 3741 private void handlePulseWhileDozing(@NonNull PulseCallback callback, int reason) { 3742 mDozeScrimController.pulse(callback, reason); 3743 } 3744 3745 private void handleStopDozing() { 3746 if (mDozing) { 3747 mDozing = false; 3748 DozeLog.traceDozing(mContext, mDozing); 3749 updateDozingState(); 3750 } 3751 } 3752 3753 private final class H extends Handler { 3754 private static final int MSG_START_DOZING = 1; 3755 private static final int MSG_PULSE_WHILE_DOZING = 2; 3756 private static final int MSG_STOP_DOZING = 3; 3757 3758 @Override 3759 public void handleMessage(Message msg) { 3760 switch (msg.what) { 3761 case MSG_START_DOZING: 3762 handleStartDozing((Runnable) msg.obj); 3763 break; 3764 case MSG_PULSE_WHILE_DOZING: 3765 handlePulseWhileDozing((PulseCallback) msg.obj, msg.arg1); 3766 break; 3767 case MSG_STOP_DOZING: 3768 handleStopDozing(); 3769 break; 3770 } 3771 } 3772 } 3773 } 3774} 3775