2 * Copyright (C) 2010 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.systemui.statusbar.phone;
20 import android.animation.Animator;
21 import android.animation.AnimatorListenerAdapter;
22 import android.annotation.NonNull;
23 import android.app.ActivityManager;
24 import android.app.ActivityManagerNative;
25 import android.app.IActivityManager;
26 import android.app.Notification;
27 import android.app.PendingIntent;
28 import android.app.StatusBarManager;
29 import android.content.BroadcastReceiver;
30 import android.content.ComponentCallbacks2;
31 import android.content.ComponentName;
32 import android.content.Context;
33 import android.content.Intent;
34 import android.content.IntentFilter;
35 import android.content.pm.IPackageManager;
36 import android.content.pm.PackageManager;
37 import android.content.res.Configuration;
38 import android.content.res.Resources;
39 import android.database.ContentObserver;
40 import android.graphics.Bitmap;
41 import android.graphics.Canvas;
42 import android.graphics.ColorFilter;
43 import android.graphics.PixelFormat;
44 import android.graphics.Point;
45 import android.graphics.PointF;
46 import android.graphics.PorterDuff;
47 import android.graphics.PorterDuffXfermode;
48 import android.graphics.Rect;
49 import android.graphics.drawable.BitmapDrawable;
50 import android.graphics.drawable.ColorDrawable;
51 import android.graphics.drawable.Drawable;
52 import android.inputmethodservice.InputMethodService;
53 import android.media.AudioAttributes;
54 import android.media.MediaMetadata;
55 import android.media.session.MediaController;
56 import android.media.session.MediaSession;
57 import android.media.session.MediaSessionManager;
58 import android.media.session.PlaybackState;
59 import android.os.AsyncTask;
60 import android.os.Bundle;
61 import android.os.Handler;
62 import android.os.HandlerThread;
63 import android.os.IBinder;
64 import android.os.Message;
65 import android.os.PowerManager;
66 import android.os.Process;
67 import android.os.RemoteException;
68 import android.os.ServiceManager;
69 import android.os.SystemClock;
70 import android.os.UserHandle;
71 import android.os.UserManager;
72 import android.os.Vibrator;
73 import android.provider.Settings;
74 import android.service.notification.NotificationListenerService;
75 import android.service.notification.NotificationListenerService.RankingMap;
76 import android.service.notification.StatusBarNotification;
77 import android.util.ArraySet;
78 import android.util.DisplayMetrics;
79 import android.util.EventLog;
80 import android.util.Log;
81 import android.view.Display;
82 import android.view.KeyEvent;
83 import android.view.LayoutInflater;
84 import android.view.MotionEvent;
85 import android.view.ThreadedRenderer;
86 import android.view.View;
87 import android.view.ViewGroup;
88 import android.view.ViewGroup.LayoutParams;
89 import android.view.ViewStub;
90 import android.view.WindowManager;
91 import android.view.WindowManagerGlobal;
92 import android.view.animation.AccelerateInterpolator;
93 import android.view.animation.Interpolator;
94 import android.widget.ImageView;
95 import android.widget.TextView;
96 import com.android.internal.logging.MetricsLogger;
97 import com.android.internal.logging.MetricsProto.MetricsEvent;
98 import com.android.internal.statusbar.NotificationVisibility;
99 import com.android.internal.statusbar.StatusBarIcon;
100 import com.android.keyguard.KeyguardHostView.OnDismissAction;
101 import com.android.keyguard.KeyguardUpdateMonitor;
102 import com.android.keyguard.KeyguardUpdateMonitorCallback;
103 import com.android.keyguard.ViewMediatorCallback;
104 import com.android.systemui.BatteryMeterView;
105 import com.android.systemui.DemoMode;
106 import com.android.systemui.DensityContainer;
107 import com.android.systemui.DensityContainer.InflateListener;
108 import com.android.systemui.EventLogConstants;
109 import com.android.systemui.EventLogTags;
110 import com.android.systemui.Interpolators;
111 import com.android.systemui.Prefs;
112 import com.android.systemui.R;
113 import com.android.systemui.SystemUIFactory;
114 import com.android.systemui.assist.AssistManager;
115 import com.android.systemui.classifier.FalsingLog;
116 import com.android.systemui.classifier.FalsingManager;
117 import com.android.systemui.doze.DozeHost;
118 import com.android.systemui.doze.DozeLog;
119 import com.android.systemui.keyguard.KeyguardViewMediator;
120 import com.android.systemui.qs.QSContainer;
121 import com.android.systemui.qs.QSPanel;
122 import com.android.systemui.recents.ScreenPinningRequest;
123 import com.android.systemui.recents.events.EventBus;
124 import com.android.systemui.recents.events.activity.AppTransitionFinishedEvent;
125 import com.android.systemui.recents.events.activity.UndockingTaskEvent;
126 import com.android.systemui.stackdivider.Divider;
127 import com.android.systemui.stackdivider.WindowManagerProxy;
128 import com.android.systemui.statusbar.ActivatableNotificationView;
129 import com.android.systemui.statusbar.BackDropView;
130 import com.android.systemui.statusbar.BaseStatusBar;
131 import com.android.systemui.statusbar.CommandQueue;
132 import com.android.systemui.statusbar.DismissView;
133 import com.android.systemui.statusbar.DragDownHelper;
134 import com.android.systemui.statusbar.EmptyShadeView;
135 import com.android.systemui.statusbar.ExpandableNotificationRow;
136 import com.android.systemui.statusbar.GestureRecorder;
137 import com.android.systemui.statusbar.KeyboardShortcuts;
138 import com.android.systemui.statusbar.KeyguardIndicationController;
139 import com.android.systemui.statusbar.NotificationData;
140 import com.android.systemui.statusbar.NotificationData.Entry;
141 import com.android.systemui.statusbar.NotificationOverflowContainer;
142 import com.android.systemui.statusbar.RemoteInputController;
143 import com.android.systemui.statusbar.ScrimView;
144 import com.android.systemui.statusbar.SignalClusterView;
145 import com.android.systemui.statusbar.StatusBarState;
146 import com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChangedListener;
147 import com.android.systemui.statusbar.policy.AccessibilityController;
148 import com.android.systemui.statusbar.policy.BatteryController;
149 import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
150 import com.android.systemui.statusbar.policy.BatteryControllerImpl;
151 import com.android.systemui.statusbar.policy.BluetoothControllerImpl;
152 import com.android.systemui.statusbar.policy.BrightnessMirrorController;
153 import com.android.systemui.statusbar.policy.CastControllerImpl;
154 import com.android.systemui.statusbar.policy.FlashlightController;
155 import com.android.systemui.statusbar.policy.HeadsUpManager;
156 import com.android.systemui.statusbar.policy.HotspotControllerImpl;
157 import com.android.systemui.statusbar.policy.KeyguardMonitor;
158 import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
159 import com.android.systemui.statusbar.policy.LocationControllerImpl;
160 import com.android.systemui.statusbar.policy.NetworkControllerImpl;
161 import com.android.systemui.statusbar.policy.NextAlarmController;
162 import com.android.systemui.statusbar.policy.PreviewInflater;
163 import com.android.systemui.statusbar.policy.RotationLockControllerImpl;
164 import com.android.systemui.statusbar.policy.SecurityControllerImpl;
165 import com.android.systemui.statusbar.policy.UserInfoController;
166 import com.android.systemui.statusbar.policy.UserSwitcherController;
167 import com.android.systemui.statusbar.policy.ZenModeController;
168 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
169 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout.OnChildLocationsChangedListener;
170 import com.android.systemui.statusbar.stack.StackStateAnimator;
171 import com.android.systemui.statusbar.stack.StackViewState;
172 import com.android.systemui.volume.VolumeComponent;
174 import java.io.FileDescriptor;
175 import java.io.PrintWriter;
176 import java.util.ArrayList;
177 import java.util.Collection;
178 import java.util.Collections;
179 import java.util.HashMap;
180 import java.util.List;
181 import java.util.Map;
183 import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT;
184 import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN;
185 import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
186 import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
187 import static android.app.StatusBarManager.windowStateToString;
188 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
189 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
190 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
191 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
192 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSLUCENT;
193 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
194 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_WARNING;
196 public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
197 DragDownHelper.DragDownCallback, ActivityStarter, OnUnlockMethodChangedListener,
198 HeadsUpManager.OnHeadsUpChangedListener {
199 static final String TAG = "PhoneStatusBar";
200 public static final boolean DEBUG = BaseStatusBar.DEBUG;
201 public static final boolean SPEW = false;
202 public static final boolean DUMPTRUCK = true; // extra dumpsys info
203 public static final boolean DEBUG_GESTURES = false;
204 public static final boolean DEBUG_MEDIA = false;
205 public static final boolean DEBUG_MEDIA_FAKE_ARTWORK = false;
207 public static final boolean DEBUG_WINDOW_STATE = false;
209 // additional instrumentation for testing purposes; intended to be left on during development
210 public static final boolean CHATTY = DEBUG;
212 public static final boolean SHOW_LOCKSCREEN_MEDIA_ARTWORK = true;
214 public static final String ACTION_FAKE_ARTWORK = "fake_artwork";
216 private static final int MSG_OPEN_NOTIFICATION_PANEL = 1000;
217 private static final int MSG_CLOSE_PANELS = 1001;
218 private static final int MSG_OPEN_SETTINGS_PANEL = 1002;
219 private static final int MSG_LAUNCH_TRANSITION_TIMEOUT = 1003;
220 // 1020-1040 reserved for BaseStatusBar
222 // Time after we abort the launch transition.
223 private static final long LAUNCH_TRANSITION_TIMEOUT_MS = 5000;
225 private static final boolean CLOSE_PANEL_WHEN_EMPTIED = true;
227 private static final int STATUS_OR_NAV_TRANSIENT =
228 View.STATUS_BAR_TRANSIENT | View.NAVIGATION_BAR_TRANSIENT;
229 private static final long AUTOHIDE_TIMEOUT_MS = 3000;
231 /** The minimum delay in ms between reports of notification visibility. */
232 private static final int VISIBILITY_REPORT_MIN_DELAY_MS = 500;
235 * The delay to reset the hint text when the hint animation is finished running.
237 private static final int HINT_RESET_DELAY_MS = 1200;
239 private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
240 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
241 .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
244 public static final int FADE_KEYGUARD_START_DELAY = 100;
245 public static final int FADE_KEYGUARD_DURATION = 300;
246 public static final int FADE_KEYGUARD_DURATION_PULSING = 96;
248 /** Allow some time inbetween the long press for back and recents. */
249 private static final int LOCK_TO_APP_GESTURE_TOLERENCE = 200;
251 /** If true, the system is in the half-boot-to-decryption-screen state.
252 * Prudently disable QS and notifications. */
253 private static final boolean ONLY_CORE_APPS;
255 /** If true, the lockscreen will show a distinct wallpaper */
256 private static final boolean ENABLE_LOCKSCREEN_WALLPAPER = true;
258 /* If true, the device supports freeform window management.
259 * This affects the status bar UI. */
260 private static final boolean FREEFORM_WINDOW_MANAGEMENT;
263 boolean onlyCoreApps;
264 boolean freeformWindowManagement;
266 IPackageManager packageManager =
267 IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
268 onlyCoreApps = packageManager.isOnlyCoreApps();
269 freeformWindowManagement = packageManager.hasSystemFeature(
270 PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT, 0);
271 } catch (RemoteException e) {
272 onlyCoreApps = false;
273 freeformWindowManagement = false;
275 ONLY_CORE_APPS = onlyCoreApps;
276 FREEFORM_WINDOW_MANAGEMENT = freeformWindowManagement;
279 PhoneStatusBarPolicy mIconPolicy;
281 // These are no longer handled by the policy, because we need custom strategies for them
282 BluetoothControllerImpl mBluetoothController;
283 SecurityControllerImpl mSecurityController;
284 protected BatteryController mBatteryController;
285 LocationControllerImpl mLocationController;
286 NetworkControllerImpl mNetworkController;
287 HotspotControllerImpl mHotspotController;
288 RotationLockControllerImpl mRotationLockController;
289 UserInfoController mUserInfoController;
290 protected ZenModeController mZenModeController;
291 CastControllerImpl mCastController;
292 VolumeComponent mVolumeComponent;
293 KeyguardUserSwitcher mKeyguardUserSwitcher;
294 FlashlightController mFlashlightController;
295 protected UserSwitcherController mUserSwitcherController;
296 NextAlarmController mNextAlarmController;
297 protected KeyguardMonitor mKeyguardMonitor;
298 BrightnessMirrorController mBrightnessMirrorController;
299 AccessibilityController mAccessibilityController;
300 FingerprintUnlockController mFingerprintUnlockController;
301 LightStatusBarController mLightStatusBarController;
302 protected LockscreenWallpaper mLockscreenWallpaper;
304 int mNaturalBarHeight = -1;
307 Point mCurrentDisplaySize = new Point();
309 protected StatusBarWindowView mStatusBarWindow;
310 protected PhoneStatusBarView mStatusBarView;
311 private int mStatusBarWindowState = WINDOW_STATE_SHOWING;
312 protected StatusBarWindowManager mStatusBarWindowManager;
313 private UnlockMethodCache mUnlockMethodCache;
314 private DozeServiceHost mDozeServiceHost;
315 private boolean mWakeUpComingFromTouch;
316 private PointF mWakeUpTouchLocation;
317 private boolean mScreenTurningOn;
320 Object mQueueLock = new Object();
322 protected StatusBarIconController mIconController;
324 // expanded notifications
325 protected NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
326 View mExpandedContents;
327 TextView mNotificationPanelDebugText;
330 private QSPanel mQSPanel;
333 BaseStatusBarHeader mHeader;
334 protected KeyguardStatusBarView mKeyguardStatusBar;
335 View mKeyguardStatusView;
336 KeyguardBottomAreaView mKeyguardBottomArea;
337 boolean mLeaveOpenOnKeyguardHide;
338 KeyguardIndicationController mKeyguardIndicationController;
340 // Keyguard is going away soon.
341 private boolean mKeyguardGoingAway;
342 // Keyguard is actually fading away now.
343 private boolean mKeyguardFadingAway;
344 private long mKeyguardFadingAwayDelay;
345 private long mKeyguardFadingAwayDuration;
347 // RemoteInputView to be activated after unlock
348 private View mPendingRemoteInputView;
350 int mMaxAllowedKeyguardNotifications;
352 boolean mExpandedVisible;
354 private int mNavigationBarWindowState = WINDOW_STATE_SHOWING;
357 int mTrackingPosition; // the position of the top of the tracking view.
359 // Tracking finger for opening/closing.
362 int[] mAbsPos = new int[2];
363 ArrayList<Runnable> mPostCollapseRunnables = new ArrayList<>();
365 // for disabling the status bar
369 // tracking calls to View.setSystemUiVisibility()
370 int mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE;
371 private final Rect mLastFullscreenStackBounds = new Rect();
372 private final Rect mLastDockedStackBounds = new Rect();
374 // last value sent to window manager
375 private int mLastDispatchedSystemUiVisibility = ~View.SYSTEM_UI_FLAG_VISIBLE;
377 DisplayMetrics mDisplayMetrics = new DisplayMetrics();
379 // XXX: gesture research
380 private final GestureRecorder mGestureRec = DEBUG_GESTURES
381 ? new GestureRecorder("/sdcard/statusbar_gestures.dat")
384 private ScreenPinningRequest mScreenPinningRequest;
386 private int mNavigationIconHints = 0;
387 private HandlerThread mHandlerThread;
389 // ensure quick settings is disabled until the current user makes it through the setup wizard
390 private boolean mUserSetup = false;
391 private ContentObserver mUserSetupObserver = new ContentObserver(new Handler()) {
393 public void onChange(boolean selfChange) {
394 final boolean userSetup = 0 != Settings.Secure.getIntForUser(
395 mContext.getContentResolver(),
396 Settings.Secure.USER_SETUP_COMPLETE,
399 if (MULTIUSER_DEBUG) Log.d(TAG, String.format("User setup changed: " +
400 "selfChange=%s userSetup=%s mUserSetup=%s",
401 selfChange, userSetup, mUserSetup));
403 if (userSetup != mUserSetup) {
404 mUserSetup = userSetup;
405 if (!mUserSetup && mStatusBarView != null)
406 animateCollapseQuickSettings();
407 if (mKeyguardBottomArea != null) {
408 mKeyguardBottomArea.setUserSetupComplete(mUserSetup);
411 if (mIconPolicy != null) {
412 mIconPolicy.setCurrentUserSetup(mUserSetup);
417 final private ContentObserver mHeadsUpObserver = new ContentObserver(mHandler) {
419 public void onChange(boolean selfChange) {
420 boolean wasUsing = mUseHeadsUp;
421 mUseHeadsUp = ENABLE_HEADS_UP && !mDisableNotificationAlerts
422 && Settings.Global.HEADS_UP_OFF != Settings.Global.getInt(
423 mContext.getContentResolver(), Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED,
424 Settings.Global.HEADS_UP_OFF);
425 mHeadsUpTicker = mUseHeadsUp && 0 != Settings.Global.getInt(
426 mContext.getContentResolver(), SETTING_HEADS_UP_TICKER, 0);
427 Log.d(TAG, "heads up is " + (mUseHeadsUp ? "enabled" : "disabled"));
428 if (wasUsing != mUseHeadsUp) {
430 Log.d(TAG, "dismissing any existing heads up notification on disable event");
431 mHeadsUpManager.releaseAllImmediately();
437 private int mInteractingWindows;
438 private boolean mAutohideSuspended;
439 private int mStatusBarMode;
440 private int mNavigationBarMode;
441 private int mMaxKeyguardNotifications;
443 private ViewMediatorCallback mKeyguardViewMediatorCallback;
444 protected ScrimController mScrimController;
445 protected DozeScrimController mDozeScrimController;
447 private final Runnable mAutohide = new Runnable() {
450 int requested = mSystemUiVisibility & ~STATUS_OR_NAV_TRANSIENT;
451 if (mSystemUiVisibility != requested) {
452 notifyUiVisibilityChanged(requested);
456 private boolean mWaitingForKeyguardExit;
457 private boolean mDozing;
458 private boolean mDozingRequested;
459 protected boolean mScrimSrcModeEnabled;
461 public static final Interpolator ALPHA_IN = Interpolators.ALPHA_IN;
462 public static final Interpolator ALPHA_OUT = Interpolators.ALPHA_OUT;
464 private BackDropView mBackdrop;
465 private ImageView mBackdropFront, mBackdropBack;
466 private PorterDuffXfermode mSrcXferMode = new PorterDuffXfermode(PorterDuff.Mode.SRC);
467 private PorterDuffXfermode mSrcOverXferMode = new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER);
469 private MediaSessionManager mMediaSessionManager;
470 private MediaController mMediaController;
471 private String mMediaNotificationKey;
472 private MediaMetadata mMediaMetadata;
473 private MediaController.Callback mMediaListener
474 = new MediaController.Callback() {
476 public void onPlaybackStateChanged(PlaybackState state) {
477 super.onPlaybackStateChanged(state);
478 if (DEBUG_MEDIA) Log.v(TAG, "DEBUG_MEDIA: onPlaybackStateChanged: " + state);
480 if (!isPlaybackActive(state.getState())) {
481 clearCurrentMediaNotification();
482 updateMediaMetaData(true, true);
488 public void onMetadataChanged(MediaMetadata metadata) {
489 super.onMetadataChanged(metadata);
490 if (DEBUG_MEDIA) Log.v(TAG, "DEBUG_MEDIA: onMetadataChanged: " + metadata);
491 mMediaMetadata = metadata;
492 updateMediaMetaData(true, true);
496 private final OnChildLocationsChangedListener mOnChildLocationsChangedListener =
497 new OnChildLocationsChangedListener() {
499 public void onChildLocationsChanged(NotificationStackScrollLayout stackScrollLayout) {
504 private int mDisabledUnmodified1;
505 private int mDisabledUnmodified2;
507 /** Keys of notifications currently visible to the user. */
508 private final ArraySet<NotificationVisibility> mCurrentlyVisibleNotifications =
510 private long mLastVisibilityReportUptimeMs;
512 private final ShadeUpdates mShadeUpdates = new ShadeUpdates();
514 private Runnable mLaunchTransitionEndRunnable;
515 private boolean mLaunchTransitionFadingAway;
516 private ExpandableNotificationRow mDraggedDownRow;
517 private boolean mLaunchCameraOnScreenTurningOn;
518 private boolean mLaunchCameraOnFinishedGoingToSleep;
519 private int mLastCameraLaunchSource;
520 private PowerManager.WakeLock mGestureWakeLock;
521 private Vibrator mVibrator;
523 // Fingerprint (as computed by getLoggingFingerprint() of the last logged state.
524 private int mLastLoggedStateFingerprint;
527 * If set, the device has started going to sleep but isn't fully non-interactive yet.
529 protected boolean mStartedGoingToSleep;
531 private static final int VISIBLE_LOCATIONS = StackViewState.LOCATION_FIRST_HUN
532 | StackViewState.LOCATION_MAIN_AREA;
534 private final OnChildLocationsChangedListener mNotificationLocationsChangedListener =
535 new OnChildLocationsChangedListener() {
537 public void onChildLocationsChanged(
538 NotificationStackScrollLayout stackScrollLayout) {
539 if (mHandler.hasCallbacks(mVisibilityReporter)) {
540 // Visibilities will be reported when the existing
541 // callback is executed.
544 // Calculate when we're allowed to run the visibility
545 // reporter. Note that this timestamp might already have
546 // passed. That's OK, the callback will just be executed
548 long nextReportUptimeMs =
549 mLastVisibilityReportUptimeMs + VISIBILITY_REPORT_MIN_DELAY_MS;
550 mHandler.postAtTime(mVisibilityReporter, nextReportUptimeMs);
554 // Tracks notifications currently visible in mNotificationStackScroller and
555 // emits visibility events via NoMan on changes.
556 private final Runnable mVisibilityReporter = new Runnable() {
557 private final ArraySet<NotificationVisibility> mTmpNewlyVisibleNotifications =
559 private final ArraySet<NotificationVisibility> mTmpCurrentlyVisibleNotifications =
561 private final ArraySet<NotificationVisibility> mTmpNoLongerVisibleNotifications =
566 mLastVisibilityReportUptimeMs = SystemClock.uptimeMillis();
567 final String mediaKey = getCurrentMediaNotificationKey();
569 // 1. Loop over mNotificationData entries:
570 // A. Keep list of visible notifications.
571 // B. Keep list of previously hidden, now visible notifications.
572 // 2. Compute no-longer visible notifications by removing currently
573 // visible notifications from the set of previously visible
575 // 3. Report newly visible and no-longer visible notifications.
576 // 4. Keep currently visible notifications for next report.
577 ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
578 int N = activeNotifications.size();
579 for (int i = 0; i < N; i++) {
580 Entry entry = activeNotifications.get(i);
581 String key = entry.notification.getKey();
583 (mStackScroller.getChildLocation(entry.row) & VISIBLE_LOCATIONS) != 0;
584 NotificationVisibility visObj = NotificationVisibility.obtain(key, i, isVisible);
585 boolean previouslyVisible = mCurrentlyVisibleNotifications.contains(visObj);
587 // Build new set of visible notifications.
588 mTmpCurrentlyVisibleNotifications.add(visObj);
589 if (!previouslyVisible) {
590 mTmpNewlyVisibleNotifications.add(visObj);
597 mTmpNoLongerVisibleNotifications.addAll(mCurrentlyVisibleNotifications);
598 mTmpNoLongerVisibleNotifications.removeAll(mTmpCurrentlyVisibleNotifications);
600 logNotificationVisibilityChanges(
601 mTmpNewlyVisibleNotifications, mTmpNoLongerVisibleNotifications);
603 recycleAllVisibilityObjects(mCurrentlyVisibleNotifications);
604 mCurrentlyVisibleNotifications.addAll(mTmpCurrentlyVisibleNotifications);
606 recycleAllVisibilityObjects(mTmpNoLongerVisibleNotifications);
607 mTmpCurrentlyVisibleNotifications.clear();
608 mTmpNewlyVisibleNotifications.clear();
609 mTmpNoLongerVisibleNotifications.clear();
613 private void recycleAllVisibilityObjects(ArraySet<NotificationVisibility> array) {
614 final int N = array.size();
615 for (int i = 0 ; i < N; i++) {
616 array.valueAt(i).recycle();
621 private final View.OnClickListener mOverflowClickListener = new View.OnClickListener() {
623 public void onClick(View v) {
624 goToLockedShade(null);
627 private HashMap<ExpandableNotificationRow, List<ExpandableNotificationRow>> mTmpChildOrderMap
629 private RankingMap mLatestRankingMap;
630 private boolean mNoAnimationOnNextBarModeChange;
631 private FalsingManager mFalsingManager;
634 public void start() {
635 mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
636 .getDefaultDisplay();
638 mScrimSrcModeEnabled = mContext.getResources().getBoolean(
639 R.bool.config_status_bar_scrim_behind_use_src);
641 super.start(); // calls createAndAddWindows()
644 = (MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE);
645 // TODO: use MediaSessionManager.SessionListener to hook us up to future updates
650 // Lastly, call to the icon policy to install/update all the icons.
651 mIconPolicy = new PhoneStatusBarPolicy(mContext, mIconController, mCastController,
652 mHotspotController, mUserInfoController, mBluetoothController,
653 mRotationLockController, mNetworkController.getDataSaverController());
654 mIconPolicy.setCurrentUserSetup(mUserSetup);
655 mSettingsObserver.onChange(false); // set up
657 mHeadsUpObserver.onChange(true); // set up
658 if (ENABLE_HEADS_UP) {
659 mContext.getContentResolver().registerContentObserver(
660 Settings.Global.getUriFor(Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED), true,
662 mContext.getContentResolver().registerContentObserver(
663 Settings.Global.getUriFor(SETTING_HEADS_UP_TICKER), true,
666 mUnlockMethodCache = UnlockMethodCache.getInstance(mContext);
667 mUnlockMethodCache.addListener(this);
670 mDozeServiceHost = new DozeServiceHost();
671 KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mDozeServiceHost);
672 putComponent(DozeHost.class, mDozeServiceHost);
673 putComponent(PhoneStatusBar.class, this);
675 setControllerUsers();
677 notifyUserAboutHiddenNotifications();
679 mScreenPinningRequest = new ScreenPinningRequest(mContext);
680 mFalsingManager = FalsingManager.getInstance(mContext);
683 protected void createIconController() {
684 mIconController = new StatusBarIconController(
685 mContext, mStatusBarView, mKeyguardStatusBar, this);
688 // ================================================================================
689 // Constructing the view
690 // ================================================================================
691 protected PhoneStatusBarView makeStatusBarView() {
692 final Context context = mContext;
694 updateDisplaySize(); // populates mDisplayMetrics
697 inflateStatusBarWindow(context);
698 mStatusBarWindow.setService(this);
699 mStatusBarWindow.setOnTouchListener(new View.OnTouchListener() {
701 public boolean onTouch(View v, MotionEvent event) {
702 checkUserAutohide(v, event);
703 if (event.getAction() == MotionEvent.ACTION_DOWN) {
704 if (mExpandedVisible) {
705 animateCollapsePanels();
708 return mStatusBarWindow.onTouchEvent(event);
712 mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById(
713 R.id.notification_panel);
714 mNotificationPanel.setStatusBar(this);
715 mNotificationPanel.setGroupManager(mGroupManager);
717 mStatusBarView = (PhoneStatusBarView) mStatusBarWindow.findViewById(R.id.status_bar);
718 mStatusBarView.setBar(this);
719 mStatusBarView.setPanel(mNotificationPanel);
721 if (!ActivityManager.isHighEndGfx()) {
722 mStatusBarWindow.setBackground(null);
723 mNotificationPanel.setBackground(new FastColorDrawable(context.getColor(
724 R.color.notification_panel_solid_background)));
727 mHeadsUpManager = new HeadsUpManager(context, mStatusBarWindow, mGroupManager);
728 mHeadsUpManager.setBar(this);
729 mHeadsUpManager.addListener(this);
730 mHeadsUpManager.addListener(mNotificationPanel);
731 mHeadsUpManager.addListener(mGroupManager);
732 mNotificationPanel.setHeadsUpManager(mHeadsUpManager);
733 mNotificationData.setHeadsUpManager(mHeadsUpManager);
734 mGroupManager.setHeadsUpManager(mHeadsUpManager);
736 if (MULTIUSER_DEBUG) {
737 mNotificationPanelDebugText = (TextView) mNotificationPanel.findViewById(
738 R.id.header_debug_info);
739 mNotificationPanelDebugText.setVisibility(View.VISIBLE);
743 boolean showNav = mWindowManagerService.hasNavigationBar();
744 if (DEBUG) Log.v(TAG, "hasNavigationBar=" + showNav);
746 createNavigationBarView(context);
748 } catch (RemoteException ex) {
749 // no window manager? good luck with that
752 mAssistManager = new AssistManager(this, context);
754 // figure out which pixel-format to use for the status bar.
755 mPixelFormat = PixelFormat.OPAQUE;
757 mStackScroller = (NotificationStackScrollLayout) mStatusBarWindow.findViewById(
758 R.id.notification_stack_scroller);
759 mStackScroller.setLongPressListener(getNotificationLongClicker());
760 mStackScroller.setPhoneStatusBar(this);
761 mStackScroller.setGroupManager(mGroupManager);
762 mStackScroller.setHeadsUpManager(mHeadsUpManager);
763 mGroupManager.setOnGroupChangeListener(mStackScroller);
765 mKeyguardIconOverflowContainer =
766 (NotificationOverflowContainer) LayoutInflater.from(mContext).inflate(
767 R.layout.status_bar_notification_keyguard_overflow, mStackScroller, false);
768 mKeyguardIconOverflowContainer.setOnActivatedListener(this);
769 mKeyguardIconOverflowContainer.setOnClickListener(mOverflowClickListener);
770 mStackScroller.setOverflowContainer(mKeyguardIconOverflowContainer);
773 inflateEmptyShadeView();
774 inflateDismissView();
775 mExpandedContents = mStackScroller;
777 mBackdrop = (BackDropView) mStatusBarWindow.findViewById(R.id.backdrop);
778 mBackdropFront = (ImageView) mBackdrop.findViewById(R.id.backdrop_front);
779 mBackdropBack = (ImageView) mBackdrop.findViewById(R.id.backdrop_back);
781 ScrimView scrimBehind = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_behind);
782 ScrimView scrimInFront = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_in_front);
783 View headsUpScrim = mStatusBarWindow.findViewById(R.id.heads_up_scrim);
784 mScrimController = SystemUIFactory.getInstance().createScrimController(
785 scrimBehind, scrimInFront, headsUpScrim);
786 if (mScrimSrcModeEnabled) {
787 Runnable runnable = new Runnable() {
790 boolean asSrc = mBackdrop.getVisibility() != View.VISIBLE;
791 mScrimController.setDrawBehindAsSrc(asSrc);
792 mStackScroller.setDrawBackgroundAsSrc(asSrc);
795 mBackdrop.setOnVisibilityChangedRunnable(runnable);
798 mHeadsUpManager.addListener(mScrimController);
799 mStackScroller.setScrimController(mScrimController);
800 mStatusBarView.setScrimController(mScrimController);
801 mDozeScrimController = new DozeScrimController(mScrimController, context);
803 mKeyguardStatusBar = (KeyguardStatusBarView) mStatusBarWindow.findViewById(R.id.keyguard_header);
804 mKeyguardStatusView = mStatusBarWindow.findViewById(R.id.keyguard_status_view);
805 mKeyguardBottomArea =
806 (KeyguardBottomAreaView) mStatusBarWindow.findViewById(R.id.keyguard_bottom_area);
807 mKeyguardBottomArea.setActivityStarter(this);
808 mKeyguardBottomArea.setAssistManager(mAssistManager);
809 mKeyguardIndicationController = new KeyguardIndicationController(mContext,
810 (KeyguardIndicationTextView) mStatusBarWindow.findViewById(
811 R.id.keyguard_indication_text),
812 mKeyguardBottomArea.getLockIcon());
813 mKeyguardBottomArea.setKeyguardIndicationController(mKeyguardIndicationController);
815 if (ENABLE_LOCKSCREEN_WALLPAPER) {
816 mLockscreenWallpaper = new LockscreenWallpaper(mContext, this, mHandler);
819 // set the initial view visibility
820 setAreThereNotifications();
822 createIconController();
824 // Background thread for any controllers that need it.
825 mHandlerThread = new HandlerThread(TAG, Process.THREAD_PRIORITY_BACKGROUND);
826 mHandlerThread.start();
829 mLocationController = new LocationControllerImpl(mContext,
830 mHandlerThread.getLooper()); // will post a notification
831 mBatteryController = createBatteryController();
832 mBatteryController.addStateChangedCallback(new BatteryStateChangeCallback() {
834 public void onPowerSaveChanged(boolean isPowerSave) {
835 mHandler.post(mCheckBarModes);
836 if (mDozeServiceHost != null) {
837 mDozeServiceHost.firePowerSaveChanged(isPowerSave);
841 public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
845 mNetworkController = new NetworkControllerImpl(mContext, mHandlerThread.getLooper());
846 mHotspotController = new HotspotControllerImpl(mContext);
847 mBluetoothController = new BluetoothControllerImpl(mContext, mHandlerThread.getLooper());
848 mSecurityController = new SecurityControllerImpl(mContext);
849 if (mContext.getResources().getBoolean(R.bool.config_showRotationLock)) {
850 mRotationLockController = new RotationLockControllerImpl(mContext);
852 mUserInfoController = new UserInfoController(mContext);
853 mVolumeComponent = getComponent(VolumeComponent.class);
854 if (mVolumeComponent != null) {
855 mZenModeController = mVolumeComponent.getZenController();
857 mCastController = new CastControllerImpl(mContext);
859 initSignalCluster(mStatusBarView);
860 initSignalCluster(mKeyguardStatusBar);
862 mFlashlightController = new FlashlightController(mContext);
863 mKeyguardBottomArea.setFlashlightController(mFlashlightController);
864 mKeyguardBottomArea.setPhoneStatusBar(this);
865 mKeyguardBottomArea.setUserSetupComplete(mUserSetup);
866 mAccessibilityController = new AccessibilityController(mContext);
867 mKeyguardBottomArea.setAccessibilityController(mAccessibilityController);
868 mNextAlarmController = new NextAlarmController(mContext);
869 mLightStatusBarController = new LightStatusBarController(mIconController,
871 mKeyguardMonitor = new KeyguardMonitor(mContext);
872 if (UserManager.get(mContext).isUserSwitcherEnabled()) {
873 mUserSwitcherController = new UserSwitcherController(mContext, mKeyguardMonitor,
875 createUserSwitcher();
878 // Set up the quick settings tile panel
879 DensityContainer container = (DensityContainer) mStatusBarWindow.findViewById(
880 R.id.qs_density_container);
881 if (container != null) {
882 final QSTileHost qsh = SystemUIFactory.getInstance().createQSTileHost(mContext, this,
883 mBluetoothController, mLocationController, mRotationLockController,
884 mNetworkController, mZenModeController, mHotspotController,
885 mCastController, mFlashlightController,
886 mUserSwitcherController, mUserInfoController, mKeyguardMonitor,
887 mSecurityController, mBatteryController, mIconController,
888 mNextAlarmController);
889 mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow);
890 container.addInflateListener(new InflateListener() {
892 public void onInflated(View v) {
893 QSContainer qsContainer = (QSContainer) v.findViewById(
894 R.id.quick_settings_container);
895 qsContainer.setHost(qsh);
896 mQSPanel = qsContainer.getQsPanel();
897 mQSPanel.setBrightnessMirror(mBrightnessMirrorController);
898 mKeyguardStatusBar.setQSPanel(mQSPanel);
899 mHeader = qsContainer.getHeader();
900 initSignalCluster(mHeader);
901 mHeader.setActivityStarter(PhoneStatusBar.this);
906 // User info. Trigger first load.
907 mKeyguardStatusBar.setUserInfoController(mUserInfoController);
908 mKeyguardStatusBar.setUserSwitcherController(mUserSwitcherController);
909 mUserInfoController.reloadUserInfo();
911 ((BatteryMeterView) mStatusBarView.findViewById(R.id.battery)).setBatteryController(
913 mKeyguardStatusBar.setBatteryController(mBatteryController);
915 PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
916 mBroadcastReceiver.onReceive(mContext,
917 new Intent(pm.isScreenOn() ? Intent.ACTION_SCREEN_ON : Intent.ACTION_SCREEN_OFF));
918 mGestureWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
920 mVibrator = mContext.getSystemService(Vibrator.class);
922 // receive broadcasts
923 IntentFilter filter = new IntentFilter();
924 filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
925 filter.addAction(Intent.ACTION_SCREEN_OFF);
926 filter.addAction(Intent.ACTION_SCREEN_ON);
927 context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
929 IntentFilter demoFilter = new IntentFilter();
930 if (DEBUG_MEDIA_FAKE_ARTWORK) {
931 demoFilter.addAction(ACTION_FAKE_ARTWORK);
933 demoFilter.addAction(ACTION_DEMO);
934 context.registerReceiverAsUser(mDemoReceiver, UserHandle.ALL, demoFilter,
935 android.Manifest.permission.DUMP, null);
937 // listen for USER_SETUP_COMPLETE setting (per-user)
938 resetUserSetupObserver();
940 // disable profiling bars, since they overlap and clutter the output on app windows
941 ThreadedRenderer.overrideProperty("disableProfileBars", "true");
943 // Private API call to make the shadows look better for Recents
944 ThreadedRenderer.overrideProperty("ambientRatio", String.valueOf(1.5f));
946 return mStatusBarView;
949 protected BatteryController createBatteryController() {
950 return new BatteryControllerImpl(mContext);
954 protected void reInflateViews() {
955 super.reInflateViews();
956 inflateDismissView();
958 inflateEmptyShadeView();
959 updateEmptyShadeView();
962 private void inflateEmptyShadeView() {
963 mEmptyShadeView = (EmptyShadeView) LayoutInflater.from(mContext).inflate(
964 R.layout.status_bar_no_notifications, mStackScroller, false);
965 mStackScroller.setEmptyShadeView(mEmptyShadeView);
968 private void inflateDismissView() {
969 mDismissView = (DismissView) LayoutInflater.from(mContext).inflate(
970 R.layout.status_bar_notification_dismiss_all, mStackScroller, false);
971 mDismissView.setOnButtonClickListener(new View.OnClickListener() {
973 public void onClick(View v) {
974 MetricsLogger.action(mContext, MetricsEvent.ACTION_DISMISS_ALL_NOTES);
975 clearAllNotifications();
978 mStackScroller.setDismissView(mDismissView);
981 protected void createUserSwitcher() {
982 mKeyguardUserSwitcher = new KeyguardUserSwitcher(mContext,
983 (ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_user_switcher),
984 mKeyguardStatusBar, mNotificationPanel, mUserSwitcherController);
987 protected void inflateStatusBarWindow(Context context) {
988 mStatusBarWindow = (StatusBarWindowView) View.inflate(context,
989 R.layout.super_status_bar, null);
992 protected void createNavigationBarView(Context context) {
993 inflateNavigationBarView(context);
994 mNavigationBarView.setDisabledFlags(mDisabled1);
995 mNavigationBarView.setComponents(mRecents, getComponent(Divider.class));
996 mNavigationBarView.setOnVerticalChangedListener(
997 new NavigationBarView.OnVerticalChangedListener() {
999 public void onVerticalChanged(boolean isVertical) {
1000 if (mAssistManager != null) {
1001 mAssistManager.onConfigurationChanged();
1003 mNotificationPanel.setQsScrimEnabled(!isVertical);
1006 mNavigationBarView.setOnTouchListener(new View.OnTouchListener() {
1008 public boolean onTouch(View v, MotionEvent event) {
1009 checkUserAutohide(v, event);
1014 protected void inflateNavigationBarView(Context context) {
1015 mNavigationBarView = (NavigationBarView) View.inflate(
1016 context, R.layout.navigation_bar, null);
1019 protected void initSignalCluster(View containerView) {
1020 SignalClusterView signalCluster =
1021 (SignalClusterView) containerView.findViewById(R.id.signal_cluster);
1022 if (signalCluster != null) {
1023 signalCluster.setSecurityController(mSecurityController);
1024 signalCluster.setNetworkController(mNetworkController);
1028 public void clearAllNotifications() {
1030 // animate-swipe all dismissable notifications, then animate the shade closed
1031 int numChildren = mStackScroller.getChildCount();
1033 final ArrayList<View> viewsToHide = new ArrayList<View>(numChildren);
1034 for (int i = 0; i < numChildren; i++) {
1035 final View child = mStackScroller.getChildAt(i);
1036 if (child instanceof ExpandableNotificationRow) {
1037 if (mStackScroller.canChildBeDismissed(child)) {
1038 if (child.getVisibility() == View.VISIBLE) {
1039 viewsToHide.add(child);
1042 ExpandableNotificationRow row = (ExpandableNotificationRow) child;
1043 List<ExpandableNotificationRow> children = row.getNotificationChildren();
1044 if (row.areChildrenExpanded() && children != null) {
1045 for (ExpandableNotificationRow childRow : children) {
1046 if (childRow.getVisibility() == View.VISIBLE) {
1047 viewsToHide.add(childRow);
1053 if (viewsToHide.isEmpty()) {
1054 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
1058 addPostCollapseAction(new Runnable() {
1061 mStackScroller.setDismissAllInProgress(false);
1063 mBarService.onClearAllNotifications(mCurrentUserId);
1064 } catch (Exception ex) { }
1068 performDismissAllAnimations(viewsToHide);
1072 private void performDismissAllAnimations(ArrayList<View> hideAnimatedList) {
1073 Runnable animationFinishAction = new Runnable() {
1076 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
1080 // let's disable our normal animations
1081 mStackScroller.setDismissAllInProgress(true);
1083 // Decrease the delay for every row we animate to give the sense of
1084 // accelerating the swipes
1085 int rowDelayDecrement = 10;
1086 int currentDelay = 140;
1087 int totalDelay = 180;
1088 int numItems = hideAnimatedList.size();
1089 for (int i = numItems - 1; i >= 0; i--) {
1090 View view = hideAnimatedList.get(i);
1091 Runnable endRunnable = null;
1093 endRunnable = animationFinishAction;
1095 mStackScroller.dismissViewAnimated(view, endRunnable, totalDelay, 260);
1096 currentDelay = Math.max(50, currentDelay - rowDelayDecrement);
1097 totalDelay += currentDelay;
1102 protected void setZenMode(int mode) {
1103 super.setZenMode(mode);
1104 if (mIconPolicy != null) {
1105 mIconPolicy.setZenMode(mode);
1109 protected void startKeyguard() {
1110 KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class);
1111 mFingerprintUnlockController = new FingerprintUnlockController(mContext,
1112 mStatusBarWindowManager, mDozeScrimController, keyguardViewMediator,
1113 mScrimController, this);
1114 mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this,
1115 getBouncerContainer(), mStatusBarWindowManager, mScrimController,
1116 mFingerprintUnlockController);
1117 mKeyguardIndicationController.setStatusBarKeyguardViewManager(
1118 mStatusBarKeyguardViewManager);
1119 mFingerprintUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
1120 mRemoteInputController.addCallback(mStatusBarKeyguardViewManager);
1122 if (FORCE_REMOTE_INPUT_HISTORY) {
1123 mRemoteInputController.addCallback(new RemoteInputController.Callback() {
1125 public void onRemoteInputSent(Entry entry) {
1126 if (mKeysKeptForRemoteInput.contains(entry.key)) {
1127 removeNotification(entry.key, null);
1133 mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback();
1134 mLightStatusBarController.setFingerprintUnlockController(mFingerprintUnlockController);
1138 protected View getStatusBarView() {
1139 return mStatusBarView;
1142 public StatusBarWindowView getStatusBarWindow() {
1143 return mStatusBarWindow;
1146 protected ViewGroup getBouncerContainer() {
1147 return mStatusBarWindow;
1150 public int getStatusBarHeight() {
1151 if (mNaturalBarHeight < 0) {
1152 final Resources res = mContext.getResources();
1154 res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
1156 return mNaturalBarHeight;
1159 private View.OnClickListener mRecentsClickListener = new View.OnClickListener() {
1160 public void onClick(View v) {
1166 private View.OnLongClickListener mLongPressBackListener = new View.OnLongClickListener() {
1168 public boolean onLongClick(View v) {
1169 return handleLongPressBack();
1173 private View.OnLongClickListener mRecentsLongClickListener = new View.OnLongClickListener() {
1176 public boolean onLongClick(View v) {
1177 if (mRecents == null || !ActivityManager.supportsMultiWindow()
1178 || !getComponent(Divider.class).getView().getSnapAlgorithm()
1179 .isSplitScreenFeasible()) {
1183 toggleSplitScreenMode(MetricsEvent.ACTION_WINDOW_DOCK_LONGPRESS,
1184 MetricsEvent.ACTION_WINDOW_UNDOCK_LONGPRESS);
1190 protected void toggleSplitScreenMode(int metricsDockAction, int metricsUndockAction) {
1191 if (mRecents == null) {
1194 int dockSide = WindowManagerProxy.getInstance().getDockSide();
1195 if (dockSide == WindowManager.DOCKED_INVALID) {
1196 mRecents.dockTopTask(NavigationBarGestureHelper.DRAG_MODE_NONE,
1197 ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, null, metricsDockAction);
1199 EventBus.getDefault().send(new UndockingTaskEvent());
1200 if (metricsUndockAction != -1) {
1201 MetricsLogger.action(mContext, metricsUndockAction);
1206 private final View.OnLongClickListener mLongPressHomeListener
1207 = new View.OnLongClickListener() {
1209 public boolean onLongClick(View v) {
1210 if (shouldDisableNavbarGestures()) {
1213 MetricsLogger.action(mContext, MetricsEvent.ACTION_ASSIST_LONG_PRESS);
1214 mAssistManager.startAssist(new Bundle() /* args */);
1216 if (mNavigationBarView != null) {
1217 mNavigationBarView.abortCurrentGesture();
1223 private final View.OnTouchListener mHomeActionListener = new View.OnTouchListener() {
1224 public boolean onTouch(View v, MotionEvent event) {
1225 switch (event.getAction()) {
1226 case MotionEvent.ACTION_UP:
1227 case MotionEvent.ACTION_CANCEL:
1235 private void awakenDreams() {
1236 if (mDreamManager != null) {
1238 mDreamManager.awaken();
1239 } catch (RemoteException e) {
1240 // fine, stay asleep then
1245 private void prepareNavigationBarView() {
1246 mNavigationBarView.reorient();
1248 ButtonDispatcher recentsButton = mNavigationBarView.getRecentsButton();
1249 recentsButton.setOnClickListener(mRecentsClickListener);
1250 recentsButton.setOnTouchListener(mRecentsPreloadOnTouchListener);
1251 recentsButton.setLongClickable(true);
1252 recentsButton.setOnLongClickListener(mRecentsLongClickListener);
1254 ButtonDispatcher backButton = mNavigationBarView.getBackButton();
1255 backButton.setLongClickable(true);
1256 backButton.setOnLongClickListener(mLongPressBackListener);
1258 ButtonDispatcher homeButton = mNavigationBarView.getHomeButton();
1259 homeButton.setOnTouchListener(mHomeActionListener);
1260 homeButton.setOnLongClickListener(mLongPressHomeListener);
1262 mAssistManager.onConfigurationChanged();
1265 // For small-screen devices (read: phones) that lack hardware navigation buttons
1266 protected void addNavigationBar() {
1267 if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + mNavigationBarView);
1268 if (mNavigationBarView == null) return;
1270 prepareNavigationBarView();
1272 mWindowManager.addView(mNavigationBarView, getNavigationBarLayoutParams());
1275 protected void repositionNavigationBar() {
1276 if (mNavigationBarView == null || !mNavigationBarView.isAttachedToWindow()) return;
1278 prepareNavigationBarView();
1280 mWindowManager.updateViewLayout(mNavigationBarView, getNavigationBarLayoutParams());
1283 private void notifyNavigationBarScreenOn(boolean screenOn) {
1284 if (mNavigationBarView == null) return;
1285 mNavigationBarView.notifyScreenOn(screenOn);
1288 private WindowManager.LayoutParams getNavigationBarLayoutParams() {
1289 WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
1290 LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
1291 WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
1293 | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
1294 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
1295 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
1296 | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
1297 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
1298 PixelFormat.TRANSLUCENT);
1299 // this will allow the navbar to run in an overlay on devices that support this
1300 if (ActivityManager.isHighEndGfx()) {
1301 lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
1304 lp.setTitle("NavigationBar");
1305 lp.windowAnimations = 0;
1310 public void setIcon(String slot, StatusBarIcon icon) {
1311 mIconController.setIcon(slot, icon);
1315 public void removeIcon(String slot) {
1316 mIconController.removeIcon(slot);
1319 public UserHandle getCurrentUserHandle() {
1320 return new UserHandle(mCurrentUserId);
1324 public void addNotification(StatusBarNotification notification, RankingMap ranking,
1326 if (DEBUG) Log.d(TAG, "addNotification key=" + notification.getKey());
1328 mNotificationData.updateRanking(ranking);
1329 Entry shadeEntry = createNotificationViews(notification);
1330 if (shadeEntry == null) {
1333 boolean isHeadsUped = mUseHeadsUp && shouldPeek(shadeEntry);
1335 mHeadsUpManager.showNotification(shadeEntry);
1336 // Mark as seen immediately
1337 setNotificationShown(notification);
1340 if (!isHeadsUped && notification.getNotification().fullScreenIntent != null) {
1341 if (shouldSuppressFullScreenIntent(notification.getKey())) {
1343 Log.d(TAG, "No Fullscreen intent: suppressed by DND: " + notification.getKey());
1345 } else if (mNotificationData.getImportance(notification.getKey())
1346 < NotificationListenerService.Ranking.IMPORTANCE_MAX) {
1348 Log.d(TAG, "No Fullscreen intent: not important enough: "
1349 + notification.getKey());
1352 // Stop screensaver if the notification has a full-screen intent.
1353 // (like an incoming phone call)
1356 // not immersive & a full-screen alert should be shown
1358 Log.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent");
1360 EventLog.writeEvent(EventLogTags.SYSUI_FULLSCREEN_NOTIFICATION,
1361 notification.getKey());
1362 notification.getNotification().fullScreenIntent.send();
1363 shadeEntry.notifyFullScreenIntentLaunched();
1364 MetricsLogger.count(mContext, "note_fullscreen", 1);
1365 } catch (PendingIntent.CanceledException e) {
1369 addNotificationViews(shadeEntry, ranking);
1370 // Recalculate the position of the sliding windows and the titles.
1371 setAreThereNotifications();
1374 private boolean shouldSuppressFullScreenIntent(String key) {
1375 if (isDeviceInVrMode()) {
1379 if (mPowerManager.isInteractive()) {
1380 return mNotificationData.shouldSuppressScreenOn(key);
1382 return mNotificationData.shouldSuppressScreenOff(key);
1387 protected void updateNotificationRanking(RankingMap ranking) {
1388 mNotificationData.updateRanking(ranking);
1389 updateNotifications();
1393 public void removeNotification(String key, RankingMap ranking) {
1394 boolean deferRemoval = false;
1395 if (mHeadsUpManager.isHeadsUp(key)) {
1396 deferRemoval = !mHeadsUpManager.removeNotification(key);
1398 if (key.equals(mMediaNotificationKey)) {
1399 clearCurrentMediaNotification();
1400 updateMediaMetaData(true, true);
1402 if (FORCE_REMOTE_INPUT_HISTORY && mRemoteInputController.isSpinning(key)) {
1403 Entry entry = mNotificationData.get(key);
1404 StatusBarNotification sbn = entry.notification;
1406 Notification.Builder b = Notification.Builder
1407 .recoverBuilder(mContext, sbn.getNotification().clone());
1408 CharSequence[] oldHistory = sbn.getNotification().extras
1409 .getCharSequenceArray(Notification.EXTRA_REMOTE_INPUT_HISTORY);
1410 CharSequence[] newHistory;
1411 if (oldHistory == null) {
1412 newHistory = new CharSequence[1];
1414 newHistory = new CharSequence[oldHistory.length + 1];
1415 for (int i = 0; i < oldHistory.length; i++) {
1416 newHistory[i + 1] = oldHistory[i];
1419 newHistory[0] = String.valueOf(entry.remoteInputText);
1420 b.setRemoteInputHistory(newHistory);
1422 Notification newNotification = b.build();
1424 // Undo any compatibility view inflation
1425 newNotification.contentView = sbn.getNotification().contentView;
1426 newNotification.bigContentView = sbn.getNotification().bigContentView;
1427 newNotification.headsUpContentView = sbn.getNotification().headsUpContentView;
1429 StatusBarNotification newSbn = new StatusBarNotification(sbn.getPackageName(),
1431 sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
1432 0, newNotification, sbn.getUser(), sbn.getPostTime());
1434 updateNotification(newSbn, null);
1435 mKeysKeptForRemoteInput.add(entry.key);
1439 mLatestRankingMap = ranking;
1440 mHeadsUpEntriesToRemoveOnSwitch.add(mHeadsUpManager.getEntry(key));
1443 StatusBarNotification old = removeNotificationViews(key, ranking);
1444 if (SPEW) Log.d(TAG, "removeNotification key=" + key + " old=" + old);
1447 if (CLOSE_PANEL_WHEN_EMPTIED && !hasActiveNotifications()
1448 && !mNotificationPanel.isTracking() && !mNotificationPanel.isQsExpanded()) {
1449 if (mState == StatusBarState.SHADE) {
1450 animateCollapsePanels();
1451 } else if (mState == StatusBarState.SHADE_LOCKED) {
1456 setAreThereNotifications();
1460 protected void refreshLayout(int layoutDirection) {
1461 if (mNavigationBarView != null) {
1462 mNavigationBarView.setLayoutDirection(layoutDirection);
1466 private void updateNotificationShade() {
1467 if (mStackScroller == null) return;
1469 // Do not modify the notifications during collapse.
1470 if (isCollapsing()) {
1471 addPostCollapseAction(new Runnable() {
1474 updateNotificationShade();
1480 ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
1481 ArrayList<ExpandableNotificationRow> toShow = new ArrayList<>(activeNotifications.size());
1482 final int N = activeNotifications.size();
1483 for (int i=0; i<N; i++) {
1484 Entry ent = activeNotifications.get(i);
1485 int vis = ent.notification.getNotification().visibility;
1487 // Display public version of the notification if we need to redact.
1488 final boolean hideSensitive =
1489 !userAllowsPrivateNotificationsInPublic(ent.notification.getUserId());
1490 boolean sensitiveNote = vis == Notification.VISIBILITY_PRIVATE;
1491 boolean sensitivePackage = packageHasVisibilityOverride(ent.notification.getKey());
1492 boolean sensitive = (sensitiveNote && hideSensitive) || sensitivePackage;
1493 boolean showingPublic = sensitive && isLockscreenPublicMode();
1494 if (showingPublic) {
1495 updatePublicContentView(ent, ent.notification);
1497 ent.row.setSensitive(sensitive, hideSensitive);
1498 if (ent.autoRedacted && ent.legacy) {
1499 // TODO: Also fade this? Or, maybe easier (and better), provide a dark redacted form
1500 // for legacy auto redacted notifications.
1501 if (showingPublic) {
1502 ent.row.setShowingLegacyBackground(false);
1504 ent.row.setShowingLegacyBackground(true);
1507 if (mGroupManager.isChildInGroupWithSummary(ent.row.getStatusBarNotification())) {
1508 ExpandableNotificationRow summary = mGroupManager.getGroupSummary(
1509 ent.row.getStatusBarNotification());
1510 List<ExpandableNotificationRow> orderedChildren =
1511 mTmpChildOrderMap.get(summary);
1512 if (orderedChildren == null) {
1513 orderedChildren = new ArrayList<>();
1514 mTmpChildOrderMap.put(summary, orderedChildren);
1516 orderedChildren.add(ent.row);
1518 toShow.add(ent.row);
1523 ArrayList<ExpandableNotificationRow> toRemove = new ArrayList<>();
1524 for (int i=0; i< mStackScroller.getChildCount(); i++) {
1525 View child = mStackScroller.getChildAt(i);
1526 if (!toShow.contains(child) && child instanceof ExpandableNotificationRow) {
1527 toRemove.add((ExpandableNotificationRow) child);
1531 for (ExpandableNotificationRow remove : toRemove) {
1532 if (mGroupManager.isChildInGroupWithSummary(remove.getStatusBarNotification())) {
1533 // we are only transfering this notification to its parent, don't generate an animation
1534 mStackScroller.setChildTransferInProgress(true);
1536 if (remove.isSummaryWithChildren()) {
1537 remove.removeAllChildren();
1539 mStackScroller.removeView(remove);
1540 mStackScroller.setChildTransferInProgress(false);
1543 removeNotificationChildren();
1545 for (int i=0; i<toShow.size(); i++) {
1546 View v = toShow.get(i);
1547 if (v.getParent() == null) {
1548 mStackScroller.addView(v);
1552 addNotificationChildrenAndSort();
1554 // So after all this work notifications still aren't sorted correctly.
1555 // Let's do that now by advancing through toShow and mStackScroller in
1556 // lock-step, making sure mStackScroller matches what we see in toShow.
1558 for (int i = 0; i < mStackScroller.getChildCount(); i++) {
1559 View child = mStackScroller.getChildAt(i);
1560 if (!(child instanceof ExpandableNotificationRow)) {
1561 // We don't care about non-notification views.
1565 ExpandableNotificationRow targetChild = toShow.get(j);
1566 if (child != targetChild) {
1567 // Oops, wrong notification at this position. Put the right one
1568 // here and advance both lists.
1569 mStackScroller.changeViewPosition(targetChild, i);
1575 // clear the map again for the next usage
1576 mTmpChildOrderMap.clear();
1581 updateEmptyShadeView();
1583 updateQsExpansionEnabled();
1584 mShadeUpdates.check();
1588 * Disable QS if device not provisioned.
1589 * If the user switcher is simple then disable QS during setup because
1590 * the user intends to use the lock screen user switcher, QS in not needed.
1592 private void updateQsExpansionEnabled() {
1593 mNotificationPanel.setQsExpansionEnabled(isDeviceProvisioned()
1594 && (mUserSetup || mUserSwitcherController == null
1595 || !mUserSwitcherController.isSimpleUserSwitcher())
1596 && ((mDisabled2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) == 0)
1597 && !ONLY_CORE_APPS);
1600 private void addNotificationChildrenAndSort() {
1601 // Let's now add all notification children which are missing
1602 boolean orderChanged = false;
1603 for (int i = 0; i < mStackScroller.getChildCount(); i++) {
1604 View view = mStackScroller.getChildAt(i);
1605 if (!(view instanceof ExpandableNotificationRow)) {
1606 // We don't care about non-notification views.
1610 ExpandableNotificationRow parent = (ExpandableNotificationRow) view;
1611 List<ExpandableNotificationRow> children = parent.getNotificationChildren();
1612 List<ExpandableNotificationRow> orderedChildren = mTmpChildOrderMap.get(parent);
1614 for (int childIndex = 0; orderedChildren != null && childIndex < orderedChildren.size();
1616 ExpandableNotificationRow childView = orderedChildren.get(childIndex);
1617 if (children == null || !children.contains(childView)) {
1618 parent.addChildNotification(childView, childIndex);
1619 mStackScroller.notifyGroupChildAdded(childView);
1623 // Finally after removing and adding has been beformed we can apply the order.
1624 orderChanged |= parent.applyChildOrder(orderedChildren);
1627 mStackScroller.generateChildOrderChangedEvent();
1631 private void removeNotificationChildren() {
1632 // First let's remove all children which don't belong in the parents
1633 ArrayList<ExpandableNotificationRow> toRemove = new ArrayList<>();
1634 for (int i = 0; i < mStackScroller.getChildCount(); i++) {
1635 View view = mStackScroller.getChildAt(i);
1636 if (!(view instanceof ExpandableNotificationRow)) {
1637 // We don't care about non-notification views.
1641 ExpandableNotificationRow parent = (ExpandableNotificationRow) view;
1642 List<ExpandableNotificationRow> children = parent.getNotificationChildren();
1643 List<ExpandableNotificationRow> orderedChildren = mTmpChildOrderMap.get(parent);
1645 if (children != null) {
1647 for (ExpandableNotificationRow childRow : children) {
1648 if (orderedChildren == null || !orderedChildren.contains(childRow)) {
1649 toRemove.add(childRow);
1652 for (ExpandableNotificationRow remove : toRemove) {
1653 parent.removeChildNotification(remove);
1654 if (mNotificationData.get(remove.getStatusBarNotification().getKey()) == null) {
1655 // We only want to add an animation if the view is completely removed
1656 // otherwise it's just a transfer
1657 mStackScroller.notifyGroupChildRemoved(remove);
1665 public void addQsTile(ComponentName tile) {
1666 mQSPanel.getHost().addTile(tile);
1670 public void remQsTile(ComponentName tile) {
1671 mQSPanel.getHost().removeTile(tile);
1675 public void clickTile(ComponentName tile) {
1676 mQSPanel.clickTile(tile);
1679 private boolean packageHasVisibilityOverride(String key) {
1680 return mNotificationData.getVisibilityOverride(key) == Notification.VISIBILITY_PRIVATE;
1683 private void updateClearAll() {
1684 boolean showDismissView =
1685 mState != StatusBarState.KEYGUARD &&
1686 mNotificationData.hasActiveClearableNotifications();
1687 mStackScroller.updateDismissView(showDismissView);
1690 private void updateEmptyShadeView() {
1691 boolean showEmptyShade =
1692 mState != StatusBarState.KEYGUARD &&
1693 mNotificationData.getActiveNotifications().size() == 0;
1694 mNotificationPanel.setShadeEmpty(showEmptyShade);
1697 private void updateSpeedbump() {
1698 int speedbumpIndex = -1;
1699 int currentIndex = 0;
1700 final int N = mStackScroller.getChildCount();
1701 for (int i = 0; i < N; i++) {
1702 View view = mStackScroller.getChildAt(i);
1703 if (view.getVisibility() == View.GONE || !(view instanceof ExpandableNotificationRow)) {
1706 ExpandableNotificationRow row = (ExpandableNotificationRow) view;
1707 if (mNotificationData.isAmbient(row.getStatusBarNotification().getKey())) {
1708 speedbumpIndex = currentIndex;
1713 mStackScroller.updateSpeedBumpIndex(speedbumpIndex);
1716 public static boolean isTopLevelChild(Entry entry) {
1717 return entry.row.getParent() instanceof NotificationStackScrollLayout;
1721 protected void updateNotifications() {
1722 mNotificationData.filterAndSort();
1724 updateNotificationShade();
1725 mIconController.updateNotificationIcons(mNotificationData);
1728 public void requestNotificationUpdate() {
1729 updateNotifications();
1733 protected void setAreThereNotifications() {
1736 final boolean clearable = hasActiveNotifications() &&
1737 mNotificationData.hasActiveClearableNotifications();
1738 Log.d(TAG, "setAreThereNotifications: N=" +
1739 mNotificationData.getActiveNotifications().size() + " any=" +
1740 hasActiveNotifications() + " clearable=" + clearable);
1743 final View nlo = mStatusBarView.findViewById(R.id.notification_lights_out);
1744 final boolean showDot = hasActiveNotifications() && !areLightsOn();
1745 if (showDot != (nlo.getAlpha() == 1.0f)) {
1748 nlo.setVisibility(View.VISIBLE);
1752 .setDuration(showDot?750:250)
1753 .setInterpolator(new AccelerateInterpolator(2.0f))
1754 .setListener(showDot ? null : new AnimatorListenerAdapter() {
1756 public void onAnimationEnd(Animator _a) {
1757 nlo.setVisibility(View.GONE);
1763 findAndUpdateMediaNotifications();
1766 public void findAndUpdateMediaNotifications() {
1767 boolean metaDataChanged = false;
1769 synchronized (mNotificationData) {
1770 ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
1771 final int N = activeNotifications.size();
1773 // Promote the media notification with a controller in 'playing' state, if any.
1774 Entry mediaNotification = null;
1775 MediaController controller = null;
1776 for (int i = 0; i < N; i++) {
1777 final Entry entry = activeNotifications.get(i);
1778 if (isMediaNotification(entry)) {
1779 final MediaSession.Token token =
1780 entry.notification.getNotification().extras
1781 .getParcelable(Notification.EXTRA_MEDIA_SESSION);
1782 if (token != null) {
1783 MediaController aController = new MediaController(mContext, token);
1784 if (PlaybackState.STATE_PLAYING ==
1785 getMediaControllerPlaybackState(aController)) {
1787 Log.v(TAG, "DEBUG_MEDIA: found mediastyle controller matching "
1788 + entry.notification.getKey());
1790 mediaNotification = entry;
1791 controller = aController;
1797 if (mediaNotification == null) {
1798 // Still nothing? OK, let's just look for live media sessions and see if they match
1799 // one of our notifications. This will catch apps that aren't (yet!) using media
1802 if (mMediaSessionManager != null) {
1803 final List<MediaController> sessions
1804 = mMediaSessionManager.getActiveSessionsForUser(
1806 UserHandle.USER_ALL);
1808 for (MediaController aController : sessions) {
1809 if (PlaybackState.STATE_PLAYING ==
1810 getMediaControllerPlaybackState(aController)) {
1811 // now to see if we have one like this
1812 final String pkg = aController.getPackageName();
1814 for (int i = 0; i < N; i++) {
1815 final Entry entry = activeNotifications.get(i);
1816 if (entry.notification.getPackageName().equals(pkg)) {
1818 Log.v(TAG, "DEBUG_MEDIA: found controller matching "
1819 + entry.notification.getKey());
1821 controller = aController;
1822 mediaNotification = entry;
1831 if (controller != null && !sameSessions(mMediaController, controller)) {
1832 // We have a new media session
1833 clearCurrentMediaNotification();
1834 mMediaController = controller;
1835 mMediaController.registerCallback(mMediaListener);
1836 mMediaMetadata = mMediaController.getMetadata();
1838 Log.v(TAG, "DEBUG_MEDIA: insert listener, receive metadata: "
1842 if (mediaNotification != null) {
1843 mMediaNotificationKey = mediaNotification.notification.getKey();
1845 Log.v(TAG, "DEBUG_MEDIA: Found new media notification: key="
1846 + mMediaNotificationKey + " controller=" + mMediaController);
1849 metaDataChanged = true;
1853 if (metaDataChanged) {
1854 updateNotifications();
1856 updateMediaMetaData(metaDataChanged, true);
1859 private int getMediaControllerPlaybackState(MediaController controller) {
1860 if (controller != null) {
1861 final PlaybackState playbackState = controller.getPlaybackState();
1862 if (playbackState != null) {
1863 return playbackState.getState();
1866 return PlaybackState.STATE_NONE;
1869 private boolean isPlaybackActive(int state) {
1870 if (state != PlaybackState.STATE_STOPPED
1871 && state != PlaybackState.STATE_ERROR
1872 && state != PlaybackState.STATE_NONE) {
1878 private void clearCurrentMediaNotification() {
1879 mMediaNotificationKey = null;
1880 mMediaMetadata = null;
1881 if (mMediaController != null) {
1883 Log.v(TAG, "DEBUG_MEDIA: Disconnecting from old controller: "
1884 + mMediaController.getPackageName());
1886 mMediaController.unregisterCallback(mMediaListener);
1888 mMediaController = null;
1891 private boolean sameSessions(MediaController a, MediaController b) {
1892 if (a == b) return true;
1893 if (a == null) return false;
1894 return a.controlsSameSession(b);
1898 * Hide the album artwork that is fading out and release its bitmap.
1900 private Runnable mHideBackdropFront = new Runnable() {
1904 Log.v(TAG, "DEBUG_MEDIA: removing fade layer");
1906 mBackdropFront.setVisibility(View.INVISIBLE);
1907 mBackdropFront.animate().cancel();
1908 mBackdropFront.setImageDrawable(null);
1913 * Refresh or remove lockscreen artwork from media metadata or the lockscreen wallpaper.
1915 public void updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation) {
1916 if (!SHOW_LOCKSCREEN_MEDIA_ARTWORK) return;
1918 if (mBackdrop == null) return; // called too early
1920 if (mLaunchTransitionFadingAway) {
1921 mBackdrop.setVisibility(View.INVISIBLE);
1926 Log.v(TAG, "DEBUG_MEDIA: updating album art for notification " + mMediaNotificationKey
1927 + " metadata=" + mMediaMetadata
1928 + " metaDataChanged=" + metaDataChanged
1929 + " state=" + mState);
1932 Drawable artworkDrawable = null;
1933 if (mMediaMetadata != null) {
1934 Bitmap artworkBitmap = null;
1935 artworkBitmap = mMediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ART);
1936 if (artworkBitmap == null) {
1937 artworkBitmap = mMediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
1938 // might still be null
1940 if (artworkBitmap != null) {
1941 artworkDrawable = new BitmapDrawable(mBackdropBack.getResources(), artworkBitmap);
1944 if (ENABLE_LOCKSCREEN_WALLPAPER && artworkDrawable == null) {
1945 Bitmap lockWallpaper = mLockscreenWallpaper.getBitmap();
1946 if (lockWallpaper != null) {
1947 artworkDrawable = new LockscreenWallpaper.WallpaperDrawable(
1948 mBackdropBack.getResources(), lockWallpaper);
1952 final boolean hasArtwork = artworkDrawable != null;
1954 if ((hasArtwork || DEBUG_MEDIA_FAKE_ARTWORK) && mState != StatusBarState.SHADE
1955 && mFingerprintUnlockController.getMode()
1956 != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING) {
1957 // time to show some art!
1958 if (mBackdrop.getVisibility() != View.VISIBLE) {
1959 mBackdrop.setVisibility(View.VISIBLE);
1960 if (allowEnterAnimation) {
1961 mBackdrop.animate().alpha(1f).withEndAction(new Runnable() {
1964 mStatusBarWindowManager.setBackdropShowing(true);
1968 mBackdrop.animate().cancel();
1969 mBackdrop.setAlpha(1f);
1970 mStatusBarWindowManager.setBackdropShowing(true);
1972 metaDataChanged = true;
1974 Log.v(TAG, "DEBUG_MEDIA: Fading in album artwork");
1977 if (metaDataChanged) {
1978 if (mBackdropBack.getDrawable() != null) {
1980 mBackdropBack.getDrawable().getConstantState().newDrawable().mutate();
1981 mBackdropFront.setImageDrawable(drawable);
1982 if (mScrimSrcModeEnabled) {
1983 mBackdropFront.getDrawable().mutate().setXfermode(mSrcOverXferMode);
1985 mBackdropFront.setAlpha(1f);
1986 mBackdropFront.setVisibility(View.VISIBLE);
1988 mBackdropFront.setVisibility(View.INVISIBLE);
1991 if (DEBUG_MEDIA_FAKE_ARTWORK) {
1992 final int c = 0xFF000000 | (int)(Math.random() * 0xFFFFFF);
1993 Log.v(TAG, String.format("DEBUG_MEDIA: setting new color: 0x%08x", c));
1994 mBackdropBack.setBackgroundColor(0xFFFFFFFF);
1995 mBackdropBack.setImageDrawable(new ColorDrawable(c));
1997 mBackdropBack.setImageDrawable(artworkDrawable);
1999 if (mScrimSrcModeEnabled) {
2000 mBackdropBack.getDrawable().mutate().setXfermode(mSrcXferMode);
2003 if (mBackdropFront.getVisibility() == View.VISIBLE) {
2005 Log.v(TAG, "DEBUG_MEDIA: Crossfading album artwork from "
2006 + mBackdropFront.getDrawable()
2008 + mBackdropBack.getDrawable());
2010 mBackdropFront.animate()
2012 .alpha(0f).withEndAction(mHideBackdropFront);
2016 // need to hide the album art, either because we are unlocked or because
2017 // the metadata isn't there to support it
2018 if (mBackdrop.getVisibility() != View.GONE) {
2020 Log.v(TAG, "DEBUG_MEDIA: Fading out album artwork");
2022 if (mFingerprintUnlockController.getMode()
2023 == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING) {
2025 // We are unlocking directly - no animation!
2026 mBackdrop.setVisibility(View.GONE);
2027 mBackdropBack.setImageDrawable(null);
2028 mStatusBarWindowManager.setBackdropShowing(false);
2030 mStatusBarWindowManager.setBackdropShowing(false);
2032 // Never let the alpha become zero - otherwise the RenderNode
2033 // won't draw anything and uninitialized memory will show through
2034 // if mScrimSrcModeEnabled. Note that 0.001 is rounded down to 0 in
2037 .setInterpolator(Interpolators.ACCELERATE_DECELERATE)
2040 .withEndAction(new Runnable() {
2043 mBackdrop.setVisibility(View.GONE);
2044 mBackdropFront.animate().cancel();
2045 mBackdropBack.setImageDrawable(null);
2046 mHandler.post(mHideBackdropFront);
2049 if (mKeyguardFadingAway) {
2052 // Make it disappear faster, as the focus should be on the activity
2054 .setDuration(mKeyguardFadingAwayDuration / 2)
2055 .setStartDelay(mKeyguardFadingAwayDelay)
2056 .setInterpolator(Interpolators.LINEAR)
2064 protected int adjustDisableFlags(int state) {
2065 if (!mLaunchTransitionFadingAway && !mKeyguardFadingAway
2066 && (mExpandedVisible || mBouncerShowing || mWaitingForKeyguardExit)) {
2067 state |= StatusBarManager.DISABLE_NOTIFICATION_ICONS;
2068 state |= StatusBarManager.DISABLE_SYSTEM_INFO;
2074 * State is one or more of the DISABLE constants from StatusBarManager.
2076 public void disable(int state1, int state2, boolean animate) {
2077 animate &= mStatusBarWindowState != WINDOW_STATE_HIDDEN;
2078 mDisabledUnmodified1 = state1;
2079 mDisabledUnmodified2 = state2;
2080 state1 = adjustDisableFlags(state1);
2081 final int old1 = mDisabled1;
2082 final int diff1 = state1 ^ old1;
2083 mDisabled1 = state1;
2085 final int old2 = mDisabled2;
2086 final int diff2 = state2 ^ old2;
2087 mDisabled2 = state2;
2090 Log.d(TAG, String.format("disable1: 0x%08x -> 0x%08x (diff1: 0x%08x)",
2091 old1, state1, diff1));
2092 Log.d(TAG, String.format("disable2: 0x%08x -> 0x%08x (diff2: 0x%08x)",
2093 old2, state2, diff2));
2096 StringBuilder flagdbg = new StringBuilder();
2097 flagdbg.append("disable: < ");
2098 flagdbg.append(((state1 & StatusBarManager.DISABLE_EXPAND) != 0) ? "EXPAND" : "expand");
2099 flagdbg.append(((diff1 & StatusBarManager.DISABLE_EXPAND) != 0) ? "* " : " ");
2100 flagdbg.append(((state1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) ? "ICONS" : "icons");
2101 flagdbg.append(((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) ? "* " : " ");
2102 flagdbg.append(((state1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) ? "ALERTS" : "alerts");
2103 flagdbg.append(((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) ? "* " : " ");
2104 flagdbg.append(((state1 & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) ? "SYSTEM_INFO" : "system_info");
2105 flagdbg.append(((diff1 & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) ? "* " : " ");
2106 flagdbg.append(((state1 & StatusBarManager.DISABLE_BACK) != 0) ? "BACK" : "back");
2107 flagdbg.append(((diff1 & StatusBarManager.DISABLE_BACK) != 0) ? "* " : " ");
2108 flagdbg.append(((state1 & StatusBarManager.DISABLE_HOME) != 0) ? "HOME" : "home");
2109 flagdbg.append(((diff1 & StatusBarManager.DISABLE_HOME) != 0) ? "* " : " ");
2110 flagdbg.append(((state1 & StatusBarManager.DISABLE_RECENT) != 0) ? "RECENT" : "recent");
2111 flagdbg.append(((diff1 & StatusBarManager.DISABLE_RECENT) != 0) ? "* " : " ");
2112 flagdbg.append(((state1 & StatusBarManager.DISABLE_CLOCK) != 0) ? "CLOCK" : "clock");
2113 flagdbg.append(((diff1 & StatusBarManager.DISABLE_CLOCK) != 0) ? "* " : " ");
2114 flagdbg.append(((state1 & StatusBarManager.DISABLE_SEARCH) != 0) ? "SEARCH" : "search");
2115 flagdbg.append(((diff1 & StatusBarManager.DISABLE_SEARCH) != 0) ? "* " : " ");
2116 flagdbg.append(((state2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) ? "QUICK_SETTINGS"
2117 : "quick_settings");
2118 flagdbg.append(((diff2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) ? "* " : " ");
2119 flagdbg.append(">");
2120 Log.d(TAG, flagdbg.toString());
2122 if ((diff1 & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
2123 if ((state1 & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
2124 mIconController.hideSystemIconArea(animate);
2126 mIconController.showSystemIconArea(animate);
2130 if ((diff1 & StatusBarManager.DISABLE_CLOCK) != 0) {
2131 boolean visible = (state1 & StatusBarManager.DISABLE_CLOCK) == 0;
2132 mIconController.setClockVisibility(visible);
2134 if ((diff1 & StatusBarManager.DISABLE_EXPAND) != 0) {
2135 if ((state1 & StatusBarManager.DISABLE_EXPAND) != 0) {
2136 animateCollapsePanels();
2140 if ((diff1 & (StatusBarManager.DISABLE_HOME
2141 | StatusBarManager.DISABLE_RECENT
2142 | StatusBarManager.DISABLE_BACK
2143 | StatusBarManager.DISABLE_SEARCH)) != 0) {
2144 // the nav bar will take care of these
2145 if (mNavigationBarView != null) mNavigationBarView.setDisabledFlags(state1);
2147 if ((state1 & StatusBarManager.DISABLE_RECENT) != 0) {
2148 // close recents if it's visible
2149 mHandler.removeMessages(MSG_HIDE_RECENT_APPS);
2150 mHandler.sendEmptyMessage(MSG_HIDE_RECENT_APPS);
2154 if ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
2155 if ((state1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
2156 mIconController.hideNotificationIconArea(animate);
2158 mIconController.showNotificationIconArea(animate);
2162 if ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) {
2163 mDisableNotificationAlerts =
2164 (state1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
2165 mHeadsUpObserver.onChange(true);
2168 if ((diff2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) {
2169 updateQsExpansionEnabled();
2174 protected BaseStatusBar.H createHandler() {
2175 return new PhoneStatusBar.H();
2179 public void startActivity(Intent intent, boolean dismissShade) {
2180 startActivityDismissingKeyguard(intent, false, dismissShade);
2184 public void startActivity(Intent intent, boolean dismissShade, Callback callback) {
2185 startActivityDismissingKeyguard(intent, false, dismissShade, callback);
2189 public void preventNextAnimation() {
2190 overrideActivityPendingAppTransition(true /* keyguardShowing */);
2193 public void setQsExpanded(boolean expanded) {
2194 mStatusBarWindowManager.setQsExpanded(expanded);
2195 mKeyguardStatusView.setImportantForAccessibility(expanded
2196 ? View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
2197 : View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
2200 public boolean isGoingToNotificationShade() {
2201 return mLeaveOpenOnKeyguardHide;
2204 public boolean isQsExpanded() {
2205 return mNotificationPanel.isQsExpanded();
2208 public boolean isWakeUpComingFromTouch() {
2209 return mWakeUpComingFromTouch;
2212 public boolean isFalsingThresholdNeeded() {
2213 return getBarState() == StatusBarState.KEYGUARD;
2216 public boolean isDozing() {
2220 @Override // NotificationData.Environment
2221 public String getCurrentMediaNotificationKey() {
2222 return mMediaNotificationKey;
2225 public boolean isScrimSrcModeEnabled() {
2226 return mScrimSrcModeEnabled;
2230 * To be called when there's a state change in StatusBarKeyguardViewManager.
2232 public void onKeyguardViewManagerStatesUpdated() {
2233 logStateToEventlog();
2236 @Override // UnlockMethodCache.OnUnlockMethodChangedListener
2237 public void onUnlockMethodStateChanged() {
2238 logStateToEventlog();
2242 public void onHeadsUpPinnedModeChanged(boolean inPinnedMode) {
2244 mStatusBarWindowManager.setHeadsUpShowing(true);
2245 mStatusBarWindowManager.setForceStatusBarVisible(true);
2246 if (mNotificationPanel.isFullyCollapsed()) {
2247 // We need to ensure that the touchable region is updated before the window will be
2248 // resized, in order to not catch any touches. A layout will ensure that
2249 // onComputeInternalInsets will be called and after that we can resize the layout. Let's
2250 // make sure that the window stays small for one frame until the touchableRegion is set.
2251 mNotificationPanel.requestLayout();
2252 mStatusBarWindowManager.setForceWindowCollapsed(true);
2253 mNotificationPanel.post(new Runnable() {
2256 mStatusBarWindowManager.setForceWindowCollapsed(false);
2261 if (!mNotificationPanel.isFullyCollapsed() || mNotificationPanel.isTracking()) {
2262 // We are currently tracking or is open and the shade doesn't need to be kept
2263 // open artificially.
2264 mStatusBarWindowManager.setHeadsUpShowing(false);
2266 // we need to keep the panel open artificially, let's wait until the animation
2268 mHeadsUpManager.setHeadsUpGoingAway(true);
2269 mStackScroller.runAfterAnimationFinished(new Runnable() {
2272 if (!mHeadsUpManager.hasPinnedHeadsUp()) {
2273 mStatusBarWindowManager.setHeadsUpShowing(false);
2274 mHeadsUpManager.setHeadsUpGoingAway(false);
2283 public void onHeadsUpPinned(ExpandableNotificationRow headsUp) {
2284 dismissVolumeDialog();
2288 public void onHeadsUpUnPinned(ExpandableNotificationRow headsUp) {
2292 public void onHeadsUpStateChanged(Entry entry, boolean isHeadsUp) {
2293 if (!isHeadsUp && mHeadsUpEntriesToRemoveOnSwitch.contains(entry)) {
2294 removeNotification(entry.key, mLatestRankingMap);
2295 mHeadsUpEntriesToRemoveOnSwitch.remove(entry);
2296 if (mHeadsUpEntriesToRemoveOnSwitch.isEmpty()) {
2297 mLatestRankingMap = null;
2300 updateNotificationRanking(null);
2305 protected void updateHeadsUp(String key, Entry entry, boolean shouldPeek,
2306 boolean alertAgain) {
2307 final boolean wasHeadsUp = isHeadsUp(key);
2310 // We don't want this to be interrupting anymore, lets remove it
2311 mHeadsUpManager.removeNotification(key);
2313 mHeadsUpManager.updateNotification(entry, alertAgain);
2315 } else if (shouldPeek && alertAgain) {
2316 // This notification was updated to be a heads-up, show it!
2317 mHeadsUpManager.showNotification(entry);
2321 protected void setHeadsUpUser(int newUserId) {
2322 if (mHeadsUpManager != null) {
2323 mHeadsUpManager.setUser(newUserId);
2327 public boolean isHeadsUp(String key) {
2328 return mHeadsUpManager.isHeadsUp(key);
2331 protected boolean isSnoozedPackage(StatusBarNotification sbn) {
2332 return mHeadsUpManager.isSnoozed(sbn.getPackageName());
2335 public boolean isKeyguardCurrentlySecure() {
2336 return !mUnlockMethodCache.canSkipBouncer();
2339 public void setPanelExpanded(boolean isExpanded) {
2340 mStatusBarWindowManager.setPanelExpanded(isExpanded);
2343 public void onScreenTurnedOff() {
2344 mFalsingManager.onScreenOff();
2348 * All changes to the status bar and notifications funnel through here and are batched.
2350 private class H extends BaseStatusBar.H {
2351 public void handleMessage(Message m) {
2352 super.handleMessage(m);
2354 case MSG_OPEN_NOTIFICATION_PANEL:
2355 animateExpandNotificationsPanel();
2357 case MSG_OPEN_SETTINGS_PANEL:
2358 animateExpandSettingsPanel((String) m.obj);
2360 case MSG_CLOSE_PANELS:
2361 animateCollapsePanels();
2363 case MSG_LAUNCH_TRANSITION_TIMEOUT:
2364 onLaunchTransitionTimeout();
2371 public void maybeEscalateHeadsUp() {
2372 Collection<HeadsUpManager.HeadsUpEntry> entries = mHeadsUpManager.getAllEntries();
2373 for (HeadsUpManager.HeadsUpEntry entry : entries) {
2374 final StatusBarNotification sbn = entry.entry.notification;
2375 final Notification notification = sbn.getNotification();
2376 if (notification.fullScreenIntent != null) {
2378 Log.d(TAG, "converting a heads up to fullScreen");
2381 EventLog.writeEvent(EventLogTags.SYSUI_HEADS_UP_ESCALATION,
2383 notification.fullScreenIntent.send();
2384 entry.entry.notifyFullScreenIntentLaunched();
2385 } catch (PendingIntent.CanceledException e) {
2389 mHeadsUpManager.releaseAllImmediately();
2392 boolean panelsEnabled() {
2393 return (mDisabled1 & StatusBarManager.DISABLE_EXPAND) == 0 && !ONLY_CORE_APPS;
2396 void makeExpandedVisible(boolean force) {
2397 if (SPEW) Log.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible);
2398 if (!force && (mExpandedVisible || !panelsEnabled())) {
2402 mExpandedVisible = true;
2403 if (mNavigationBarView != null)
2404 mNavigationBarView.setSlippery(true);
2406 // Expand the window to encompass the full screen in anticipation of the drag.
2407 // This is only possible to do atomically because the status bar is at the top of the screen!
2408 mStatusBarWindowManager.setPanelVisible(true);
2410 visibilityChanged(true);
2411 mWaitingForKeyguardExit = false;
2412 disable(mDisabledUnmodified1, mDisabledUnmodified2, !force /* animate */);
2413 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true);
2416 public void animateCollapsePanels() {
2417 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
2420 private final Runnable mAnimateCollapsePanels = new Runnable() {
2423 animateCollapsePanels();
2427 public void postAnimateCollapsePanels() {
2428 mHandler.post(mAnimateCollapsePanels);
2431 public void postAnimateOpenPanels() {
2432 mHandler.sendEmptyMessage(MSG_OPEN_SETTINGS_PANEL);
2435 public void animateCollapsePanels(int flags) {
2436 animateCollapsePanels(flags, false /* force */, false /* delayed */,
2437 1.0f /* speedUpFactor */);
2440 public void animateCollapsePanels(int flags, boolean force) {
2441 animateCollapsePanels(flags, force, false /* delayed */, 1.0f /* speedUpFactor */);
2444 public void animateCollapsePanels(int flags, boolean force, boolean delayed) {
2445 animateCollapsePanels(flags, force, delayed, 1.0f /* speedUpFactor */);
2448 public void animateCollapsePanels(int flags, boolean force, boolean delayed,
2449 float speedUpFactor) {
2450 if (!force && mState != StatusBarState.SHADE) {
2451 runPostCollapseRunnables();
2455 Log.d(TAG, "animateCollapse():"
2456 + " mExpandedVisible=" + mExpandedVisible
2457 + " flags=" + flags);
2460 if ((flags & CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL) == 0) {
2461 if (!mHandler.hasMessages(MSG_HIDE_RECENT_APPS)) {
2462 mHandler.removeMessages(MSG_HIDE_RECENT_APPS);
2463 mHandler.sendEmptyMessage(MSG_HIDE_RECENT_APPS);
2467 if (mStatusBarWindow != null) {
2468 // release focus immediately to kick off focus change transition
2469 mStatusBarWindowManager.setStatusBarFocusable(false);
2471 mStatusBarWindow.cancelExpandHelper();
2472 mStatusBarView.collapsePanel(true /* animate */, delayed, speedUpFactor);
2476 private void runPostCollapseRunnables() {
2477 ArrayList<Runnable> clonedList = new ArrayList<>(mPostCollapseRunnables);
2478 mPostCollapseRunnables.clear();
2479 int size = clonedList.size();
2480 for (int i = 0; i < size; i++) {
2481 clonedList.get(i).run();
2487 public void animateExpandNotificationsPanel() {
2488 if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible);
2489 if (!panelsEnabled()) {
2493 mNotificationPanel.expand(true /* animate */);
2495 if (false) postStartTracing();
2499 public void animateExpandSettingsPanel(String subPanel) {
2500 if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible);
2501 if (!panelsEnabled()) {
2505 // Settings are not available in setup
2506 if (!mUserSetup) return;
2509 if (subPanel != null) {
2510 mQSPanel.openDetails(subPanel);
2512 mNotificationPanel.expandWithQs();
2514 if (false) postStartTracing();
2517 public void animateCollapseQuickSettings() {
2518 if (mState == StatusBarState.SHADE) {
2519 mStatusBarView.collapsePanel(true, false /* delayed */, 1.0f /* speedUpFactor */);
2523 void makeExpandedInvisible() {
2524 if (SPEW) Log.d(TAG, "makeExpandedInvisible: mExpandedVisible=" + mExpandedVisible
2525 + " mExpandedVisible=" + mExpandedVisible);
2527 if (!mExpandedVisible || mStatusBarWindow == null) {
2531 // Ensure the panel is fully collapsed (just in case; bug 6765842, 7260868)
2532 mStatusBarView.collapsePanel(/*animate=*/ false, false /* delayed*/,
2533 1.0f /* speedUpFactor */);
2535 mNotificationPanel.closeQs();
2537 mExpandedVisible = false;
2538 if (mNavigationBarView != null)
2539 mNavigationBarView.setSlippery(false);
2540 visibilityChanged(false);
2542 // Shrink the window to the size of the status bar only
2543 mStatusBarWindowManager.setPanelVisible(false);
2544 mStatusBarWindowManager.setForceStatusBarVisible(false);
2546 // Close any "App info" popups that might have snuck on-screen
2549 runPostCollapseRunnables();
2550 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
2552 disable(mDisabledUnmodified1, mDisabledUnmodified2, true /* animate */);
2554 // Trimming will happen later if Keyguard is showing - doing it here might cause a jank in
2555 // the bouncer appear animation.
2556 if (!mStatusBarKeyguardViewManager.isShowing()) {
2557 WindowManagerGlobal.getInstance().trimMemory(ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
2561 public boolean interceptTouchEvent(MotionEvent event) {
2562 if (DEBUG_GESTURES) {
2563 if (event.getActionMasked() != MotionEvent.ACTION_MOVE) {
2564 EventLog.writeEvent(EventLogTags.SYSUI_STATUSBAR_TOUCH,
2565 event.getActionMasked(), (int) event.getX(), (int) event.getY(),
2566 mDisabled1, mDisabled2);
2572 Log.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled1="
2573 + mDisabled1 + " mDisabled2=" + mDisabled2 + " mTracking=" + mTracking);
2574 } else if (CHATTY) {
2575 if (event.getAction() != MotionEvent.ACTION_MOVE) {
2576 Log.d(TAG, String.format(
2577 "panel: %s at (%f, %f) mDisabled1=0x%08x mDisabled2=0x%08x",
2578 MotionEvent.actionToString(event.getAction()),
2579 event.getRawX(), event.getRawY(), mDisabled1, mDisabled2));
2583 if (DEBUG_GESTURES) {
2584 mGestureRec.add(event);
2587 if (mStatusBarWindowState == WINDOW_STATE_SHOWING) {
2588 final boolean upOrCancel =
2589 event.getAction() == MotionEvent.ACTION_UP ||
2590 event.getAction() == MotionEvent.ACTION_CANCEL;
2591 if (upOrCancel && !mExpandedVisible) {
2592 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
2594 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true);
2600 public GestureRecorder getGestureRecorder() {
2604 private void setNavigationIconHints(int hints) {
2605 if (hints == mNavigationIconHints) return;
2607 mNavigationIconHints = hints;
2609 if (mNavigationBarView != null) {
2610 mNavigationBarView.setNavigationIconHints(hints);
2615 @Override // CommandQueue
2616 public void setWindowState(int window, int state) {
2617 boolean showing = state == WINDOW_STATE_SHOWING;
2618 if (mStatusBarWindow != null
2619 && window == StatusBarManager.WINDOW_STATUS_BAR
2620 && mStatusBarWindowState != state) {
2621 mStatusBarWindowState = state;
2622 if (DEBUG_WINDOW_STATE) Log.d(TAG, "Status bar " + windowStateToString(state));
2623 if (!showing && mState == StatusBarState.SHADE) {
2624 mStatusBarView.collapsePanel(false /* animate */, false /* delayed */,
2625 1.0f /* speedUpFactor */);
2628 if (mNavigationBarView != null
2629 && window == StatusBarManager.WINDOW_NAVIGATION_BAR
2630 && mNavigationBarWindowState != state) {
2631 mNavigationBarWindowState = state;
2632 if (DEBUG_WINDOW_STATE) Log.d(TAG, "Navigation bar " + windowStateToString(state));
2636 @Override // CommandQueue
2637 public void buzzBeepBlinked() {
2638 if (mDozeServiceHost != null) {
2639 mDozeServiceHost.fireBuzzBeepBlinked();
2644 public void notificationLightOff() {
2645 if (mDozeServiceHost != null) {
2646 mDozeServiceHost.fireNotificationLight(false);
2651 public void notificationLightPulse(int argb, int onMillis, int offMillis) {
2652 if (mDozeServiceHost != null) {
2653 mDozeServiceHost.fireNotificationLight(true);
2657 @Override // CommandQueue
2658 public void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis,
2659 int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
2660 final int oldVal = mSystemUiVisibility;
2661 final int newVal = (oldVal&~mask) | (vis&mask);
2662 final int diff = newVal ^ oldVal;
2663 if (DEBUG) Log.d(TAG, String.format(
2664 "setSystemUiVisibility vis=%s mask=%s oldVal=%s newVal=%s diff=%s",
2665 Integer.toHexString(vis), Integer.toHexString(mask),
2666 Integer.toHexString(oldVal), Integer.toHexString(newVal),
2667 Integer.toHexString(diff)));
2668 boolean sbModeChanged = false;
2670 // we never set the recents bit via this method, so save the prior state to prevent
2671 // clobbering the bit below
2672 final boolean wasRecentsVisible = (mSystemUiVisibility & View.RECENT_APPS_VISIBLE) > 0;
2674 mSystemUiVisibility = newVal;
2676 // update low profile
2677 if ((diff & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0) {
2678 final boolean lightsOut = (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0;
2680 animateCollapsePanels();
2683 setAreThereNotifications();
2687 if ((vis & View.STATUS_BAR_UNHIDE) != 0) {
2688 mSystemUiVisibility &= ~View.STATUS_BAR_UNHIDE;
2689 mNoAnimationOnNextBarModeChange = true;
2692 // update status bar mode
2693 final int sbMode = computeBarMode(oldVal, newVal, mStatusBarView.getBarTransitions(),
2694 View.STATUS_BAR_TRANSIENT, View.STATUS_BAR_TRANSLUCENT,
2695 View.STATUS_BAR_TRANSPARENT);
2697 // update navigation bar mode
2698 final int nbMode = mNavigationBarView == null ? -1 : computeBarMode(
2699 oldVal, newVal, mNavigationBarView.getBarTransitions(),
2700 View.NAVIGATION_BAR_TRANSIENT, View.NAVIGATION_BAR_TRANSLUCENT,
2701 View.NAVIGATION_BAR_TRANSPARENT);
2702 sbModeChanged = sbMode != -1;
2703 final boolean nbModeChanged = nbMode != -1;
2704 boolean checkBarModes = false;
2705 if (sbModeChanged && sbMode != mStatusBarMode) {
2706 mStatusBarMode = sbMode;
2707 checkBarModes = true;
2709 if (nbModeChanged && nbMode != mNavigationBarMode) {
2710 mNavigationBarMode = nbMode;
2711 checkBarModes = true;
2713 if (checkBarModes) {
2716 if (sbModeChanged || nbModeChanged) {
2717 // update transient bar autohide
2718 if (mStatusBarMode == MODE_SEMI_TRANSPARENT || mNavigationBarMode == MODE_SEMI_TRANSPARENT) {
2725 if ((vis & View.NAVIGATION_BAR_UNHIDE) != 0) {
2726 mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE;
2729 // restore the recents bit
2730 if (wasRecentsVisible) {
2731 mSystemUiVisibility |= View.RECENT_APPS_VISIBLE;
2734 // send updated sysui visibility to window manager
2735 notifyUiVisibilityChanged(mSystemUiVisibility);
2738 mLightStatusBarController.onSystemUiVisibilityChanged(fullscreenStackVis, dockedStackVis,
2739 mask, fullscreenStackBounds, dockedStackBounds, sbModeChanged, mStatusBarMode);
2742 private int computeBarMode(int oldVis, int newVis, BarTransitions transitions,
2743 int transientFlag, int translucentFlag, int transparentFlag) {
2744 final int oldMode = barMode(oldVis, transientFlag, translucentFlag, transparentFlag);
2745 final int newMode = barMode(newVis, transientFlag, translucentFlag, transparentFlag);
2746 if (oldMode == newMode) {
2747 return -1; // no mode change
2752 private int barMode(int vis, int transientFlag, int translucentFlag, int transparentFlag) {
2753 int lightsOutTransparent = View.SYSTEM_UI_FLAG_LOW_PROFILE | transparentFlag;
2754 return (vis & transientFlag) != 0 ? MODE_SEMI_TRANSPARENT
2755 : (vis & translucentFlag) != 0 ? MODE_TRANSLUCENT
2756 : (vis & lightsOutTransparent) == lightsOutTransparent ? MODE_LIGHTS_OUT_TRANSPARENT
2757 : (vis & transparentFlag) != 0 ? MODE_TRANSPARENT
2758 : (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0 ? MODE_LIGHTS_OUT
2762 private void checkBarModes() {
2763 if (mDemoMode) return;
2764 checkBarMode(mStatusBarMode, mStatusBarWindowState, mStatusBarView.getBarTransitions(),
2765 mNoAnimationOnNextBarModeChange);
2766 if (mNavigationBarView != null) {
2767 checkBarMode(mNavigationBarMode,
2768 mNavigationBarWindowState, mNavigationBarView.getBarTransitions(),
2769 mNoAnimationOnNextBarModeChange);
2771 mNoAnimationOnNextBarModeChange = false;
2774 private void checkBarMode(int mode, int windowState, BarTransitions transitions,
2775 boolean noAnimation) {
2776 final boolean powerSave = mBatteryController.isPowerSave();
2777 final boolean anim = !noAnimation && mDeviceInteractive
2778 && windowState != WINDOW_STATE_HIDDEN && !powerSave;
2779 if (powerSave && getBarState() == StatusBarState.SHADE) {
2780 mode = MODE_WARNING;
2782 transitions.transitionTo(mode, anim);
2785 private void finishBarAnimations() {
2786 mStatusBarView.getBarTransitions().finishAnimations();
2787 if (mNavigationBarView != null) {
2788 mNavigationBarView.getBarTransitions().finishAnimations();
2792 private final Runnable mCheckBarModes = new Runnable() {
2800 public void setInteracting(int barWindow, boolean interacting) {
2801 final boolean changing = ((mInteractingWindows & barWindow) != 0) != interacting;
2802 mInteractingWindows = interacting
2803 ? (mInteractingWindows | barWindow)
2804 : (mInteractingWindows & ~barWindow);
2805 if (mInteractingWindows != 0) {
2808 resumeSuspendedAutohide();
2810 // manually dismiss the volume panel when interacting with the nav bar
2811 if (changing && interacting && barWindow == StatusBarManager.WINDOW_NAVIGATION_BAR) {
2812 dismissVolumeDialog();
2817 private void dismissVolumeDialog() {
2818 if (mVolumeComponent != null) {
2819 mVolumeComponent.dismissNow();
2823 private void resumeSuspendedAutohide() {
2824 if (mAutohideSuspended) {
2826 mHandler.postDelayed(mCheckBarModes, 500); // longer than home -> launcher
2830 private void suspendAutohide() {
2831 mHandler.removeCallbacks(mAutohide);
2832 mHandler.removeCallbacks(mCheckBarModes);
2833 mAutohideSuspended = (mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0;
2836 private void cancelAutohide() {
2837 mAutohideSuspended = false;
2838 mHandler.removeCallbacks(mAutohide);
2841 private void scheduleAutohide() {
2843 mHandler.postDelayed(mAutohide, AUTOHIDE_TIMEOUT_MS);
2846 private void checkUserAutohide(View v, MotionEvent event) {
2847 if ((mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0 // a transient bar is revealed
2848 && event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar
2849 && event.getX() == 0 && event.getY() == 0 // a touch outside both bars
2855 private void userAutohide() {
2857 mHandler.postDelayed(mAutohide, 350); // longer than app gesture -> flag clear
2860 private boolean areLightsOn() {
2861 return 0 == (mSystemUiVisibility & View.SYSTEM_UI_FLAG_LOW_PROFILE);
2864 public void setLightsOn(boolean on) {
2865 Log.v(TAG, "setLightsOn(" + on + ")");
2867 setSystemUiVisibility(0, 0, 0, View.SYSTEM_UI_FLAG_LOW_PROFILE,
2868 mLastFullscreenStackBounds, mLastDockedStackBounds);
2870 setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE, 0, 0,
2871 View.SYSTEM_UI_FLAG_LOW_PROFILE, mLastFullscreenStackBounds,
2872 mLastDockedStackBounds);
2876 private void notifyUiVisibilityChanged(int vis) {
2878 if (mLastDispatchedSystemUiVisibility != vis) {
2879 mWindowManagerService.statusBarVisibilityChanged(vis);
2880 mLastDispatchedSystemUiVisibility = vis;
2882 } catch (RemoteException ex) {
2886 public void topAppWindowChanged(boolean showMenu) {
2888 Log.d(TAG, (showMenu?"showing":"hiding") + " the MENU button");
2890 if (mNavigationBarView != null) {
2891 mNavigationBarView.setMenuVisibility(showMenu);
2894 // See above re: lights-out policy for legacy apps.
2895 if (showMenu) setLightsOn(true);
2899 public void setImeWindowStatus(IBinder token, int vis, int backDisposition,
2900 boolean showImeSwitcher) {
2901 boolean imeShown = (vis & InputMethodService.IME_VISIBLE) != 0;
2902 int flags = mNavigationIconHints;
2903 if ((backDisposition == InputMethodService.BACK_DISPOSITION_WILL_DISMISS) || imeShown) {
2904 flags |= NAVIGATION_HINT_BACK_ALT;
2906 flags &= ~NAVIGATION_HINT_BACK_ALT;
2908 if (showImeSwitcher) {
2909 flags |= NAVIGATION_HINT_IME_SHOWN;
2911 flags &= ~NAVIGATION_HINT_IME_SHOWN;
2914 setNavigationIconHints(flags);
2917 public static String viewInfo(View v) {
2918 return "[(" + v.getLeft() + "," + v.getTop() + ")(" + v.getRight() + "," + v.getBottom()
2919 + ") " + v.getWidth() + "x" + v.getHeight() + "]";
2922 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2923 synchronized (mQueueLock) {
2924 pw.println("Current Status Bar state:");
2925 pw.println(" mExpandedVisible=" + mExpandedVisible
2926 + ", mTrackingPosition=" + mTrackingPosition);
2927 pw.println(" mTracking=" + mTracking);
2928 pw.println(" mDisplayMetrics=" + mDisplayMetrics);
2929 pw.println(" mStackScroller: " + viewInfo(mStackScroller));
2930 pw.println(" mStackScroller: " + viewInfo(mStackScroller)
2931 + " scroll " + mStackScroller.getScrollX()
2932 + "," + mStackScroller.getScrollY());
2935 pw.print(" mInteractingWindows="); pw.println(mInteractingWindows);
2936 pw.print(" mStatusBarWindowState=");
2937 pw.println(windowStateToString(mStatusBarWindowState));
2938 pw.print(" mStatusBarMode=");
2939 pw.println(BarTransitions.modeToString(mStatusBarMode));
2940 pw.print(" mDozing="); pw.println(mDozing);
2941 pw.print(" mZenMode=");
2942 pw.println(Settings.Global.zenModeToString(mZenMode));
2943 pw.print(" mUseHeadsUp=");
2944 pw.println(mUseHeadsUp);
2945 dumpBarTransitions(pw, "mStatusBarView", mStatusBarView.getBarTransitions());
2946 if (mNavigationBarView != null) {
2947 pw.print(" mNavigationBarWindowState=");
2948 pw.println(windowStateToString(mNavigationBarWindowState));
2949 pw.print(" mNavigationBarMode=");
2950 pw.println(BarTransitions.modeToString(mNavigationBarMode));
2951 dumpBarTransitions(pw, "mNavigationBarView", mNavigationBarView.getBarTransitions());
2954 pw.print(" mNavigationBarView=");
2955 if (mNavigationBarView == null) {
2958 mNavigationBarView.dump(fd, pw, args);
2961 pw.print(" mMediaSessionManager=");
2962 pw.println(mMediaSessionManager);
2963 pw.print(" mMediaNotificationKey=");
2964 pw.println(mMediaNotificationKey);
2965 pw.print(" mMediaController=");
2966 pw.print(mMediaController);
2967 if (mMediaController != null) {
2968 pw.print(" state=" + mMediaController.getPlaybackState());
2971 pw.print(" mMediaMetadata=");
2972 pw.print(mMediaMetadata);
2973 if (mMediaMetadata != null) {
2974 pw.print(" title=" + mMediaMetadata.getText(MediaMetadata.METADATA_KEY_TITLE));
2978 pw.println(" Panels: ");
2979 if (mNotificationPanel != null) {
2980 pw.println(" mNotificationPanel=" +
2981 mNotificationPanel + " params=" + mNotificationPanel.getLayoutParams().debug(""));
2983 mNotificationPanel.dump(fd, pw, args);
2989 synchronized (mNotificationData) {
2990 mNotificationData.dump(pw, " ");
2993 mIconController.dump(pw);
2996 pw.println("see the logcat for a dump of the views we have created.");
2997 // must happen on ui thread
2998 mHandler.post(new Runnable() {
3000 mStatusBarView.getLocationOnScreen(mAbsPos);
3001 Log.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
3002 + ") " + mStatusBarView.getWidth() + "x"
3003 + getStatusBarHeight());
3004 mStatusBarView.debug();
3010 if (DEBUG_GESTURES) {
3011 pw.print(" status bar gestures: ");
3012 mGestureRec.dump(fd, pw, args);
3014 if (mStatusBarWindowManager != null) {
3015 mStatusBarWindowManager.dump(fd, pw, args);
3017 if (mNetworkController != null) {
3018 mNetworkController.dump(fd, pw, args);
3020 if (mBluetoothController != null) {
3021 mBluetoothController.dump(fd, pw, args);
3023 if (mHotspotController != null) {
3024 mHotspotController.dump(fd, pw, args);
3026 if (mCastController != null) {
3027 mCastController.dump(fd, pw, args);
3029 if (mUserSwitcherController != null) {
3030 mUserSwitcherController.dump(fd, pw, args);
3032 if (mBatteryController != null) {
3033 mBatteryController.dump(fd, pw, args);
3035 if (mNextAlarmController != null) {
3036 mNextAlarmController.dump(fd, pw, args);
3038 if (mSecurityController != null) {
3039 mSecurityController.dump(fd, pw, args);
3041 if (mHeadsUpManager != null) {
3042 mHeadsUpManager.dump(fd, pw, args);
3044 pw.println(" mHeadsUpManager: null");
3046 if (KeyguardUpdateMonitor.getInstance(mContext) != null) {
3047 KeyguardUpdateMonitor.getInstance(mContext).dump(fd, pw, args);
3050 FalsingManager.getInstance(mContext).dump(pw);
3051 FalsingLog.dump(pw);
3053 pw.println("SharedPreferences:");
3054 for (Map.Entry<String, ?> entry : Prefs.getAll(mContext).entrySet()) {
3055 pw.print(" "); pw.print(entry.getKey()); pw.print("="); pw.println(entry.getValue());
3059 private static void dumpBarTransitions(PrintWriter pw, String var, BarTransitions transitions) {
3060 pw.print(" "); pw.print(var); pw.print(".BarTransitions.mMode=");
3061 pw.println(BarTransitions.modeToString(transitions.getMode()));
3065 public void createAndAddWindows() {
3066 addStatusBarWindow();
3069 private void addStatusBarWindow() {
3070 makeStatusBarView();
3071 mStatusBarWindowManager = new StatusBarWindowManager(mContext);
3072 mRemoteInputController = new RemoteInputController(mStatusBarWindowManager,
3074 mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());
3077 // called by makeStatusbar and also by PhoneStatusBarView
3078 void updateDisplaySize() {
3079 mDisplay.getMetrics(mDisplayMetrics);
3080 mDisplay.getSize(mCurrentDisplaySize);
3081 if (DEBUG_GESTURES) {
3082 mGestureRec.tag("display",
3083 String.format("%dx%d", mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels));
3087 float getDisplayDensity() {
3088 return mDisplayMetrics.density;
3091 public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned,
3092 boolean dismissShade) {
3093 startActivityDismissingKeyguard(intent, onlyProvisioned, dismissShade, null /* callback */);
3096 public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned,
3097 final boolean dismissShade, final Callback callback) {
3098 if (onlyProvisioned && !isDeviceProvisioned()) return;
3100 final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity(
3101 mContext, intent, mCurrentUserId);
3102 final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
3103 Runnable runnable = new Runnable() {
3105 mAssistManager.hideAssist();
3107 Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
3108 int result = ActivityManager.START_CANCELED;
3110 result = ActivityManagerNative.getDefault().startActivityAsUser(
3111 null, mContext.getBasePackageName(),
3113 intent.resolveTypeIfNeeded(mContext.getContentResolver()),
3114 null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null,
3115 getActivityOptions(), UserHandle.CURRENT.getIdentifier());
3116 } catch (RemoteException e) {
3117 Log.w(TAG, "Unable to start activity", e);
3119 overrideActivityPendingAppTransition(
3120 keyguardShowing && !afterKeyguardGone);
3121 if (callback != null) {
3122 callback.onActivityStarted(result);
3126 Runnable cancelRunnable = new Runnable() {
3129 if (callback != null) {
3130 callback.onActivityStarted(ActivityManager.START_CANCELED);
3134 executeRunnableDismissingKeyguard(runnable, cancelRunnable, dismissShade,
3138 public void executeRunnableDismissingKeyguard(final Runnable runnable,
3139 final Runnable cancelAction,
3140 final boolean dismissShade,
3141 final boolean afterKeyguardGone) {
3142 final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
3143 dismissKeyguardThenExecute(new OnDismissAction() {
3145 public boolean onDismiss() {
3146 AsyncTask.execute(new Runnable() {
3149 if (keyguardShowing && !afterKeyguardGone) {
3150 ActivityManagerNative.getDefault()
3151 .keyguardWaitingForActivityDrawn();
3153 if (runnable != null) {
3156 } catch (RemoteException e) {
3161 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */,
3166 }, cancelAction, afterKeyguardGone);
3169 private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
3170 public void onReceive(Context context, Intent intent) {
3171 if (DEBUG) Log.v(TAG, "onReceive: " + intent);
3172 String action = intent.getAction();
3173 if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
3174 KeyboardShortcuts.dismiss();
3175 if (isCurrentProfile(getSendingUserId())) {
3176 int flags = CommandQueue.FLAG_EXCLUDE_NONE;
3177 String reason = intent.getStringExtra("reason");
3178 if (reason != null && reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) {
3179 flags |= CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL;
3181 animateCollapsePanels(flags);
3184 else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
3185 notifyNavigationBarScreenOn(false);
3186 notifyHeadsUpScreenOff();
3187 finishBarAnimations();
3188 resetUserExpandedStates();
3190 else if (Intent.ACTION_SCREEN_ON.equals(action)) {
3191 notifyNavigationBarScreenOn(true);
3196 private BroadcastReceiver mDemoReceiver = new BroadcastReceiver() {
3197 public void onReceive(Context context, Intent intent) {
3198 if (DEBUG) Log.v(TAG, "onReceive: " + intent);
3199 String action = intent.getAction();
3200 if (ACTION_DEMO.equals(action)) {
3201 Bundle bundle = intent.getExtras();
3202 if (bundle != null) {
3203 String command = bundle.getString("command", "").trim().toLowerCase();
3204 if (command.length() > 0) {
3206 dispatchDemoCommand(command, bundle);
3207 } catch (Throwable t) {
3208 Log.w(TAG, "Error running demo command, intent=" + intent, t);
3212 } else if (ACTION_FAKE_ARTWORK.equals(action)) {
3213 if (DEBUG_MEDIA_FAKE_ARTWORK) {
3214 updateMediaMetaData(true, true);
3220 public void resetUserExpandedStates() {
3221 ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
3222 final int notificationCount = activeNotifications.size();
3223 for (int i = 0; i < notificationCount; i++) {
3224 NotificationData.Entry entry = activeNotifications.get(i);
3225 if (entry.row != null) {
3226 entry.row.resetUserExpansion();
3232 protected void dismissKeyguardThenExecute(OnDismissAction action, boolean afterKeyguardGone) {
3233 dismissKeyguardThenExecute(action, null /* cancelRunnable */, afterKeyguardGone);
3236 public void dismissKeyguard() {
3237 mStatusBarKeyguardViewManager.dismiss();
3240 private void dismissKeyguardThenExecute(OnDismissAction action, Runnable cancelAction,
3241 boolean afterKeyguardGone) {
3242 if (mStatusBarKeyguardViewManager.isShowing()) {
3243 mStatusBarKeyguardViewManager.dismissWithAction(action, cancelAction,
3250 // SystemUIService notifies SystemBars of configuration changes, which then calls down here
3252 protected void onConfigurationChanged(Configuration newConfig) {
3253 super.onConfigurationChanged(newConfig); // calls refreshLayout
3256 Log.v(TAG, "configuration changed: " + mContext.getResources().getConfiguration());
3258 updateDisplaySize(); // populates mDisplayMetrics
3261 repositionNavigationBar();
3263 mIconController.updateResources();
3264 mScreenPinningRequest.onConfigurationChanged();
3265 mNetworkController.onConfigurationChanged();
3269 public void userSwitched(int newUserId) {
3270 super.userSwitched(newUserId);
3271 if (MULTIUSER_DEBUG) mNotificationPanelDebugText.setText("USER " + newUserId);
3272 animateCollapsePanels();
3274 updateNotifications();
3275 resetUserSetupObserver();
3276 setControllerUsers();
3277 clearCurrentMediaNotification();
3278 mLockscreenWallpaper.setCurrentUser(newUserId);
3279 updateMediaMetaData(true, false);
3282 private void setControllerUsers() {
3283 if (mZenModeController != null) {
3284 mZenModeController.setUserId(mCurrentUserId);
3286 if (mSecurityController != null) {
3287 mSecurityController.onUserSwitched(mCurrentUserId);
3291 private void resetUserSetupObserver() {
3292 mContext.getContentResolver().unregisterContentObserver(mUserSetupObserver);
3293 mUserSetupObserver.onChange(false);
3294 mContext.getContentResolver().registerContentObserver(
3295 Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE), true,
3296 mUserSetupObserver, mCurrentUserId);
3300 * Reload some of our resources when the configuration changes.
3302 * We don't reload everything when the configuration changes -- we probably
3303 * should, but getting that smooth is tough. Someday we'll fix that. In the
3304 * meantime, just update the things that we know change.
3306 void updateResources() {
3307 // Update the quick setting tiles
3308 if (mQSPanel != null) {
3309 mQSPanel.updateResources();
3314 if (mNotificationPanel != null) {
3315 mNotificationPanel.updateResources();
3317 if (mBrightnessMirrorController != null) {
3318 mBrightnessMirrorController.updateResources();
3322 protected void loadDimens() {
3323 final Resources res = mContext.getResources();
3325 int oldBarHeight = mNaturalBarHeight;
3326 mNaturalBarHeight = res.getDimensionPixelSize(
3327 com.android.internal.R.dimen.status_bar_height);
3328 if (mStatusBarWindowManager != null && mNaturalBarHeight != oldBarHeight) {
3329 mStatusBarWindowManager.setBarHeight(mNaturalBarHeight);
3331 mMaxAllowedKeyguardNotifications = res.getInteger(
3332 R.integer.keyguard_max_notification_count);
3334 if (DEBUG) Log.v(TAG, "updateResources");
3337 // Visibility reporting
3340 protected void handleVisibleToUserChanged(boolean visibleToUser) {
3341 if (visibleToUser) {
3342 super.handleVisibleToUserChanged(visibleToUser);
3343 startNotificationLogging();
3345 stopNotificationLogging();
3346 super.handleVisibleToUserChanged(visibleToUser);
3350 private void stopNotificationLogging() {
3351 // Report all notifications as invisible and turn down the
3353 if (!mCurrentlyVisibleNotifications.isEmpty()) {
3354 logNotificationVisibilityChanges(Collections.<NotificationVisibility>emptyList(),
3355 mCurrentlyVisibleNotifications);
3356 recycleAllVisibilityObjects(mCurrentlyVisibleNotifications);
3358 mHandler.removeCallbacks(mVisibilityReporter);
3359 mStackScroller.setChildLocationsChangedListener(null);
3362 private void startNotificationLogging() {
3363 mStackScroller.setChildLocationsChangedListener(mNotificationLocationsChangedListener);
3364 // Some transitions like mVisibleToUser=false -> mVisibleToUser=true don't
3365 // cause the scroller to emit child location events. Hence generate
3366 // one ourselves to guarantee that we're reporting visible
3368 // (Note that in cases where the scroller does emit events, this
3369 // additional event doesn't break anything.)
3370 mNotificationLocationsChangedListener.onChildLocationsChanged(mStackScroller);
3373 private void logNotificationVisibilityChanges(
3374 Collection<NotificationVisibility> newlyVisible,
3375 Collection<NotificationVisibility> noLongerVisible) {
3376 if (newlyVisible.isEmpty() && noLongerVisible.isEmpty()) {
3379 NotificationVisibility[] newlyVisibleAr =
3380 newlyVisible.toArray(new NotificationVisibility[newlyVisible.size()]);
3381 NotificationVisibility[] noLongerVisibleAr =
3382 noLongerVisible.toArray(new NotificationVisibility[noLongerVisible.size()]);
3384 mBarService.onNotificationVisibilityChanged(newlyVisibleAr, noLongerVisibleAr);
3385 } catch (RemoteException e) {
3389 final int N = newlyVisible.size();
3391 String[] newlyVisibleKeyAr = new String[N];
3392 for (int i = 0; i < N; i++) {
3393 newlyVisibleKeyAr[i] = newlyVisibleAr[i].key;
3396 setNotificationsShown(newlyVisibleKeyAr);
3402 private void logStateToEventlog() {
3403 boolean isShowing = mStatusBarKeyguardViewManager.isShowing();
3404 boolean isOccluded = mStatusBarKeyguardViewManager.isOccluded();
3405 boolean isBouncerShowing = mStatusBarKeyguardViewManager.isBouncerShowing();
3406 boolean isSecure = mUnlockMethodCache.isMethodSecure();
3407 boolean canSkipBouncer = mUnlockMethodCache.canSkipBouncer();
3408 int stateFingerprint = getLoggingFingerprint(mState,
3414 if (stateFingerprint != mLastLoggedStateFingerprint) {
3415 EventLogTags.writeSysuiStatusBarState(mState,
3418 isBouncerShowing ? 1 : 0,
3420 canSkipBouncer ? 1 : 0);
3421 mLastLoggedStateFingerprint = stateFingerprint;
3426 * Returns a fingerprint of fields logged to eventlog
3428 private static int getLoggingFingerprint(int statusBarState, boolean keyguardShowing,
3429 boolean keyguardOccluded, boolean bouncerShowing, boolean secure,
3430 boolean currentlyInsecure) {
3431 // Reserve 8 bits for statusBarState. We'll never go higher than
3432 // that, right? Riiiight.
3433 return (statusBarState & 0xFF)
3434 | ((keyguardShowing ? 1 : 0) << 8)
3435 | ((keyguardOccluded ? 1 : 0) << 9)
3436 | ((bouncerShowing ? 1 : 0) << 10)
3437 | ((secure ? 1 : 0) << 11)
3438 | ((currentlyInsecure ? 1 : 0) << 12);
3445 void postStartTracing() {
3446 mHandler.postDelayed(mStartTracing, 3000);
3450 android.os.Vibrator vib = (android.os.Vibrator)mContext.getSystemService(
3451 Context.VIBRATOR_SERVICE);
3452 vib.vibrate(250, VIBRATION_ATTRIBUTES);
3455 Runnable mStartTracing = new Runnable() {
3458 SystemClock.sleep(250);
3459 Log.d(TAG, "startTracing");
3460 android.os.Debug.startMethodTracing("/data/statusbar-traces/trace");
3461 mHandler.postDelayed(mStopTracing, 10000);
3465 Runnable mStopTracing = new Runnable() {
3467 android.os.Debug.stopMethodTracing();
3468 Log.d(TAG, "stopTracing");
3474 public boolean shouldDisableNavbarGestures() {
3475 return !isDeviceProvisioned() || (mDisabled1 & StatusBarManager.DISABLE_SEARCH) != 0;
3478 public void postQSRunnableDismissingKeyguard(final Runnable runnable) {
3479 mHandler.post(new Runnable() {
3482 mLeaveOpenOnKeyguardHide = true;
3483 executeRunnableDismissingKeyguard(runnable, null, false, false);
3488 public void postStartActivityDismissingKeyguard(final PendingIntent intent) {
3489 mHandler.post(new Runnable() {
3492 startPendingIntentDismissingKeyguard(intent);
3497 public void postStartActivityDismissingKeyguard(final Intent intent, int delay) {
3498 mHandler.postDelayed(new Runnable() {
3501 handleStartActivityDismissingKeyguard(intent, true /*onlyProvisioned*/);
3506 private void handleStartActivityDismissingKeyguard(Intent intent, boolean onlyProvisioned) {
3507 startActivityDismissingKeyguard(intent, onlyProvisioned, true /* dismissShade */);
3510 private static class FastColorDrawable extends Drawable {
3511 private final int mColor;
3513 public FastColorDrawable(int color) {
3514 mColor = 0xff000000 | color;
3518 public void draw(Canvas canvas) {
3519 canvas.drawColor(mColor, PorterDuff.Mode.SRC);
3523 public void setAlpha(int alpha) {
3527 public void setColorFilter(ColorFilter colorFilter) {
3531 public int getOpacity() {
3532 return PixelFormat.OPAQUE;
3536 public void setBounds(int left, int top, int right, int bottom) {
3540 public void setBounds(Rect bounds) {
3545 public void destroy() {
3547 if (mStatusBarWindow != null) {
3548 mWindowManager.removeViewImmediate(mStatusBarWindow);
3549 mStatusBarWindow = null;
3551 if (mNavigationBarView != null) {
3552 mWindowManager.removeViewImmediate(mNavigationBarView);
3553 mNavigationBarView = null;
3555 if (mHandlerThread != null) {
3556 mHandlerThread.quitSafely();
3557 mHandlerThread = null;
3559 mContext.unregisterReceiver(mBroadcastReceiver);
3560 mContext.unregisterReceiver(mDemoReceiver);
3561 mAssistManager.destroy();
3563 final SignalClusterView signalCluster =
3564 (SignalClusterView) mStatusBarView.findViewById(R.id.signal_cluster);
3565 final SignalClusterView signalClusterKeyguard =
3566 (SignalClusterView) mKeyguardStatusBar.findViewById(R.id.signal_cluster);
3567 final SignalClusterView signalClusterQs =
3568 (SignalClusterView) mHeader.findViewById(R.id.signal_cluster);
3569 mNetworkController.removeSignalCallback(signalCluster);
3570 mNetworkController.removeSignalCallback(signalClusterKeyguard);
3571 mNetworkController.removeSignalCallback(signalClusterQs);
3572 if (mQSPanel != null && mQSPanel.getHost() != null) {
3573 mQSPanel.getHost().destroy();
3577 private boolean mDemoModeAllowed;
3578 private boolean mDemoMode;
3581 public void dispatchDemoCommand(String command, Bundle args) {
3582 if (!mDemoModeAllowed) {
3583 mDemoModeAllowed = Settings.Global.getInt(mContext.getContentResolver(),
3584 DEMO_MODE_ALLOWED, 0) != 0;
3586 if (!mDemoModeAllowed) return;
3587 if (command.equals(COMMAND_ENTER)) {
3589 } else if (command.equals(COMMAND_EXIT)) {
3592 } else if (!mDemoMode) {
3593 // automatically enter demo mode on first demo command
3594 dispatchDemoCommand(COMMAND_ENTER, new Bundle());
3596 boolean modeChange = command.equals(COMMAND_ENTER) || command.equals(COMMAND_EXIT);
3597 if ((modeChange || command.equals(COMMAND_VOLUME)) && mVolumeComponent != null) {
3598 mVolumeComponent.dispatchDemoCommand(command, args);
3600 if (modeChange || command.equals(COMMAND_CLOCK)) {
3601 dispatchDemoCommandToView(command, args, R.id.clock);
3603 if (modeChange || command.equals(COMMAND_BATTERY)) {
3604 mBatteryController.dispatchDemoCommand(command, args);
3606 if (modeChange || command.equals(COMMAND_STATUS)) {
3607 mIconController.dispatchDemoCommand(command, args);
3609 if (mNetworkController != null && (modeChange || command.equals(COMMAND_NETWORK))) {
3610 mNetworkController.dispatchDemoCommand(command, args);
3612 if (modeChange || command.equals(COMMAND_NOTIFICATIONS)) {
3613 View notifications = mStatusBarView == null ? null
3614 : mStatusBarView.findViewById(R.id.notification_icon_area);
3615 if (notifications != null) {
3616 String visible = args.getString("visible");
3617 int vis = mDemoMode && "false".equals(visible) ? View.INVISIBLE : View.VISIBLE;
3618 notifications.setVisibility(vis);
3621 if (command.equals(COMMAND_BARS)) {
3622 String mode = args.getString("mode");
3623 int barMode = "opaque".equals(mode) ? MODE_OPAQUE :
3624 "translucent".equals(mode) ? MODE_TRANSLUCENT :
3625 "semi-transparent".equals(mode) ? MODE_SEMI_TRANSPARENT :
3626 "transparent".equals(mode) ? MODE_TRANSPARENT :
3627 "warning".equals(mode) ? MODE_WARNING :
3629 if (barMode != -1) {
3630 boolean animate = true;
3631 if (mStatusBarView != null) {
3632 mStatusBarView.getBarTransitions().transitionTo(barMode, animate);
3634 if (mNavigationBarView != null) {
3635 mNavigationBarView.getBarTransitions().transitionTo(barMode, animate);
3641 private void dispatchDemoCommandToView(String command, Bundle args, int id) {
3642 if (mStatusBarView == null) return;
3643 View v = mStatusBarView.findViewById(id);
3644 if (v instanceof DemoMode) {
3645 ((DemoMode)v).dispatchDemoCommand(command, args);
3650 * @return The {@link StatusBarState} the status bar is in.
3652 public int getBarState() {
3657 public boolean isPanelFullyCollapsed() {
3658 return mNotificationPanel.isFullyCollapsed();
3661 public void showKeyguard() {
3662 if (mLaunchTransitionFadingAway) {
3663 mNotificationPanel.animate().cancel();
3664 onLaunchTransitionFadingEnded();
3666 mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
3667 if (mUserSwitcherController != null && mUserSwitcherController.useFullscreenUserSwitcher()) {
3668 setBarState(StatusBarState.FULLSCREEN_USER_SWITCHER);
3670 setBarState(StatusBarState.KEYGUARD);
3672 updateKeyguardState(false /* goingToFullShade */, false /* fromShadeLocked */);
3673 if (!mDeviceInteractive) {
3675 // If the screen is off already, we need to disable touch events because these might
3676 // collapse the panel after we expanded it, and thus we would end up with a blank
3678 mNotificationPanel.setTouchDisabled(true);
3680 if (mState == StatusBarState.KEYGUARD) {
3681 instantExpandNotificationsPanel();
3682 } else if (mState == StatusBarState.FULLSCREEN_USER_SWITCHER) {
3683 instantCollapseNotificationPanel();
3685 mLeaveOpenOnKeyguardHide = false;
3686 if (mDraggedDownRow != null) {
3687 mDraggedDownRow.setUserLocked(false);
3688 mDraggedDownRow.notifyHeightChanged(false /* needsAnimation */);
3689 mDraggedDownRow = null;
3691 mPendingRemoteInputView = null;
3692 mAssistManager.onLockscreenShown();
3695 private void onLaunchTransitionFadingEnded() {
3696 mNotificationPanel.setAlpha(1.0f);
3697 mNotificationPanel.onAffordanceLaunchEnded();
3698 releaseGestureWakeLock();
3699 runLaunchTransitionEndRunnable();
3700 mLaunchTransitionFadingAway = false;
3701 mScrimController.forceHideScrims(false /* hide */);
3702 updateMediaMetaData(true /* metaDataChanged */, true);
3705 public boolean isCollapsing() {
3706 return mNotificationPanel.isCollapsing();
3709 public void addPostCollapseAction(Runnable r) {
3710 mPostCollapseRunnables.add(r);
3713 public boolean isInLaunchTransition() {
3714 return mNotificationPanel.isLaunchTransitionRunning()
3715 || mNotificationPanel.isLaunchTransitionFinished();
3719 * Fades the content of the keyguard away after the launch transition is done.
3721 * @param beforeFading the runnable to be run when the circle is fully expanded and the fading
3723 * @param endRunnable the runnable to be run when the transition is done
3725 public void fadeKeyguardAfterLaunchTransition(final Runnable beforeFading,
3726 Runnable endRunnable) {
3727 mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
3728 mLaunchTransitionEndRunnable = endRunnable;
3729 Runnable hideRunnable = new Runnable() {
3732 mLaunchTransitionFadingAway = true;
3733 if (beforeFading != null) {
3736 mScrimController.forceHideScrims(true /* hide */);
3737 updateMediaMetaData(false, true);
3738 mNotificationPanel.setAlpha(1);
3739 mNotificationPanel.animate()
3741 .setStartDelay(FADE_KEYGUARD_START_DELAY)
3742 .setDuration(FADE_KEYGUARD_DURATION)
3744 .withEndAction(new Runnable() {
3747 onLaunchTransitionFadingEnded();
3750 mIconController.appTransitionStarting(SystemClock.uptimeMillis(),
3751 StatusBarIconController.DEFAULT_TINT_ANIMATION_DURATION);
3754 if (mNotificationPanel.isLaunchTransitionRunning()) {
3755 mNotificationPanel.setLaunchTransitionEndRunnable(hideRunnable);
3762 * Fades the content of the Keyguard while we are dozing and makes it invisible when finished
3765 public void fadeKeyguardWhilePulsing() {
3766 mNotificationPanel.animate()
3769 .setDuration(FADE_KEYGUARD_DURATION_PULSING)
3770 .setInterpolator(ScrimController.KEYGUARD_FADE_OUT_INTERPOLATOR)
3775 * Starts the timeout when we try to start the affordances on Keyguard. We usually rely that
3776 * Keyguard goes away via fadeKeyguardAfterLaunchTransition, however, that might not happen
3777 * because the launched app crashed or something else went wrong.
3779 public void startLaunchTransitionTimeout() {
3780 mHandler.sendEmptyMessageDelayed(MSG_LAUNCH_TRANSITION_TIMEOUT,
3781 LAUNCH_TRANSITION_TIMEOUT_MS);
3784 private void onLaunchTransitionTimeout() {
3785 Log.w(TAG, "Launch transition: Timeout!");
3786 mNotificationPanel.onAffordanceLaunchEnded();
3787 releaseGestureWakeLock();
3788 mNotificationPanel.resetViews();
3791 private void runLaunchTransitionEndRunnable() {
3792 if (mLaunchTransitionEndRunnable != null) {
3793 Runnable r = mLaunchTransitionEndRunnable;
3795 // mLaunchTransitionEndRunnable might call showKeyguard, which would execute it again,
3796 // which would lead to infinite recursion. Protect against it.
3797 mLaunchTransitionEndRunnable = null;
3803 * @return true if we would like to stay in the shade, false if it should go away entirely
3805 public boolean hideKeyguard() {
3806 boolean staying = mLeaveOpenOnKeyguardHide;
3807 setBarState(StatusBarState.SHADE);
3808 View viewToClick = null;
3809 if (mLeaveOpenOnKeyguardHide) {
3810 mLeaveOpenOnKeyguardHide = false;
3811 long delay = calculateGoingToFullShadeDelay();
3812 mNotificationPanel.animateToFullShade(delay);
3813 if (mDraggedDownRow != null) {
3814 mDraggedDownRow.setUserLocked(false);
3815 mDraggedDownRow = null;
3817 viewToClick = mPendingRemoteInputView;
3818 mPendingRemoteInputView = null;
3820 // Disable layout transitions in navbar for this transition because the load is just
3821 // too heavy for the CPU and GPU on any device.
3822 if (mNavigationBarView != null) {
3823 mNavigationBarView.setLayoutTransitionsEnabled(false);
3824 mNavigationBarView.postDelayed(new Runnable() {
3827 mNavigationBarView.setLayoutTransitionsEnabled(true);
3829 }, delay + StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE);
3832 instantCollapseNotificationPanel();
3834 updateKeyguardState(staying, false /* fromShadeLocked */);
3836 if (viewToClick != null) {
3837 viewToClick.callOnClick();
3840 // Keyguard state has changed, but QS is not listening anymore. Make sure to update the tile
3841 // visibilities so next time we open the panel we know the correct height already.
3842 if (mQSPanel != null) {
3843 mQSPanel.refreshAllTiles();
3845 mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
3846 releaseGestureWakeLock();
3847 mNotificationPanel.onAffordanceLaunchEnded();
3848 mNotificationPanel.animate().cancel();
3849 mNotificationPanel.setAlpha(1f);
3853 private void releaseGestureWakeLock() {
3854 if (mGestureWakeLock.isHeld()) {
3855 mGestureWakeLock.release();
3859 public long calculateGoingToFullShadeDelay() {
3860 return mKeyguardFadingAwayDelay + mKeyguardFadingAwayDuration;
3864 * Notifies the status bar that Keyguard is going away very soon.
3866 public void keyguardGoingAway() {
3868 // Treat Keyguard exit animation as an app transition to achieve nice transition for status
3870 mKeyguardGoingAway = true;
3871 mIconController.appTransitionPending();
3875 * Notifies the status bar the Keyguard is fading away with the specified timings.
3877 * @param startTime the start time of the animations in uptime millis
3878 * @param delay the precalculated animation delay in miliseconds
3879 * @param fadeoutDuration the duration of the exit animation, in milliseconds
3881 public void setKeyguardFadingAway(long startTime, long delay, long fadeoutDuration) {
3882 mKeyguardFadingAway = true;
3883 mKeyguardFadingAwayDelay = delay;
3884 mKeyguardFadingAwayDuration = fadeoutDuration;
3885 mWaitingForKeyguardExit = false;
3886 mIconController.appTransitionStarting(
3887 startTime + fadeoutDuration
3888 - StatusBarIconController.DEFAULT_TINT_ANIMATION_DURATION,
3889 StatusBarIconController.DEFAULT_TINT_ANIMATION_DURATION);
3890 disable(mDisabledUnmodified1, mDisabledUnmodified2, fadeoutDuration > 0 /* animate */);
3893 public boolean isKeyguardFadingAway() {
3894 return mKeyguardFadingAway;
3898 * Notifies that the Keyguard fading away animation is done.
3900 public void finishKeyguardFadingAway() {
3901 mKeyguardFadingAway = false;
3902 mKeyguardGoingAway = false;
3905 public void stopWaitingForKeyguardExit() {
3906 mWaitingForKeyguardExit = false;
3909 private void updatePublicMode() {
3910 setLockscreenPublicMode(
3911 mStatusBarKeyguardViewManager.isShowing() && mStatusBarKeyguardViewManager
3912 .isSecure(mCurrentUserId));
3915 protected void updateKeyguardState(boolean goingToFullShade, boolean fromShadeLocked) {
3916 if (mState == StatusBarState.KEYGUARD) {
3917 mKeyguardIndicationController.setVisible(true);
3918 mNotificationPanel.resetViews();
3919 if (mKeyguardUserSwitcher != null) {
3920 mKeyguardUserSwitcher.setKeyguard(true, fromShadeLocked);
3922 mStatusBarView.removePendingHideExpandedRunnables();
3924 mKeyguardIndicationController.setVisible(false);
3925 if (mKeyguardUserSwitcher != null) {
3926 mKeyguardUserSwitcher.setKeyguard(false,
3928 mState == StatusBarState.SHADE_LOCKED ||
3932 if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
3933 mScrimController.setKeyguardShowing(true);
3934 mIconPolicy.setKeyguardShowing(true);
3936 mScrimController.setKeyguardShowing(false);
3937 mIconPolicy.setKeyguardShowing(false);
3940 mNotificationPanel.setBarState(mState, mKeyguardFadingAway, goingToFullShade);
3941 updateDozingState();
3943 updateStackScrollerState(goingToFullShade, fromShadeLocked);
3944 updateNotifications();
3946 updateMediaMetaData(false, mState != StatusBarState.KEYGUARD);
3947 mKeyguardMonitor.notifyKeyguardState(mStatusBarKeyguardViewManager.isShowing(),
3948 mStatusBarKeyguardViewManager.isSecure());
3951 private void updateDozingState() {
3952 boolean animate = !mDozing && mDozeScrimController.isPulsing();
3953 mNotificationPanel.setDozing(mDozing, animate);
3954 mStackScroller.setDark(mDozing, animate, mWakeUpTouchLocation);
3955 mScrimController.setDozing(mDozing);
3957 // Immediately abort the dozing from the doze scrim controller in case of wake-and-unlock
3958 // for pulsing so the Keyguard fade-out animation scrim can take over.
3959 mDozeScrimController.setDozing(mDozing &&
3960 mFingerprintUnlockController.getMode()
3961 != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING, animate);
3964 public void updateStackScrollerState(boolean goingToFullShade, boolean fromShadeLocked) {
3965 if (mStackScroller == null) return;
3966 boolean onKeyguard = mState == StatusBarState.KEYGUARD;
3967 mStackScroller.setHideSensitive(isLockscreenPublicMode(), goingToFullShade);
3968 mStackScroller.setDimmed(onKeyguard, fromShadeLocked /* animate */);
3969 mStackScroller.setExpandingEnabled(!onKeyguard);
3970 ActivatableNotificationView activatedChild = mStackScroller.getActivatedChild();
3971 mStackScroller.setActivatedChild(null);
3972 if (activatedChild != null) {
3973 activatedChild.makeInactive(false /* animate */);
3977 public void userActivity() {
3978 if (mState == StatusBarState.KEYGUARD) {
3979 mKeyguardViewMediatorCallback.userActivity();
3983 public boolean interceptMediaKey(KeyEvent event) {
3984 return mState == StatusBarState.KEYGUARD
3985 && mStatusBarKeyguardViewManager.interceptMediaKey(event);
3988 public boolean onMenuPressed() {
3989 if (mDeviceInteractive && mState != StatusBarState.SHADE
3990 && mStatusBarKeyguardViewManager.shouldDismissOnMenuPressed()) {
3991 animateCollapsePanels(
3992 CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL /* flags */, true /* force */);
3998 public void endAffordanceLaunch() {
3999 releaseGestureWakeLock();
4000 mNotificationPanel.onAffordanceLaunchEnded();
4003 public boolean onBackPressed() {
4004 if (mStatusBarKeyguardViewManager.onBackPressed()) {
4007 if (mNotificationPanel.isQsExpanded()) {
4008 if (mNotificationPanel.isQsDetailShowing()) {
4009 mNotificationPanel.closeQsDetail();
4011 mNotificationPanel.animateCloseQs();
4015 if (mState != StatusBarState.KEYGUARD && mState != StatusBarState.SHADE_LOCKED) {
4016 animateCollapsePanels();
4022 public boolean onSpacePressed() {
4023 if (mDeviceInteractive && mState != StatusBarState.SHADE) {
4024 animateCollapsePanels(
4025 CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL /* flags */, true /* force */);
4031 private void showBouncer() {
4032 if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
4033 mWaitingForKeyguardExit = mStatusBarKeyguardViewManager.isShowing();
4034 mStatusBarKeyguardViewManager.dismiss();
4038 private void instantExpandNotificationsPanel() {
4040 // Make our window larger and the panel expanded.
4041 makeExpandedVisible(true);
4042 mNotificationPanel.expand(false /* animate */);
4045 private void instantCollapseNotificationPanel() {
4046 mNotificationPanel.instantCollapse();
4050 public void onActivated(ActivatableNotificationView view) {
4051 EventLogTags.writeSysuiLockscreenGesture(
4052 EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_TAP_NOTIFICATION_ACTIVATE,
4053 0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */);
4054 mKeyguardIndicationController.showTransientIndication(R.string.notification_tap_again);
4055 ActivatableNotificationView previousView = mStackScroller.getActivatedChild();
4056 if (previousView != null) {
4057 previousView.makeInactive(true /* animate */);
4059 mStackScroller.setActivatedChild(view);
4063 * @param state The {@link StatusBarState} to set.
4065 public void setBarState(int state) {
4066 // If we're visible and switched to SHADE_LOCKED (the user dragged
4067 // down on the lockscreen), clear notification LED, vibration,
4069 // Other transitions are covered in handleVisibleToUserChanged().
4070 if (state != mState && mVisible && (state == StatusBarState.SHADE_LOCKED
4071 || (state == StatusBarState.SHADE && isGoingToNotificationShade()))) {
4072 clearNotificationEffects();
4075 mGroupManager.setStatusBarState(state);
4076 mFalsingManager.setStatusBarState(state);
4077 mStatusBarWindowManager.setStatusBarState(state);
4082 public void onActivationReset(ActivatableNotificationView view) {
4083 if (view == mStackScroller.getActivatedChild()) {
4084 mKeyguardIndicationController.hideTransientIndication();
4085 mStackScroller.setActivatedChild(null);
4089 public void onTrackingStarted() {
4090 runPostCollapseRunnables();
4093 public void onClosingFinished() {
4094 runPostCollapseRunnables();
4097 public void onUnlockHintStarted() {
4098 mFalsingManager.onUnlockHintStarted();
4099 mKeyguardIndicationController.showTransientIndication(R.string.keyguard_unlock);
4102 public void onHintFinished() {
4103 // Delay the reset a bit so the user can read the text.
4104 mKeyguardIndicationController.hideTransientIndicationDelayed(HINT_RESET_DELAY_MS);
4107 public void onCameraHintStarted() {
4108 mFalsingManager.onCameraHintStarted();
4109 mKeyguardIndicationController.showTransientIndication(R.string.camera_hint);
4112 public void onVoiceAssistHintStarted() {
4113 mFalsingManager.onLeftAffordanceHintStarted();
4114 mKeyguardIndicationController.showTransientIndication(R.string.voice_hint);
4117 public void onPhoneHintStarted() {
4118 mFalsingManager.onLeftAffordanceHintStarted();
4119 mKeyguardIndicationController.showTransientIndication(R.string.phone_hint);
4122 public void onTrackingStopped(boolean expand) {
4123 if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
4124 if (!expand && !mUnlockMethodCache.canSkipBouncer()) {
4131 protected int getMaxKeyguardNotifications(boolean recompute) {
4133 mMaxKeyguardNotifications = Math.max(1,
4134 mNotificationPanel.computeMaxKeyguardNotifications(
4135 mMaxAllowedKeyguardNotifications));
4136 return mMaxKeyguardNotifications;
4138 return mMaxKeyguardNotifications;
4141 public int getMaxKeyguardNotifications() {
4142 return getMaxKeyguardNotifications(false /* recompute */);
4145 public NavigationBarView getNavigationBarView() {
4146 return mNavigationBarView;
4149 // ---------------------- DragDownHelper.OnDragDownListener ------------------------------------
4152 public boolean onDraggedDown(View startingChild, int dragLengthY) {
4153 if (hasActiveNotifications()) {
4154 EventLogTags.writeSysuiLockscreenGesture(
4155 EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_SWIPE_DOWN_FULL_SHADE,
4156 (int) (dragLengthY / mDisplayMetrics.density),
4157 0 /* velocityDp - N/A */);
4159 // We have notifications, go to locked shade.
4160 goToLockedShade(startingChild);
4164 // No notifications - abort gesture.
4170 public void onDragDownReset() {
4171 mStackScroller.setDimmed(true /* dimmed */, true /* animated */);
4172 mStackScroller.resetScrollPosition();
4176 public void onCrossedThreshold(boolean above) {
4177 mStackScroller.setDimmed(!above /* dimmed */, true /* animate */);
4181 public void onTouchSlopExceeded() {
4182 mStackScroller.removeLongPressCallback();
4186 public void setEmptyDragAmount(float amount) {
4187 mNotificationPanel.setEmptyDragAmount(amount);
4191 * If secure with redaction: Show bouncer, go to unlocked shade.
4193 * <p>If secure without redaction or no security: Go to {@link StatusBarState#SHADE_LOCKED}.</p>
4195 * @param expandView The view to expand after going to the shade.
4197 public void goToLockedShade(View expandView) {
4198 ExpandableNotificationRow row = null;
4199 if (expandView instanceof ExpandableNotificationRow) {
4200 row = (ExpandableNotificationRow) expandView;
4201 row.setUserExpanded(true /* userExpanded */, true /* allowChildExpansion */);
4203 boolean fullShadeNeedsBouncer = !userAllowsPrivateNotificationsInPublic(mCurrentUserId)
4204 || !mShowLockscreenNotifications || mFalsingManager.shouldEnforceBouncer();
4205 if (isLockscreenPublicMode() && fullShadeNeedsBouncer) {
4206 mLeaveOpenOnKeyguardHide = true;
4208 mDraggedDownRow = row;
4209 mPendingRemoteInputView = null;
4211 mNotificationPanel.animateToFullShade(0 /* delay */);
4212 setBarState(StatusBarState.SHADE_LOCKED);
4213 updateKeyguardState(false /* goingToFullShade */, false /* fromShadeLocked */);
4218 public void onLockedNotificationImportanceChange(OnDismissAction dismissAction) {
4219 mLeaveOpenOnKeyguardHide = true;
4220 dismissKeyguardThenExecute(dismissAction, true /* afterKeyguardGone */);
4224 protected void onLockedRemoteInput(ExpandableNotificationRow row, View clicked) {
4225 mLeaveOpenOnKeyguardHide = true;
4227 mPendingRemoteInputView = clicked;
4231 public void onExpandClicked(Entry clickedEntry, boolean nowExpanded) {
4232 mHeadsUpManager.setExpanded(clickedEntry, nowExpanded);
4233 if (mState == StatusBarState.KEYGUARD && nowExpanded) {
4234 goToLockedShade(clickedEntry.row);
4239 * Goes back to the keyguard after hanging around in {@link StatusBarState#SHADE_LOCKED}.
4241 public void goToKeyguard() {
4242 if (mState == StatusBarState.SHADE_LOCKED) {
4243 mStackScroller.onGoToKeyguard();
4244 setBarState(StatusBarState.KEYGUARD);
4245 updateKeyguardState(false /* goingToFullShade */, true /* fromShadeLocked*/);
4249 public long getKeyguardFadingAwayDelay() {
4250 return mKeyguardFadingAwayDelay;
4253 public long getKeyguardFadingAwayDuration() {
4254 return mKeyguardFadingAwayDuration;
4258 public void setBouncerShowing(boolean bouncerShowing) {
4259 super.setBouncerShowing(bouncerShowing);
4260 mStatusBarView.setBouncerShowing(bouncerShowing);
4261 disable(mDisabledUnmodified1, mDisabledUnmodified2, true /* animate */);
4264 public void onStartedGoingToSleep() {
4265 mStartedGoingToSleep = true;
4268 public void onFinishedGoingToSleep() {
4269 mNotificationPanel.onAffordanceLaunchEnded();
4270 releaseGestureWakeLock();
4271 mLaunchCameraOnScreenTurningOn = false;
4272 mStartedGoingToSleep = false;
4273 mDeviceInteractive = false;
4274 mWakeUpComingFromTouch = false;
4275 mWakeUpTouchLocation = null;
4276 mStackScroller.setAnimationsEnabled(false);
4277 updateVisibleToUser();
4278 if (mLaunchCameraOnFinishedGoingToSleep) {
4279 mLaunchCameraOnFinishedGoingToSleep = false;
4281 // This gets executed before we will show Keyguard, so post it in order that the state
4283 mHandler.post(new Runnable() {
4286 onCameraLaunchGestureDetected(mLastCameraLaunchSource);
4292 public void onStartedWakingUp() {
4293 mDeviceInteractive = true;
4294 mStackScroller.setAnimationsEnabled(true);
4295 mNotificationPanel.setTouchDisabled(false);
4296 updateVisibleToUser();
4299 public void onScreenTurningOn() {
4300 mScreenTurningOn = true;
4301 mFalsingManager.onScreenTurningOn();
4302 mNotificationPanel.onScreenTurningOn();
4303 if (mLaunchCameraOnScreenTurningOn) {
4304 mNotificationPanel.launchCamera(false, mLastCameraLaunchSource);
4305 mLaunchCameraOnScreenTurningOn = false;
4309 private void vibrateForCameraGesture() {
4310 // Make sure to pass -1 for repeat so VibratorService doesn't stop us when going to sleep.
4311 mVibrator.vibrate(new long[]{0, 750L}, -1 /* repeat */);
4314 public void onScreenTurnedOn() {
4315 mScreenTurningOn = false;
4316 mDozeScrimController.onScreenTurnedOn();
4320 * Handles long press for back button. This exits screen pinning.
4322 private boolean handleLongPressBack() {
4324 IActivityManager activityManager = ActivityManagerNative.getDefault();
4325 if (activityManager.isInLockTaskMode()) {
4326 activityManager.stopSystemLockTaskMode();
4328 // When exiting refresh disabled flags.
4329 mNavigationBarView.setDisabledFlags(mDisabled1, true);
4332 } catch (RemoteException e) {
4333 Log.d(TAG, "Unable to reach activity manager", e);
4338 public void updateRecentsVisibility(boolean visible) {
4339 // Update the recents visibility flag
4341 mSystemUiVisibility |= View.RECENT_APPS_VISIBLE;
4343 mSystemUiVisibility &= ~View.RECENT_APPS_VISIBLE;
4345 notifyUiVisibilityChanged(mSystemUiVisibility);
4349 public void showScreenPinningRequest(int taskId) {
4350 if (mKeyguardMonitor.isShowing()) {
4351 // Don't allow apps to trigger this from keyguard.
4354 // Show screen pinning request, since this comes from an app, show 'no thanks', button.
4355 showScreenPinningRequest(taskId, true);
4358 public void showScreenPinningRequest(int taskId, boolean allowCancel) {
4359 mScreenPinningRequest.showPrompt(taskId, allowCancel);
4362 public boolean hasActiveNotifications() {
4363 return !mNotificationData.getActiveNotifications().isEmpty();
4366 public void wakeUpIfDozing(long time, MotionEvent event) {
4367 if (mDozing && mDozeScrimController.isPulsing()) {
4368 PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
4369 pm.wakeUp(time, "com.android.systemui:NODOZE");
4370 mWakeUpComingFromTouch = true;
4371 mWakeUpTouchLocation = new PointF(event.getX(), event.getY());
4372 mNotificationPanel.setTouchDisabled(false);
4373 mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested();
4374 mFalsingManager.onScreenOnFromTouch();
4379 public void appTransitionPending() {
4381 // Use own timings when Keyguard is going away, see keyguardGoingAway and
4382 // setKeyguardFadingAway
4383 if (!mKeyguardFadingAway) {
4384 mIconController.appTransitionPending();
4389 public void appTransitionCancelled() {
4390 mIconController.appTransitionCancelled();
4391 EventBus.getDefault().send(new AppTransitionFinishedEvent());
4395 public void appTransitionStarting(long startTime, long duration) {
4397 // Use own timings when Keyguard is going away, see keyguardGoingAway and
4398 // setKeyguardFadingAway.
4399 if (!mKeyguardGoingAway) {
4400 mIconController.appTransitionStarting(startTime, duration);
4402 if (mIconPolicy != null) {
4403 mIconPolicy.appTransitionStarting(startTime, duration);
4408 public void appTransitionFinished() {
4409 EventBus.getDefault().send(new AppTransitionFinishedEvent());
4413 public void onCameraLaunchGestureDetected(int source) {
4414 mLastCameraLaunchSource = source;
4415 if (mStartedGoingToSleep) {
4416 mLaunchCameraOnFinishedGoingToSleep = true;
4419 if (!mNotificationPanel.canCameraGestureBeLaunched(
4420 mStatusBarKeyguardViewManager.isShowing() && mExpandedVisible)) {
4423 if (!mDeviceInteractive) {
4424 PowerManager pm = mContext.getSystemService(PowerManager.class);
4425 pm.wakeUp(SystemClock.uptimeMillis(), "com.android.systemui:CAMERA_GESTURE");
4426 mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested();
4428 vibrateForCameraGesture();
4429 if (!mStatusBarKeyguardViewManager.isShowing()) {
4430 startActivity(KeyguardBottomAreaView.INSECURE_CAMERA_INTENT,
4431 true /* dismissShade */);
4433 if (!mDeviceInteractive) {
4434 // Avoid flickering of the scrim when we instant launch the camera and the bouncer
4436 mScrimController.dontAnimateBouncerChangesUntilNextFrame();
4437 mGestureWakeLock.acquire(LAUNCH_TRANSITION_TIMEOUT_MS + 1000L);
4439 if (mScreenTurningOn || mStatusBarKeyguardViewManager.isScreenTurnedOn()) {
4440 mNotificationPanel.launchCamera(mDeviceInteractive /* animate */, source);
4442 // We need to defer the camera launch until the screen comes on, since otherwise
4443 // we will dismiss us too early since we are waiting on an activity to be drawn and
4444 // incorrectly get notified because of the screen on event (which resumes and pauses
4446 mLaunchCameraOnScreenTurningOn = true;
4452 public void requestTvPictureInPicture() {
4456 public void notifyFpAuthModeChanged() {
4460 private void updateDozing() {
4461 // When in wake-and-unlock while pulsing, keep dozing state until fully unlocked.
4462 mDozing = mDozingRequested && mState == StatusBarState.KEYGUARD
4463 || mFingerprintUnlockController.getMode()
4464 == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING;
4465 updateDozingState();
4468 private final class ShadeUpdates {
4469 private final ArraySet<String> mVisibleNotifications = new ArraySet<String>();
4470 private final ArraySet<String> mNewVisibleNotifications = new ArraySet<String>();
4472 public void check() {
4473 mNewVisibleNotifications.clear();
4474 ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
4475 for (int i = 0; i < activeNotifications.size(); i++) {
4476 final Entry entry = activeNotifications.get(i);
4477 final boolean visible = entry.row != null
4478 && entry.row.getVisibility() == View.VISIBLE;
4480 mNewVisibleNotifications.add(entry.key + entry.notification.getPostTime());
4483 final boolean updates = !mVisibleNotifications.containsAll(mNewVisibleNotifications);
4484 mVisibleNotifications.clear();
4485 mVisibleNotifications.addAll(mNewVisibleNotifications);
4487 // We have new notifications
4488 if (updates && mDozeServiceHost != null) {
4489 mDozeServiceHost.fireNewNotifications();
4494 private final class DozeServiceHost extends KeyguardUpdateMonitorCallback implements DozeHost {
4495 // Amount of time to allow to update the time shown on the screen before releasing
4496 // the wakelock. This timeout is design to compensate for the fact that we don't
4497 // currently have a way to know when time display contents have actually been
4498 // refreshed once we've finished rendering a new frame.
4499 private static final long PROCESSING_TIME = 500;
4501 private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
4502 private final H mHandler = new H();
4504 // Keeps the last reported state by fireNotificationLight.
4505 private boolean mNotificationLightOn;
4508 public String toString() {
4509 return "PSB.DozeServiceHost[mCallbacks=" + mCallbacks.size() + "]";
4512 public void firePowerSaveChanged(boolean active) {
4513 for (Callback callback : mCallbacks) {
4514 callback.onPowerSaveChanged(active);
4518 public void fireBuzzBeepBlinked() {
4519 for (Callback callback : mCallbacks) {
4520 callback.onBuzzBeepBlinked();
4524 public void fireNotificationLight(boolean on) {
4525 mNotificationLightOn = on;
4526 for (Callback callback : mCallbacks) {
4527 callback.onNotificationLight(on);
4531 public void fireNewNotifications() {
4532 for (Callback callback : mCallbacks) {
4533 callback.onNewNotifications();
4538 public void addCallback(@NonNull Callback callback) {
4539 mCallbacks.add(callback);
4543 public void removeCallback(@NonNull Callback callback) {
4544 mCallbacks.remove(callback);
4548 public void startDozing(@NonNull Runnable ready) {
4549 mHandler.obtainMessage(H.MSG_START_DOZING, ready).sendToTarget();
4553 public void pulseWhileDozing(@NonNull PulseCallback callback, int reason) {
4554 mHandler.obtainMessage(H.MSG_PULSE_WHILE_DOZING, reason, 0, callback).sendToTarget();
4558 public void stopDozing() {
4559 mHandler.obtainMessage(H.MSG_STOP_DOZING).sendToTarget();
4563 public boolean isPowerSaveActive() {
4564 return mBatteryController != null && mBatteryController.isPowerSave();
4568 public boolean isPulsingBlocked() {
4569 return mFingerprintUnlockController.getMode()
4570 == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK;
4574 public boolean isNotificationLightOn() {
4575 return mNotificationLightOn;
4578 private void handleStartDozing(@NonNull Runnable ready) {
4579 if (!mDozingRequested) {
4580 mDozingRequested = true;
4581 DozeLog.traceDozing(mContext, mDozing);
4587 private void handlePulseWhileDozing(@NonNull PulseCallback callback, int reason) {
4588 mDozeScrimController.pulse(new PulseCallback() {
4591 public void onPulseStarted() {
4592 callback.onPulseStarted();
4593 mStackScroller.setPulsing(true);
4597 public void onPulseFinished() {
4598 callback.onPulseFinished();
4599 mStackScroller.setPulsing(false);
4604 private void handleStopDozing() {
4605 if (mDozingRequested) {
4606 mDozingRequested = false;
4607 DozeLog.traceDozing(mContext, mDozing);
4612 private final class H extends Handler {
4613 private static final int MSG_START_DOZING = 1;
4614 private static final int MSG_PULSE_WHILE_DOZING = 2;
4615 private static final int MSG_STOP_DOZING = 3;
4618 public void handleMessage(Message msg) {
4620 case MSG_START_DOZING:
4621 handleStartDozing((Runnable) msg.obj);
4623 case MSG_PULSE_WHILE_DOZING:
4624 handlePulseWhileDozing((PulseCallback) msg.obj, msg.arg1);
4626 case MSG_STOP_DOZING: