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;
19 import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT;
20 import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
21 import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
22 import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
23 import static android.app.StatusBarManager.windowStateToString;
24 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
26 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP;
27 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
28 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_WAKING;
29 import static com.android.systemui.shared.system.WindowManagerWrapper.NAV_BAR_POS_LEFT;
30 import static com.android.systemui.shared.system.WindowManagerWrapper.NAV_BAR_POS_INVALID;
31 import static com.android.systemui.statusbar.NotificationLockscreenUserManager
32 .NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION;
33 import static com.android.systemui.statusbar.NotificationLockscreenUserManager.PERMISSION_SELF;
34 import static com.android.systemui.statusbar.NotificationMediaManager.DEBUG_MEDIA;
35 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
36 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
37 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
38 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
39 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSLUCENT;
40 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
41 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_WARNING;
43 import android.animation.Animator;
44 import android.animation.AnimatorListenerAdapter;
45 import android.annotation.NonNull;
46 import android.annotation.Nullable;
47 import android.app.ActivityManager;
48 import android.app.ActivityOptions;
49 import android.app.ActivityTaskManager;
50 import android.app.AlarmManager;
51 import android.app.IWallpaperManager;
52 import android.app.KeyguardManager;
53 import android.app.Notification;
54 import android.app.NotificationManager;
55 import android.app.PendingIntent;
56 import android.app.StatusBarManager;
57 import android.app.TaskStackBuilder;
58 import android.app.UiModeManager;
59 import android.app.WallpaperColors;
60 import android.app.WallpaperInfo;
61 import android.app.WallpaperManager;
62 import android.app.admin.DevicePolicyManager;
63 import android.content.BroadcastReceiver;
64 import android.content.ComponentCallbacks2;
65 import android.content.ComponentName;
66 import android.content.Context;
67 import android.content.Intent;
68 import android.content.IntentFilter;
69 import android.content.IntentSender;
70 import android.content.om.IOverlayManager;
71 import android.content.om.OverlayInfo;
72 import android.content.pm.IPackageManager;
73 import android.content.pm.PackageManager;
74 import android.content.pm.PackageManager.NameNotFoundException;
75 import android.content.pm.UserInfo;
76 import android.content.res.Configuration;
77 import android.content.res.Resources;
78 import android.graphics.Bitmap;
79 import android.graphics.Point;
80 import android.graphics.PointF;
81 import android.graphics.PorterDuff;
82 import android.graphics.PorterDuffXfermode;
83 import android.graphics.Rect;
84 import android.graphics.drawable.BitmapDrawable;
85 import android.graphics.drawable.ColorDrawable;
86 import android.graphics.drawable.Drawable;
87 import android.media.AudioAttributes;
88 import android.media.MediaMetadata;
89 import android.metrics.LogMaker;
90 import android.net.Uri;
91 import android.os.AsyncTask;
92 import android.os.Bundle;
93 import android.os.Handler;
94 import android.os.IBinder;
95 import android.os.Looper;
96 import android.os.Message;
97 import android.os.PowerManager;
98 import android.os.RemoteException;
99 import android.os.ServiceManager;
100 import android.os.SystemClock;
101 import android.os.SystemProperties;
102 import android.os.Trace;
103 import android.os.UserHandle;
104 import android.os.UserManager;
105 import android.os.VibrationEffect;
106 import android.os.Vibrator;
107 import android.provider.Settings;
108 import android.service.notification.StatusBarNotification;
109 import android.service.vr.IVrManager;
110 import android.service.vr.IVrStateCallbacks;
111 import android.text.TextUtils;
112 import android.util.DisplayMetrics;
113 import android.util.EventLog;
114 import android.util.Log;
115 import android.util.Slog;
116 import android.util.SparseArray;
117 import android.view.Display;
118 import android.view.IWindowManager;
119 import android.view.KeyEvent;
120 import android.view.LayoutInflater;
121 import android.view.MotionEvent;
122 import android.view.RemoteAnimationAdapter;
123 import android.view.ThreadedRenderer;
124 import android.view.View;
125 import android.view.ViewGroup;
126 import android.view.ViewParent;
127 import android.view.ViewTreeObserver;
128 import android.view.WindowManager;
129 import android.view.WindowManagerGlobal;
130 import android.view.accessibility.AccessibilityManager;
131 import android.view.animation.AccelerateInterpolator;
132 import android.widget.DateTimeView;
133 import android.widget.ImageView;
134 import android.widget.TextView;
136 import com.android.internal.annotations.VisibleForTesting;
137 import com.android.internal.colorextraction.ColorExtractor;
138 import com.android.internal.logging.MetricsLogger;
139 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
140 import com.android.internal.statusbar.IStatusBarService;
141 import com.android.internal.statusbar.NotificationVisibility;
142 import com.android.internal.statusbar.StatusBarIcon;
143 import com.android.internal.widget.LockPatternUtils;
144 import com.android.internal.widget.MessagingGroup;
145 import com.android.internal.widget.MessagingMessage;
146 import com.android.keyguard.KeyguardHostView.OnDismissAction;
147 import com.android.keyguard.KeyguardUpdateMonitor;
148 import com.android.keyguard.KeyguardUpdateMonitorCallback;
149 import com.android.keyguard.ViewMediatorCallback;
150 import com.android.systemui.ActivityStarterDelegate;
151 import com.android.systemui.AutoReinflateContainer;
152 import com.android.systemui.DemoMode;
153 import com.android.systemui.Dependency;
154 import com.android.systemui.EventLogTags;
155 import com.android.systemui.Interpolators;
156 import com.android.systemui.Prefs;
157 import com.android.systemui.R;
158 import com.android.systemui.RecentsComponent;
159 import com.android.systemui.SystemUI;
160 import com.android.systemui.SystemUIFactory;
161 import com.android.systemui.UiOffloadThread;
162 import com.android.systemui.assist.AssistManager;
163 import com.android.systemui.charging.WirelessChargingAnimation;
164 import com.android.systemui.classifier.FalsingLog;
165 import com.android.systemui.classifier.FalsingManager;
166 import com.android.systemui.colorextraction.SysuiColorExtractor;
167 import com.android.systemui.doze.DozeHost;
168 import com.android.systemui.doze.DozeLog;
169 import com.android.systemui.doze.DozeReceiver;
170 import com.android.systemui.fragments.ExtensionFragmentListener;
171 import com.android.systemui.fragments.FragmentHostManager;
172 import com.android.systemui.keyguard.KeyguardViewMediator;
173 import com.android.systemui.keyguard.ScreenLifecycle;
174 import com.android.systemui.keyguard.WakefulnessLifecycle;
175 import com.android.systemui.plugins.ActivityStarter;
176 import com.android.systemui.plugins.qs.QS;
177 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption;
178 import com.android.systemui.qs.QSFragment;
179 import com.android.systemui.qs.QSPanel;
180 import com.android.systemui.qs.QSTileHost;
181 import com.android.systemui.qs.car.CarQSFragment;
182 import com.android.systemui.recents.Recents;
183 import com.android.systemui.recents.ScreenPinningRequest;
184 import com.android.systemui.recents.events.EventBus;
185 import com.android.systemui.recents.events.activity.AppTransitionFinishedEvent;
186 import com.android.systemui.recents.events.activity.UndockingTaskEvent;
187 import com.android.systemui.recents.misc.SystemServicesProxy;
188 import com.android.systemui.shared.system.WindowManagerWrapper;
189 import com.android.systemui.stackdivider.Divider;
190 import com.android.systemui.stackdivider.WindowManagerProxy;
191 import com.android.systemui.statusbar.ActivatableNotificationView;
192 import com.android.systemui.statusbar.AppOpsListener;
193 import com.android.systemui.statusbar.BackDropView;
194 import com.android.systemui.statusbar.CommandQueue;
195 import com.android.systemui.statusbar.CrossFadeHelper;
196 import com.android.systemui.statusbar.DragDownHelper;
197 import com.android.systemui.statusbar.EmptyShadeView;
198 import com.android.systemui.statusbar.ExpandableNotificationRow;
199 import com.android.systemui.statusbar.FooterView;
200 import com.android.systemui.statusbar.GestureRecorder;
201 import com.android.systemui.statusbar.KeyboardShortcuts;
202 import com.android.systemui.statusbar.KeyguardIndicationController;
203 import com.android.systemui.statusbar.NotificationData;
204 import com.android.systemui.statusbar.NotificationData.Entry;
205 import com.android.systemui.statusbar.NotificationEntryManager;
206 import com.android.systemui.statusbar.NotificationGutsManager;
207 import com.android.systemui.statusbar.NotificationInfo;
208 import com.android.systemui.statusbar.NotificationListener;
209 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
210 import com.android.systemui.statusbar.NotificationLogger;
211 import com.android.systemui.statusbar.NotificationMediaManager;
212 import com.android.systemui.statusbar.NotificationPresenter;
213 import com.android.systemui.statusbar.NotificationRemoteInputManager;
214 import com.android.systemui.statusbar.NotificationShelf;
215 import com.android.systemui.statusbar.NotificationViewHierarchyManager;
216 import com.android.systemui.statusbar.RemoteInputController;
217 import com.android.systemui.statusbar.ScrimView;
218 import com.android.systemui.statusbar.StatusBarState;
219 import com.android.systemui.statusbar.VibratorHelper;
220 import com.android.systemui.statusbar.notification.AboveShelfObserver;
221 import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
222 import com.android.systemui.statusbar.notification.VisualStabilityManager;
223 import com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChangedListener;
224 import com.android.systemui.statusbar.policy.BatteryController;
225 import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
226 import com.android.systemui.statusbar.policy.BrightnessMirrorController;
227 import com.android.systemui.statusbar.policy.ConfigurationController;
228 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
229 import com.android.systemui.statusbar.policy.DarkIconDispatcher;
230 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
231 import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
232 import com.android.systemui.statusbar.policy.ExtensionController;
233 import com.android.systemui.statusbar.policy.HeadsUpManager;
234 import com.android.systemui.statusbar.policy.HeadsUpUtil;
235 import com.android.systemui.statusbar.policy.KeyguardMonitor;
236 import com.android.systemui.statusbar.policy.KeyguardMonitorImpl;
237 import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
238 import com.android.systemui.statusbar.policy.NetworkController;
239 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
240 import com.android.systemui.statusbar.policy.PreviewInflater;
241 import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
242 import com.android.systemui.statusbar.policy.UserInfoController;
243 import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
244 import com.android.systemui.statusbar.policy.UserSwitcherController;
245 import com.android.systemui.statusbar.policy.ZenModeController;
246 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
247 import com.android.systemui.volume.VolumeComponent;
249 import java.io.FileDescriptor;
250 import java.io.PrintWriter;
251 import java.io.StringWriter;
252 import java.util.ArrayList;
253 import java.util.List;
254 import java.util.Map;
256 public class StatusBar extends SystemUI implements DemoMode,
257 DragDownHelper.DragDownCallback, ActivityStarter, OnUnlockMethodChangedListener,
258 OnHeadsUpChangedListener, CommandQueue.Callbacks, ZenModeController.Callback,
259 ColorExtractor.OnColorsChangedListener, ConfigurationListener, NotificationPresenter {
260 public static final boolean MULTIUSER_DEBUG = false;
262 public static final boolean ENABLE_CHILD_NOTIFICATIONS
263 = SystemProperties.getBoolean("debug.child_notifs", true);
265 protected static final int MSG_HIDE_RECENT_APPS = 1020;
266 protected static final int MSG_PRELOAD_RECENT_APPS = 1022;
267 protected static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 1023;
268 protected static final int MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU = 1026;
269 protected static final int MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU = 1027;
271 // Should match the values in PhoneWindowManager
272 public static final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
273 public static final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
274 static public final String SYSTEM_DIALOG_REASON_SCREENSHOT = "screenshot";
276 private static final String BANNER_ACTION_CANCEL =
277 "com.android.systemui.statusbar.banner_action_cancel";
278 private static final String BANNER_ACTION_SETUP =
279 "com.android.systemui.statusbar.banner_action_setup";
280 public static final String TAG = "StatusBar";
281 public static final boolean DEBUG = false;
282 public static final boolean SPEW = false;
283 public static final boolean DUMPTRUCK = true; // extra dumpsys info
284 public static final boolean DEBUG_GESTURES = false;
285 public static final boolean DEBUG_MEDIA_FAKE_ARTWORK = false;
286 public static final boolean DEBUG_CAMERA_LIFT = false;
288 public static final boolean DEBUG_WINDOW_STATE = false;
290 // additional instrumentation for testing purposes; intended to be left on during development
291 public static final boolean CHATTY = DEBUG;
293 public static final boolean SHOW_LOCKSCREEN_MEDIA_ARTWORK = true;
295 public static final String ACTION_FAKE_ARTWORK = "fake_artwork";
297 private static final int MSG_OPEN_NOTIFICATION_PANEL = 1000;
298 private static final int MSG_CLOSE_PANELS = 1001;
299 private static final int MSG_OPEN_SETTINGS_PANEL = 1002;
300 private static final int MSG_LAUNCH_TRANSITION_TIMEOUT = 1003;
301 // 1020-1040 reserved for BaseStatusBar
303 // Time after we abort the launch transition.
304 private static final long LAUNCH_TRANSITION_TIMEOUT_MS = 5000;
306 protected static final boolean CLOSE_PANEL_WHEN_EMPTIED = true;
308 private static final int STATUS_OR_NAV_TRANSIENT =
309 View.STATUS_BAR_TRANSIENT | View.NAVIGATION_BAR_TRANSIENT;
310 private static final long AUTOHIDE_TIMEOUT_MS = 2250;
313 * The delay to reset the hint text when the hint animation is finished running.
315 private static final int HINT_RESET_DELAY_MS = 1200;
317 private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
318 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
319 .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
322 public static final int FADE_KEYGUARD_START_DELAY = 100;
323 public static final int FADE_KEYGUARD_DURATION = 300;
324 public static final int FADE_KEYGUARD_DURATION_PULSING = 96;
326 /** If true, the system is in the half-boot-to-decryption-screen state.
327 * Prudently disable QS and notifications. */
328 private static final boolean ONLY_CORE_APPS;
330 /** If true, the lockscreen will show a distinct wallpaper */
331 private static final boolean ENABLE_LOCKSCREEN_WALLPAPER = true;
334 * Never let the alpha become zero for surfaces that draw with SRC - otherwise the RenderNode
335 * won't draw anything and uninitialized memory will show through
336 * if mScrimSrcModeEnabled. Note that 0.001 is rounded down to 0 in
339 private static final float SRC_MIN_ALPHA = 0.002f;
342 boolean onlyCoreApps;
344 IPackageManager packageManager =
345 IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
346 onlyCoreApps = packageManager.isOnlyCoreApps();
347 } catch (RemoteException e) {
348 onlyCoreApps = false;
350 ONLY_CORE_APPS = onlyCoreApps;
354 * The {@link StatusBarState} of the status bar.
356 protected int mState;
357 protected boolean mBouncerShowing;
359 private PhoneStatusBarPolicy mIconPolicy;
360 private StatusBarSignalPolicy mSignalPolicy;
362 private VolumeComponent mVolumeComponent;
363 private BrightnessMirrorController mBrightnessMirrorController;
364 private boolean mBrightnessMirrorVisible;
365 protected BiometricUnlockController mBiometricUnlockController;
366 private LightBarController mLightBarController;
367 protected LockscreenWallpaper mLockscreenWallpaper;
369 private int mNaturalBarHeight = -1;
371 private final Point mCurrentDisplaySize = new Point();
373 protected StatusBarWindowView mStatusBarWindow;
374 protected PhoneStatusBarView mStatusBarView;
375 private int mStatusBarWindowState = WINDOW_STATE_SHOWING;
376 protected StatusBarWindowManager mStatusBarWindowManager;
377 protected UnlockMethodCache mUnlockMethodCache;
378 private DozeServiceHost mDozeServiceHost = new DozeServiceHost();
379 private boolean mWakeUpComingFromTouch;
380 private PointF mWakeUpTouchLocation;
382 private final Object mQueueLock = new Object();
384 protected StatusBarIconController mIconController;
386 // expanded notifications
387 protected NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
388 private TextView mNotificationPanelDebugText;
391 private QSPanel mQSPanel;
394 private KeyguardStatusBarView mKeyguardStatusBar;
395 private boolean mLeaveOpenOnKeyguardHide;
396 KeyguardIndicationController mKeyguardIndicationController;
398 // Keyguard is actually fading away now.
399 protected boolean mKeyguardFadingAway;
400 protected long mKeyguardFadingAwayDelay;
401 protected long mKeyguardFadingAwayDuration;
403 // RemoteInputView to be activated after unlock
404 private View mPendingRemoteInputView;
405 private View mPendingWorkRemoteInputView;
407 private RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler =
408 Dependency.get(RemoteInputQuickSettingsDisabler.class);
410 private View mReportRejectedTouch;
412 private int mMaxAllowedKeyguardNotifications;
414 private boolean mExpandedVisible;
416 private final int[] mAbsPos = new int[2];
417 private final ArrayList<Runnable> mPostCollapseRunnables = new ArrayList<>();
419 private NotificationGutsManager mGutsManager;
420 protected NotificationLogger mNotificationLogger;
421 protected NotificationEntryManager mEntryManager;
422 protected NotificationViewHierarchyManager mViewHierarchyManager;
423 protected AppOpsListener mAppOpsListener;
424 protected KeyguardViewMediator mKeyguardViewMediator;
425 private ZenModeController mZenController;
427 // for disabling the status bar
428 private int mDisabled1 = 0;
429 private int mDisabled2 = 0;
431 // tracking calls to View.setSystemUiVisibility()
432 private int mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE;
433 private final Rect mLastFullscreenStackBounds = new Rect();
434 private final Rect mLastDockedStackBounds = new Rect();
435 private final Rect mTmpRect = new Rect();
437 // last value sent to window manager
438 private int mLastDispatchedSystemUiVisibility = ~View.SYSTEM_UI_FLAG_VISIBLE;
440 private final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
442 // XXX: gesture research
443 private final GestureRecorder mGestureRec = DEBUG_GESTURES
444 ? new GestureRecorder("/sdcard/statusbar_gestures.dat")
447 private ScreenPinningRequest mScreenPinningRequest;
449 private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
451 // ensure quick settings is disabled until the current user makes it through the setup wizard
453 protected boolean mUserSetup = false;
454 private final DeviceProvisionedListener mUserSetupObserver = new DeviceProvisionedListener() {
456 public void onUserSetupChanged() {
457 final boolean userSetup = mDeviceProvisionedController.isUserSetup(
458 mDeviceProvisionedController.getCurrentUser());
459 if (MULTIUSER_DEBUG) {
460 Log.d(TAG, String.format("User setup changed: userSetup=%s mUserSetup=%s",
461 userSetup, mUserSetup));
464 if (userSetup != mUserSetup) {
465 mUserSetup = userSetup;
466 if (!mUserSetup && mStatusBarView != null)
467 animateCollapseQuickSettings();
468 if (mNotificationPanel != null) {
469 mNotificationPanel.setUserSetupComplete(mUserSetup);
471 updateQsExpansionEnabled();
476 protected final H mHandler = createHandler();
478 private int mInteractingWindows;
479 private boolean mAutohideSuspended;
480 private int mStatusBarMode;
481 private int mMaxKeyguardNotifications;
483 private ViewMediatorCallback mKeyguardViewMediatorCallback;
484 protected ScrimController mScrimController;
485 protected DozeScrimController mDozeScrimController;
486 private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class);
488 private final Runnable mAutohide = () -> {
489 int requested = mSystemUiVisibility & ~STATUS_OR_NAV_TRANSIENT;
490 if (mSystemUiVisibility != requested) {
491 notifyUiVisibilityChanged(requested);
495 protected boolean mDozing;
496 private boolean mDozingRequested;
497 protected boolean mScrimSrcModeEnabled;
499 protected BackDropView mBackdrop;
500 protected ImageView mBackdropFront, mBackdropBack;
501 protected final PorterDuffXfermode mSrcXferMode = new PorterDuffXfermode(PorterDuff.Mode.SRC);
502 protected final PorterDuffXfermode mSrcOverXferMode =
503 new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER);
505 private NotificationMediaManager mMediaManager;
506 protected NotificationLockscreenUserManager mLockscreenUserManager;
507 protected NotificationRemoteInputManager mRemoteInputManager;
509 private final BroadcastReceiver mWallpaperChangedReceiver = new BroadcastReceiver() {
511 public void onReceive(Context context, Intent intent) {
512 WallpaperManager wallpaperManager = context.getSystemService(WallpaperManager.class);
513 if (wallpaperManager == null) {
514 Log.w(TAG, "WallpaperManager not available");
517 WallpaperInfo info = wallpaperManager.getWallpaperInfo(UserHandle.USER_CURRENT);
518 final boolean supportsAmbientMode = info != null &&
519 info.getSupportsAmbientMode();
521 mStatusBarWindowManager.setWallpaperSupportsAmbientMode(supportsAmbientMode);
522 mScrimController.setWallpaperSupportsAmbientMode(supportsAmbientMode);
526 private Runnable mLaunchTransitionEndRunnable;
527 protected boolean mLaunchTransitionFadingAway;
528 private ExpandableNotificationRow mDraggedDownRow;
529 private boolean mLaunchCameraOnScreenTurningOn;
530 private boolean mLaunchCameraOnFinishedGoingToSleep;
531 private int mLastCameraLaunchSource;
532 private PowerManager.WakeLock mGestureWakeLock;
533 private Vibrator mVibrator;
534 private long[] mCameraLaunchGestureVibePattern;
536 private final int[] mTmpInt2 = new int[2];
538 // Fingerprint (as computed by getLoggingFingerprint() of the last logged state.
539 private int mLastLoggedStateFingerprint;
540 private boolean mTopHidesStatusBar;
541 private boolean mStatusBarWindowHidden;
542 private boolean mHideIconsForBouncer;
543 private boolean mIsOccluded;
544 private boolean mWereIconsJustHidden;
545 private boolean mBouncerWasShowingWhenHidden;
547 // Notifies StatusBarKeyguardViewManager every time the keyguard transition is over,
548 // this animation is tied to the scrim for historic reasons.
549 // TODO: notify when keyguard has faded away instead of the scrim.
550 private final ScrimController.Callback mUnlockScrimCallback = new ScrimController
553 public void onFinished() {
554 if (mStatusBarKeyguardViewManager == null) {
555 Log.w(TAG, "Tried to notify keyguard visibility when "
556 + "mStatusBarKeyguardViewManager was null");
559 if (mKeyguardFadingAway) {
560 mStatusBarKeyguardViewManager.onKeyguardFadedAway();
565 public void onCancelled() {
570 private KeyguardUserSwitcher mKeyguardUserSwitcher;
571 protected UserSwitcherController mUserSwitcherController;
572 private NetworkController mNetworkController;
573 private KeyguardMonitorImpl mKeyguardMonitor
574 = (KeyguardMonitorImpl) Dependency.get(KeyguardMonitor.class);
575 private BatteryController mBatteryController;
576 protected boolean mPanelExpanded;
577 private UiModeManager mUiModeManager;
578 private boolean mKeyguardRequested;
579 private boolean mIsKeyguard;
580 private LogMaker mStatusBarStateLog;
581 private final LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
582 protected NotificationIconAreaController mNotificationIconAreaController;
583 private boolean mReinflateNotificationsOnUserSwitched;
584 protected boolean mClearAllEnabled;
585 @Nullable private View mAmbientIndicationContainer;
586 private SysuiColorExtractor mColorExtractor;
587 private ScreenLifecycle mScreenLifecycle;
588 @VisibleForTesting WakefulnessLifecycle mWakefulnessLifecycle;
590 private final View.OnClickListener mGoToLockedShadeListener = v -> {
591 if (mState == StatusBarState.KEYGUARD) {
592 wakeUpIfDozing(SystemClock.uptimeMillis(), v);
593 goToLockedShade(null);
596 private boolean mNoAnimationOnNextBarModeChange;
597 protected FalsingManager mFalsingManager;
599 private final KeyguardUpdateMonitorCallback mUpdateCallback =
600 new KeyguardUpdateMonitorCallback() {
602 public void onDreamingStateChanged(boolean dreaming) {
604 maybeEscalateHeadsUp();
609 public void onStrongAuthStateChanged(int userId) {
610 super.onStrongAuthStateChanged(userId);
611 mEntryManager.updateNotifications();
615 private NavigationBarFragment mNavigationBar;
616 private View mNavigationBarView;
617 protected ActivityLaunchAnimator mActivityLaunchAnimator;
618 private HeadsUpAppearanceController mHeadsUpAppearanceController;
619 private boolean mVibrateOnOpening;
620 private VibratorHelper mVibratorHelper;
623 public void start() {
624 mGroupManager = Dependency.get(NotificationGroupManager.class);
625 mVisualStabilityManager = Dependency.get(VisualStabilityManager.class);
626 mNotificationLogger = Dependency.get(NotificationLogger.class);
627 mRemoteInputManager = Dependency.get(NotificationRemoteInputManager.class);
628 mNotificationListener = Dependency.get(NotificationListener.class);
629 mGroupManager = Dependency.get(NotificationGroupManager.class);
630 mNetworkController = Dependency.get(NetworkController.class);
631 mUserSwitcherController = Dependency.get(UserSwitcherController.class);
632 mScreenLifecycle = Dependency.get(ScreenLifecycle.class);
633 mScreenLifecycle.addObserver(mScreenObserver);
634 mWakefulnessLifecycle = Dependency.get(WakefulnessLifecycle.class);
635 mWakefulnessLifecycle.addObserver(mWakefulnessObserver);
636 mBatteryController = Dependency.get(BatteryController.class);
637 mAssistManager = Dependency.get(AssistManager.class);
638 mUiModeManager = mContext.getSystemService(UiModeManager.class);
639 mLockscreenUserManager = Dependency.get(NotificationLockscreenUserManager.class);
640 mGutsManager = Dependency.get(NotificationGutsManager.class);
641 mMediaManager = Dependency.get(NotificationMediaManager.class);
642 mEntryManager = Dependency.get(NotificationEntryManager.class);
643 mViewHierarchyManager = Dependency.get(NotificationViewHierarchyManager.class);
644 mAppOpsListener = Dependency.get(AppOpsListener.class);
645 mAppOpsListener.setUpWithPresenter(this, mEntryManager);
646 mZenController = Dependency.get(ZenModeController.class);
647 mKeyguardViewMediator = getComponent(KeyguardViewMediator.class);
649 mColorExtractor = Dependency.get(SysuiColorExtractor.class);
650 mColorExtractor.addOnColorsChangedListener(this);
652 mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
654 mDisplay = mWindowManager.getDefaultDisplay();
657 Resources res = mContext.getResources();
658 mVibrateOnOpening = mContext.getResources().getBoolean(
659 R.bool.config_vibrateOnIconAnimation);
660 mVibratorHelper = Dependency.get(VibratorHelper.class);
661 mScrimSrcModeEnabled = res.getBoolean(R.bool.config_status_bar_scrim_behind_use_src);
662 mClearAllEnabled = res.getBoolean(R.bool.config_enableNotificationsClearAll);
664 DateTimeView.setReceiverHandler(Dependency.get(Dependency.TIME_TICK_HANDLER));
665 putComponent(StatusBar.class, this);
667 // start old BaseStatusBar.start().
668 mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
669 mDevicePolicyManager = (DevicePolicyManager) mContext.getSystemService(
670 Context.DEVICE_POLICY_SERVICE);
672 mAccessibilityManager = (AccessibilityManager)
673 mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
675 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
677 mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
679 mBarService = IStatusBarService.Stub.asInterface(
680 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
682 mRecents = getComponent(Recents.class);
684 mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
685 mLockPatternUtils = new LockPatternUtils(mContext);
687 mMediaManager.setUpWithPresenter(this, mEntryManager);
689 // Connect in to the status bar manager service
690 mCommandQueue = getComponent(CommandQueue.class);
691 mCommandQueue.addCallbacks(this);
693 int[] switches = new int[9];
694 ArrayList<IBinder> binders = new ArrayList<>();
695 ArrayList<String> iconSlots = new ArrayList<>();
696 ArrayList<StatusBarIcon> icons = new ArrayList<>();
697 Rect fullscreenStackBounds = new Rect();
698 Rect dockedStackBounds = new Rect();
700 mBarService.registerStatusBar(mCommandQueue, iconSlots, icons, switches, binders,
701 fullscreenStackBounds, dockedStackBounds);
702 } catch (RemoteException ex) {
703 // If the system process isn't there we're doomed anyway.
706 createAndAddWindows();
708 // Make sure we always have the most current wallpaper info.
709 IntentFilter wallpaperChangedFilter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED);
710 mContext.registerReceiverAsUser(mWallpaperChangedReceiver, UserHandle.ALL,
711 wallpaperChangedFilter, null /* broadcastPermission */, null /* scheduler */);
712 mWallpaperChangedReceiver.onReceive(mContext, null);
714 mLockscreenUserManager.setUpWithPresenter(this, mEntryManager);
715 mCommandQueue.disable(switches[0], switches[6], false /* animate */);
716 setSystemUiVisibility(switches[1], switches[7], switches[8], 0xffffffff,
717 fullscreenStackBounds, dockedStackBounds);
718 topAppWindowChanged(switches[2] != 0);
719 // StatusBarManagerService has a back up of IME token and it's restored here.
720 setImeWindowStatus(binders.get(0), switches[3], switches[4], switches[5] != 0);
722 // Set up the initial icon state
723 int N = iconSlots.size();
724 for (int i=0; i < N; i++) {
725 mCommandQueue.setIcon(iconSlots.get(i), icons.get(i));
728 // Set up the initial notification state.
729 mNotificationListener.setUpWithPresenter(this, mEntryManager);
732 Log.d(TAG, String.format(
733 "init: icons=%d disabled=0x%08x lights=0x%08x menu=0x%08x imeButton=0x%08x",
742 setHeadsUpUser(mLockscreenUserManager.getCurrentUserId());
744 IntentFilter internalFilter = new IntentFilter();
745 internalFilter.addAction(BANNER_ACTION_CANCEL);
746 internalFilter.addAction(BANNER_ACTION_SETUP);
747 mContext.registerReceiver(mBannerActionBroadcastReceiver, internalFilter, PERMISSION_SELF,
750 IVrManager vrManager = IVrManager.Stub.asInterface(ServiceManager.getService(
751 Context.VR_SERVICE));
753 vrManager.registerListener(mVrStateCallbacks);
754 } catch (RemoteException e) {
755 Slog.e(TAG, "Failed to register VR mode state listener: " + e);
758 IWallpaperManager wallpaperManager = IWallpaperManager.Stub.asInterface(
759 ServiceManager.getService(Context.WALLPAPER_SERVICE));
761 wallpaperManager.setInAmbientMode(false /* ambientMode */, false /* animated */);
762 } catch (RemoteException e) {
763 // Just pass, nothing critical.
766 // end old BaseStatusBar.start().
768 // Lastly, call to the icon policy to install/update all the icons.
769 mIconPolicy = new PhoneStatusBarPolicy(mContext, mIconController);
770 mSignalPolicy = new StatusBarSignalPolicy(mContext, mIconController);
772 mUnlockMethodCache = UnlockMethodCache.getInstance(mContext);
773 mUnlockMethodCache.addListener(this);
776 KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateCallback);
777 putComponent(DozeHost.class, mDozeServiceHost);
779 mScreenPinningRequest = new ScreenPinningRequest(mContext);
780 mFalsingManager = FalsingManager.getInstance(mContext);
782 Dependency.get(ActivityStarterDelegate.class).setActivityStarterImpl(this);
784 Dependency.get(ConfigurationController.class).addCallback(this);
787 // ================================================================================
788 // Constructing the view
789 // ================================================================================
790 protected void makeStatusBarView() {
791 final Context context = mContext;
792 updateDisplaySize(); // populates mDisplayMetrics
796 inflateStatusBarWindow(context);
797 mStatusBarWindow.setService(this);
798 mStatusBarWindow.setOnTouchListener(getStatusBarWindowTouchListener());
800 // TODO: Deal with the ugliness that comes from having some of the statusbar broken out
801 // into fragments, but the rest here, it leaves some awkward lifecycle and whatnot.
802 mNotificationPanel = mStatusBarWindow.findViewById(R.id.notification_panel);
803 mStackScroller = mStatusBarWindow.findViewById(R.id.notification_stack_scroller);
804 mZenController.addCallback(this);
805 mActivityLaunchAnimator = new ActivityLaunchAnimator(mStatusBarWindow,
809 mGutsManager.setUpWithPresenter(this, mEntryManager, mStackScroller, mCheckSaveListener,
812 mBarService.onNotificationSettingsViewed(key);
813 } catch (RemoteException e) {
814 // if we're here we're dead
817 mNotificationLogger.setUpWithEntryManager(mEntryManager, mStackScroller);
818 mNotificationPanel.setStatusBar(this);
819 mNotificationPanel.setGroupManager(mGroupManager);
820 mAboveShelfObserver = new AboveShelfObserver(mStackScroller);
821 mAboveShelfObserver.setListener(mStatusBarWindow.findViewById(
822 R.id.notification_container_parent));
823 mKeyguardStatusBar = mStatusBarWindow.findViewById(R.id.keyguard_header);
825 mNotificationIconAreaController = SystemUIFactory.getInstance()
826 .createNotificationIconAreaController(context, this);
828 mNotificationIconAreaController.setupShelf(mNotificationShelf);
829 mStackScroller.setIconAreaController(mNotificationIconAreaController);
830 Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mNotificationIconAreaController);
831 FragmentHostManager.get(mStatusBarWindow)
832 .addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> {
833 CollapsedStatusBarFragment statusBarFragment =
834 (CollapsedStatusBarFragment) fragment;
835 statusBarFragment.initNotificationIconArea(mNotificationIconAreaController);
836 PhoneStatusBarView oldStatusBarView = mStatusBarView;
837 mStatusBarView = (PhoneStatusBarView) fragment.getView();
838 mStatusBarView.setBar(this);
839 mStatusBarView.setPanel(mNotificationPanel);
840 mStatusBarView.setScrimController(mScrimController);
842 // CollapsedStatusBarFragment re-inflated PhoneStatusBarView and both of
843 // mStatusBarView.mExpanded and mStatusBarView.mBouncerShowing are false.
844 // PhoneStatusBarView's new instance will set to be gone in
845 // PanelBar.updateVisibility after calling mStatusBarView.setBouncerShowing
846 // that will trigger PanelBar.updateVisibility. If there is a heads up showing,
847 // it needs to notify PhoneStatusBarView's new instance to update the correct
848 // status by calling mNotificationPanel.notifyBarPanelExpansionChanged().
849 if (mHeadsUpManager.hasPinnedHeadsUp()) {
850 mNotificationPanel.notifyBarPanelExpansionChanged();
852 mStatusBarView.setBouncerShowing(mBouncerShowing);
853 if (oldStatusBarView != null) {
854 float fraction = oldStatusBarView.getExpansionFraction();
855 boolean expanded = oldStatusBarView.isExpanded();
856 mStatusBarView.panelExpansionChanged(fraction, expanded);
859 HeadsUpAppearanceController oldController = mHeadsUpAppearanceController;
860 if (mHeadsUpAppearanceController != null) {
861 // This view is being recreated, let's destroy the old one
862 mHeadsUpAppearanceController.destroy();
864 mHeadsUpAppearanceController = new HeadsUpAppearanceController(
865 mNotificationIconAreaController, mHeadsUpManager, mStatusBarWindow);
866 mHeadsUpAppearanceController.readFrom(oldController);
867 mStatusBarWindow.setStatusBarView(mStatusBarView);
868 setAreThereNotifications();
870 }).getFragmentManager()
872 .replace(R.id.status_bar_container, new CollapsedStatusBarFragment(),
873 CollapsedStatusBarFragment.TAG)
875 mIconController = Dependency.get(StatusBarIconController.class);
877 mHeadsUpManager = new HeadsUpManagerPhone(context, mStatusBarWindow, mGroupManager, this,
878 mVisualStabilityManager);
879 Dependency.get(ConfigurationController.class).addCallback(mHeadsUpManager);
880 mHeadsUpManager.addListener(this);
881 mHeadsUpManager.addListener(mNotificationPanel);
882 mHeadsUpManager.addListener(mGroupManager);
883 mHeadsUpManager.addListener(mVisualStabilityManager);
884 mNotificationPanel.setHeadsUpManager(mHeadsUpManager);
885 mGroupManager.setHeadsUpManager(mHeadsUpManager);
886 putComponent(HeadsUpManager.class, mHeadsUpManager);
888 mEntryManager.setUpWithPresenter(this, mStackScroller, this, mHeadsUpManager);
889 mViewHierarchyManager.setUpWithPresenter(this, mEntryManager, mStackScroller);
891 if (MULTIUSER_DEBUG) {
892 mNotificationPanelDebugText = mNotificationPanel.findViewById(R.id.header_debug_info);
893 mNotificationPanelDebugText.setVisibility(View.VISIBLE);
897 boolean showNav = mWindowManagerService.hasNavigationBar();
898 if (DEBUG) Log.v(TAG, "hasNavigationBar=" + showNav);
900 createNavigationBar();
902 } catch (RemoteException ex) {
903 // no window manager? good luck with that
905 mStackScroller.setLongPressListener(mEntryManager.getNotificationLongClicker());
906 mStackScroller.setStatusBar(this);
907 mStackScroller.setGroupManager(mGroupManager);
908 mStackScroller.setHeadsUpManager(mHeadsUpManager);
909 mGroupManager.setOnGroupChangeListener(mStackScroller);
910 mVisualStabilityManager.setVisibilityLocationProvider(mStackScroller);
912 inflateEmptyShadeView();
915 mBackdrop = mStatusBarWindow.findViewById(R.id.backdrop);
916 mBackdropFront = mBackdrop.findViewById(R.id.backdrop_front);
917 mBackdropBack = mBackdrop.findViewById(R.id.backdrop_back);
919 if (ENABLE_LOCKSCREEN_WALLPAPER) {
920 mLockscreenWallpaper = new LockscreenWallpaper(mContext, this, mHandler);
923 mKeyguardIndicationController =
924 SystemUIFactory.getInstance().createKeyguardIndicationController(mContext,
925 mStatusBarWindow.findViewById(R.id.keyguard_indication_area),
926 mNotificationPanel.getLockIcon());
927 mNotificationPanel.setKeyguardIndicationController(mKeyguardIndicationController);
930 mAmbientIndicationContainer = mStatusBarWindow.findViewById(
931 R.id.ambient_indication_container);
933 // set the initial view visibility
934 setAreThereNotifications();
936 // TODO: Find better place for this callback.
937 mBatteryController.addCallback(new BatteryStateChangeCallback() {
939 public void onPowerSaveChanged(boolean isPowerSave) {
940 mHandler.post(mCheckBarModes);
941 if (mDozeServiceHost != null) {
942 mDozeServiceHost.firePowerSaveChanged(isPowerSave);
947 public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
952 mLightBarController = Dependency.get(LightBarController.class);
953 if (mNavigationBar != null) {
954 mNavigationBar.setLightBarController(mLightBarController);
957 ScrimView scrimBehind = mStatusBarWindow.findViewById(R.id.scrim_behind);
958 ScrimView scrimInFront = mStatusBarWindow.findViewById(R.id.scrim_in_front);
959 mScrimController = SystemUIFactory.getInstance().createScrimController(
960 scrimBehind, scrimInFront, mLockscreenWallpaper,
961 (state, alpha, color) -> mLightBarController.setScrimState(state, alpha, color),
963 if (mStatusBarWindowManager != null) {
964 mStatusBarWindowManager.setScrimsVisibility(scrimsVisible);
966 }, DozeParameters.getInstance(mContext),
967 mContext.getSystemService(AlarmManager.class));
968 if (mScrimSrcModeEnabled) {
969 Runnable runnable = () -> {
970 boolean asSrc = mBackdrop.getVisibility() != View.VISIBLE;
971 mScrimController.setDrawBehindAsSrc(asSrc);
972 mStackScroller.setDrawBackgroundAsSrc(asSrc);
974 mBackdrop.setOnVisibilityChangedRunnable(runnable);
977 mStackScroller.setScrimController(mScrimController);
978 mDozeScrimController = new DozeScrimController(mScrimController, context,
979 DozeParameters.getInstance(context));
982 mVolumeComponent = getComponent(VolumeComponent.class);
984 mNotificationPanel.setUserSetupComplete(mUserSetup);
985 if (UserManager.get(mContext).isUserSwitcherEnabled()) {
986 createUserSwitcher();
989 // Set up the quick settings tile panel
990 View container = mStatusBarWindow.findViewById(R.id.qs_frame);
991 if (container != null) {
992 FragmentHostManager fragmentHostManager = FragmentHostManager.get(container);
993 ExtensionFragmentListener.attachExtensonToFragment(container, QS.TAG, R.id.qs_frame,
994 Dependency.get(ExtensionController.class)
995 .newExtension(QS.class)
996 .withPlugin(QS.class)
997 .withFeature(PackageManager.FEATURE_AUTOMOTIVE, CarQSFragment::new)
998 .withDefault(QSFragment::new)
1000 final QSTileHost qsh = SystemUIFactory.getInstance().createQSTileHost(mContext, this,
1002 mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow,
1004 mBrightnessMirrorVisible = visible;
1005 updateScrimController();
1007 fragmentHostManager.addTagListener(QS.TAG, (tag, f) -> {
1009 if (qs instanceof QSFragment) {
1010 ((QSFragment) qs).setHost(qsh);
1011 mQSPanel = ((QSFragment) qs).getQsPanel();
1012 mQSPanel.setBrightnessMirror(mBrightnessMirrorController);
1013 mKeyguardStatusBar.setQSPanel(mQSPanel);
1018 mReportRejectedTouch = mStatusBarWindow.findViewById(R.id.report_rejected_touch);
1019 if (mReportRejectedTouch != null) {
1020 updateReportRejectedTouchVisibility();
1021 mReportRejectedTouch.setOnClickListener(v -> {
1022 Uri session = mFalsingManager.reportRejectedTouch();
1023 if (session == null) { return; }
1025 StringWriter message = new StringWriter();
1026 message.write("Build info: ");
1027 message.write(SystemProperties.get("ro.build.description"));
1028 message.write("\nSerial number: ");
1029 message.write(SystemProperties.get("ro.serialno"));
1030 message.write("\n");
1032 PrintWriter falsingPw = new PrintWriter(message);
1033 FalsingLog.dump(falsingPw);
1036 startActivityDismissingKeyguard(Intent.createChooser(new Intent(Intent.ACTION_SEND)
1038 .putExtra(Intent.EXTRA_SUBJECT, "Rejected touch report")
1039 .putExtra(Intent.EXTRA_STREAM, session)
1040 .putExtra(Intent.EXTRA_TEXT, message.toString()),
1041 "Share rejected touch report")
1042 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK),
1043 true /* onlyProvisioned */, true /* dismissShade */);
1047 PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
1048 if (!pm.isScreenOn()) {
1049 mBroadcastReceiver.onReceive(mContext, new Intent(Intent.ACTION_SCREEN_OFF));
1051 mGestureWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
1053 mVibrator = mContext.getSystemService(Vibrator.class);
1054 int[] pattern = mContext.getResources().getIntArray(
1055 R.array.config_cameraLaunchGestureVibePattern);
1056 mCameraLaunchGestureVibePattern = new long[pattern.length];
1057 for (int i = 0; i < pattern.length; i++) {
1058 mCameraLaunchGestureVibePattern[i] = pattern[i];
1061 // receive broadcasts
1062 IntentFilter filter = new IntentFilter();
1063 filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
1064 filter.addAction(Intent.ACTION_SCREEN_OFF);
1065 filter.addAction(DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG);
1066 context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
1068 IntentFilter demoFilter = new IntentFilter();
1069 if (DEBUG_MEDIA_FAKE_ARTWORK) {
1070 demoFilter.addAction(ACTION_FAKE_ARTWORK);
1072 demoFilter.addAction(ACTION_DEMO);
1073 context.registerReceiverAsUser(mDemoReceiver, UserHandle.ALL, demoFilter,
1074 android.Manifest.permission.DUMP, null);
1076 // listen for USER_SETUP_COMPLETE setting (per-user)
1077 mDeviceProvisionedController.addCallback(mUserSetupObserver);
1078 mUserSetupObserver.onUserSetupChanged();
1080 // disable profiling bars, since they overlap and clutter the output on app windows
1081 ThreadedRenderer.overrideProperty("disableProfileBars", "true");
1083 // Private API call to make the shadows look better for Recents
1084 ThreadedRenderer.overrideProperty("ambientRatio", String.valueOf(1.5f));
1087 protected void createNavigationBar() {
1088 mNavigationBarView = NavigationBarFragment.create(mContext, (tag, fragment) -> {
1089 mNavigationBar = (NavigationBarFragment) fragment;
1090 if (mLightBarController != null) {
1091 mNavigationBar.setLightBarController(mLightBarController);
1093 mNavigationBar.setCurrentSysuiVisibility(mSystemUiVisibility);
1098 * Returns the {@link android.view.View.OnTouchListener} that will be invoked when the
1099 * background window of the status bar is clicked.
1101 protected View.OnTouchListener getStatusBarWindowTouchListener() {
1102 return (v, event) -> {
1103 checkUserAutohide(event);
1104 mRemoteInputManager.checkRemoteInputOutside(event);
1105 if (event.getAction() == MotionEvent.ACTION_DOWN) {
1106 if (mExpandedVisible) {
1107 animateCollapsePanels();
1110 return mStatusBarWindow.onTouchEvent(event);
1114 private void inflateShelf() {
1115 mNotificationShelf =
1116 (NotificationShelf) LayoutInflater.from(mContext).inflate(
1117 R.layout.status_bar_notification_shelf, mStackScroller, false);
1118 mNotificationShelf.setOnActivatedListener(this);
1119 mStackScroller.setShelf(mNotificationShelf);
1120 mNotificationShelf.setOnClickListener(mGoToLockedShadeListener);
1121 mNotificationShelf.setStatusBarState(mState);
1124 public void onDensityOrFontScaleChanged() {
1125 MessagingMessage.dropCache();
1126 MessagingGroup.dropCache();
1127 // start old BaseStatusBar.onDensityOrFontScaleChanged().
1128 if (!KeyguardUpdateMonitor.getInstance(mContext).isSwitchingUser()) {
1129 mEntryManager.updateNotificationsOnDensityOrFontScaleChanged();
1131 mReinflateNotificationsOnUserSwitched = true;
1133 // end old BaseStatusBar.onDensityOrFontScaleChanged().
1134 // TODO: Remove this.
1135 if (mBrightnessMirrorController != null) {
1136 mBrightnessMirrorController.onDensityOrFontScaleChanged();
1138 mStatusBarKeyguardViewManager.onDensityOrFontScaleChanged();
1139 // TODO: Bring these out of StatusBar.
1140 ((UserInfoControllerImpl) Dependency.get(UserInfoController.class))
1141 .onDensityOrFontScaleChanged();
1142 Dependency.get(UserSwitcherController.class).onDensityOrFontScaleChanged();
1143 if (mKeyguardUserSwitcher != null) {
1144 mKeyguardUserSwitcher.onDensityOrFontScaleChanged();
1146 mNotificationIconAreaController.onDensityOrFontScaleChanged(mContext);
1147 mHeadsUpManager.onDensityOrFontScaleChanged();
1149 inflateFooterView();
1150 inflateEmptyShadeView();
1154 private void onThemeChanged() {
1157 // Clock and bottom icons
1158 mNotificationPanel.onThemeChanged();
1159 // The status bar on the keyguard is a special layout.
1160 if (mKeyguardStatusBar != null) mKeyguardStatusBar.onThemeChanged();
1161 // Recreate Indication controller because internal references changed
1162 mKeyguardIndicationController =
1163 SystemUIFactory.getInstance().createKeyguardIndicationController(mContext,
1164 mStatusBarWindow.findViewById(R.id.keyguard_indication_area),
1165 mNotificationPanel.getLockIcon());
1166 mNotificationPanel.setKeyguardIndicationController(mKeyguardIndicationController);
1167 mKeyguardIndicationController
1168 .setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
1169 mKeyguardIndicationController.setVisible(mState == StatusBarState.KEYGUARD);
1170 mKeyguardIndicationController.setDozing(mDozing);
1171 if (mStatusBarKeyguardViewManager != null) {
1172 mStatusBarKeyguardViewManager.onThemeChanged();
1174 if (mAmbientIndicationContainer instanceof AutoReinflateContainer) {
1175 ((AutoReinflateContainer) mAmbientIndicationContainer).inflateLayout();
1179 private void reevaluateStyles() {
1181 updateEmptyShadeView();
1185 public void onOverlayChanged() {
1186 if (mBrightnessMirrorController != null) {
1187 mBrightnessMirrorController.onOverlayChanged();
1192 public void onUiModeChanged() {
1193 // UiMode will change the style was already evaluated.
1194 // We need to force the re-evaluation to make sure that all parents
1195 // are up to date and new attrs will be rettrieved.
1196 mContext.getTheme().applyStyle(mContext.getThemeResId(), true);
1198 if (mBrightnessMirrorController != null) {
1199 mBrightnessMirrorController.onUiModeChanged();
1203 private void inflateEmptyShadeView() {
1204 if (mStackScroller == null) {
1207 mEmptyShadeView = (EmptyShadeView) LayoutInflater.from(mContext).inflate(
1208 R.layout.status_bar_no_notifications, mStackScroller, false);
1209 mEmptyShadeView.setText(R.string.empty_shade_text);
1210 mStackScroller.setEmptyShadeView(mEmptyShadeView);
1214 protected void inflateFooterView() {
1215 if (mStackScroller == null) {
1219 mFooterView = (FooterView) LayoutInflater.from(mContext).inflate(
1220 R.layout.status_bar_notification_footer, mStackScroller, false);
1221 mFooterView.setDismissButtonClickListener(v -> {
1222 mMetricsLogger.action(MetricsEvent.ACTION_DISMISS_ALL_NOTES);
1223 clearAllNotifications();
1225 mFooterView.setManageButtonClickListener(v -> {
1226 manageNotifications();
1228 mStackScroller.setFooterView(mFooterView);
1231 protected void createUserSwitcher() {
1232 mKeyguardUserSwitcher = new KeyguardUserSwitcher(mContext,
1233 mStatusBarWindow.findViewById(R.id.keyguard_user_switcher), mKeyguardStatusBar,
1234 mNotificationPanel);
1237 protected void inflateStatusBarWindow(Context context) {
1238 mStatusBarWindow = (StatusBarWindowView) View.inflate(context,
1239 R.layout.super_status_bar, null);
1242 public void manageNotifications() {
1243 Intent intent = new Intent(Settings.ACTION_ALL_APPS_NOTIFICATION_SETTINGS);
1244 startActivity(intent, true, true, Intent.FLAG_ACTIVITY_SINGLE_TOP);
1247 public void clearAllNotifications() {
1248 // animate-swipe all dismissable notifications, then animate the shade closed
1249 int numChildren = mStackScroller.getChildCount();
1251 final ArrayList<View> viewsToHide = new ArrayList<>(numChildren);
1252 final ArrayList<ExpandableNotificationRow> viewsToRemove = new ArrayList<>(numChildren);
1253 for (int i = 0; i < numChildren; i++) {
1254 final View child = mStackScroller.getChildAt(i);
1255 if (child instanceof ExpandableNotificationRow) {
1256 ExpandableNotificationRow row = (ExpandableNotificationRow) child;
1257 boolean parentVisible = false;
1258 boolean hasClipBounds = child.getClipBounds(mTmpRect);
1259 if (mStackScroller.canChildBeDismissed(child)) {
1260 viewsToRemove.add(row);
1261 if (child.getVisibility() == View.VISIBLE
1262 && (!hasClipBounds || mTmpRect.height() > 0)) {
1263 viewsToHide.add(child);
1264 parentVisible = true;
1266 } else if (child.getVisibility() == View.VISIBLE
1267 && (!hasClipBounds || mTmpRect.height() > 0)) {
1268 parentVisible = true;
1270 List<ExpandableNotificationRow> children = row.getNotificationChildren();
1271 if (children != null) {
1272 for (ExpandableNotificationRow childRow : children) {
1273 viewsToRemove.add(childRow);
1274 if (parentVisible && row.areChildrenExpanded()
1275 && mStackScroller.canChildBeDismissed(childRow)) {
1276 hasClipBounds = childRow.getClipBounds(mTmpRect);
1277 if (childRow.getVisibility() == View.VISIBLE
1278 && (!hasClipBounds || mTmpRect.height() > 0)) {
1279 viewsToHide.add(childRow);
1286 if (viewsToRemove.isEmpty()) {
1287 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
1291 addPostCollapseAction(() -> {
1292 mStackScroller.setDismissAllInProgress(false);
1293 for (ExpandableNotificationRow rowToRemove : viewsToRemove) {
1294 if (mStackScroller.canChildBeDismissed(rowToRemove)) {
1295 mEntryManager.removeNotification(rowToRemove.getEntry().key, null);
1297 rowToRemove.resetTranslation();
1301 mBarService.onClearAllNotifications(mLockscreenUserManager.getCurrentUserId());
1302 } catch (Exception ex) {
1306 performDismissAllAnimations(viewsToHide);
1310 private void performDismissAllAnimations(ArrayList<View> hideAnimatedList) {
1311 Runnable animationFinishAction = () -> {
1312 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
1315 if (hideAnimatedList.isEmpty()) {
1316 animationFinishAction.run();
1320 // let's disable our normal animations
1321 mStackScroller.setDismissAllInProgress(true);
1323 // Decrease the delay for every row we animate to give the sense of
1324 // accelerating the swipes
1325 int rowDelayDecrement = 10;
1326 int currentDelay = 140;
1327 int totalDelay = 180;
1328 int numItems = hideAnimatedList.size();
1329 for (int i = numItems - 1; i >= 0; i--) {
1330 View view = hideAnimatedList.get(i);
1331 Runnable endRunnable = null;
1333 endRunnable = animationFinishAction;
1335 mStackScroller.dismissViewAnimated(view, endRunnable, totalDelay, 260);
1336 currentDelay = Math.max(50, currentDelay - rowDelayDecrement);
1337 totalDelay += currentDelay;
1341 protected void startKeyguard() {
1342 Trace.beginSection("StatusBar#startKeyguard");
1343 KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class);
1344 mBiometricUnlockController = new BiometricUnlockController(mContext,
1345 mDozeScrimController, keyguardViewMediator,
1346 mScrimController, this, UnlockMethodCache.getInstance(mContext));
1347 mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this,
1348 getBouncerContainer(), mNotificationPanel, mBiometricUnlockController);
1349 mKeyguardIndicationController
1350 .setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
1351 mBiometricUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
1352 mRemoteInputManager.getController().addCallback(mStatusBarKeyguardViewManager);
1354 mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback();
1355 mLightBarController.setBiometricUnlockController(mBiometricUnlockController);
1356 Dependency.get(KeyguardDismissUtil.class).setDismissHandler(this::executeWhenUnlocked);
1360 protected View getStatusBarView() {
1361 return mStatusBarView;
1364 public StatusBarWindowView getStatusBarWindow() {
1365 return mStatusBarWindow;
1368 protected ViewGroup getBouncerContainer() {
1369 return mStatusBarWindow;
1372 public int getStatusBarHeight() {
1373 if (mNaturalBarHeight < 0) {
1374 final Resources res = mContext.getResources();
1376 res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
1378 return mNaturalBarHeight;
1381 protected boolean toggleSplitScreenMode(int metricsDockAction, int metricsUndockAction) {
1382 if (mRecents == null) {
1385 int dockSide = WindowManagerProxy.getInstance().getDockSide();
1386 if (dockSide == WindowManager.DOCKED_INVALID) {
1387 final int navbarPos = WindowManagerWrapper.getInstance().getNavBarPosition();
1388 if (navbarPos == NAV_BAR_POS_INVALID) {
1391 int createMode = navbarPos == NAV_BAR_POS_LEFT
1392 ? SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT
1393 : SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
1394 return mRecents.splitPrimaryTask(NavigationBarGestureHelper.DRAG_MODE_NONE, createMode,
1395 null, metricsDockAction);
1397 Divider divider = getComponent(Divider.class);
1398 if (divider != null && divider.isMinimized() && !divider.isHomeStackResizable()) {
1399 // Undocking from the minimized state is not supported
1402 EventBus.getDefault().send(new UndockingTaskEvent());
1403 if (metricsUndockAction != -1) {
1404 mMetricsLogger.action(metricsUndockAction);
1412 public void onPerformRemoveNotification(StatusBarNotification n) {
1413 if (mStackScroller.hasPulsingNotifications() &&
1414 !mHeadsUpManager.hasHeadsUpNotifications()) {
1415 // We were showing a pulse for a notification, but no notifications are pulsing anymore.
1416 // Finish the pulse.
1417 mDozeScrimController.pulseOutNow();
1422 public void updateNotificationViews() {
1423 // The function updateRowStates depends on both of these being non-null, so check them here.
1424 // We may be called before they are set from DeviceProvisionedController's callback.
1425 if (mStackScroller == null || mScrimController == null) return;
1427 // Do not modify the notifications during collapse.
1428 if (isCollapsing()) {
1429 addPostCollapseAction(this::updateNotificationViews);
1433 mViewHierarchyManager.updateNotificationViews();
1435 updateSpeedBumpIndex();
1437 updateEmptyShadeView();
1439 updateQsExpansionEnabled();
1441 // Let's also update the icons
1442 mNotificationIconAreaController.updateNotificationIcons();
1446 public void onNotificationAdded(Entry shadeEntry) {
1447 // Recalculate the position of the sliding windows and the titles.
1448 setAreThereNotifications();
1452 public void onNotificationUpdated(StatusBarNotification notification) {
1453 setAreThereNotifications();
1457 public void onNotificationRemoved(String key, StatusBarNotification old) {
1458 if (SPEW) Log.d(TAG, "removeNotification key=" + key + " old=" + old);
1461 if (CLOSE_PANEL_WHEN_EMPTIED && !hasActiveNotifications()
1462 && !mNotificationPanel.isTracking() && !mNotificationPanel.isQsExpanded()) {
1463 if (mState == StatusBarState.SHADE) {
1464 animateCollapsePanels();
1465 } else if (mState == StatusBarState.SHADE_LOCKED && !isCollapsing()) {
1470 setAreThereNotifications();
1474 * Disable QS if device not provisioned.
1475 * If the user switcher is simple then disable QS during setup because
1476 * the user intends to use the lock screen user switcher, QS in not needed.
1478 private void updateQsExpansionEnabled() {
1479 mNotificationPanel.setQsExpansionEnabled(isDeviceProvisioned()
1480 && (mUserSetup || mUserSwitcherController == null
1481 || !mUserSwitcherController.isSimpleUserSwitcher())
1482 && ((mDisabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) == 0)
1483 && ((mDisabled2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) == 0)
1485 && !ONLY_CORE_APPS);
1488 public void addQsTile(ComponentName tile) {
1489 if (mQSPanel != null && mQSPanel.getHost() != null) {
1490 mQSPanel.getHost().addTile(tile);
1494 public void remQsTile(ComponentName tile) {
1495 if (mQSPanel != null && mQSPanel.getHost() != null) {
1496 mQSPanel.getHost().removeTile(tile);
1500 public void clickTile(ComponentName tile) {
1501 mQSPanel.clickTile(tile);
1505 protected void updateFooter() {
1506 boolean showDismissView = mClearAllEnabled && hasActiveClearableNotifications();
1507 boolean showFooterView = (showDismissView ||
1508 mEntryManager.getNotificationData().getActiveNotifications().size() != 0)
1509 && mState != StatusBarState.KEYGUARD
1510 && !mRemoteInputManager.getController().isRemoteInputActive();
1512 mStackScroller.updateFooterView(showFooterView, showDismissView);
1516 * Return whether there are any clearable notifications
1518 private boolean hasActiveClearableNotifications() {
1519 int childCount = mStackScroller.getChildCount();
1520 for (int i = 0; i < childCount; i++) {
1521 View child = mStackScroller.getChildAt(i);
1522 if (!(child instanceof ExpandableNotificationRow)) {
1525 if (((ExpandableNotificationRow) child).canViewBeDismissed()) {
1532 private void updateEmptyShadeView() {
1533 boolean showEmptyShadeView =
1534 mState != StatusBarState.KEYGUARD &&
1535 mEntryManager.getNotificationData().getActiveNotifications().size() == 0;
1536 mNotificationPanel.showEmptyShadeView(showEmptyShadeView);
1539 private void updateSpeedBumpIndex() {
1540 int speedBumpIndex = 0;
1541 int currentIndex = 0;
1542 final int N = mStackScroller.getChildCount();
1543 for (int i = 0; i < N; i++) {
1544 View view = mStackScroller.getChildAt(i);
1545 if (view.getVisibility() == View.GONE || !(view instanceof ExpandableNotificationRow)) {
1548 ExpandableNotificationRow row = (ExpandableNotificationRow) view;
1550 if (!mEntryManager.getNotificationData().isAmbient(
1551 row.getStatusBarNotification().getKey())) {
1552 speedBumpIndex = currentIndex;
1555 boolean noAmbient = speedBumpIndex == N;
1556 mStackScroller.updateSpeedBumpIndex(speedBumpIndex, noAmbient);
1559 public static boolean isTopLevelChild(Entry entry) {
1560 return entry.row.getParent() instanceof NotificationStackScrollLayout;
1563 public boolean areNotificationsHidden() {
1564 return mZenController.areNotificationsHiddenInShade();
1567 public void requestNotificationUpdate() {
1568 mEntryManager.updateNotifications();
1571 protected void setAreThereNotifications() {
1574 final boolean clearable = hasActiveNotifications() &&
1575 hasActiveClearableNotifications();
1576 Log.d(TAG, "setAreThereNotifications: N=" +
1577 mEntryManager.getNotificationData().getActiveNotifications().size() + " any=" +
1578 hasActiveNotifications() + " clearable=" + clearable);
1581 if (mStatusBarView != null) {
1582 final View nlo = mStatusBarView.findViewById(R.id.notification_lights_out);
1583 final boolean showDot = hasActiveNotifications() && !areLightsOn();
1584 if (showDot != (nlo.getAlpha() == 1.0f)) {
1587 nlo.setVisibility(View.VISIBLE);
1590 .alpha(showDot ? 1 : 0)
1591 .setDuration(showDot ? 750 : 250)
1592 .setInterpolator(new AccelerateInterpolator(2.0f))
1593 .setListener(showDot ? null : new AnimatorListenerAdapter() {
1595 public void onAnimationEnd(Animator _a) {
1596 nlo.setVisibility(View.GONE);
1603 mMediaManager.findAndUpdateMediaNotifications();
1608 * Hide the album artwork that is fading out and release its bitmap.
1610 protected final Runnable mHideBackdropFront = new Runnable() {
1614 Log.v(TAG, "DEBUG_MEDIA: removing fade layer");
1616 mBackdropFront.setVisibility(View.INVISIBLE);
1617 mBackdropFront.animate().cancel();
1618 mBackdropFront.setImageDrawable(null);
1622 // TODO: Move this to NotificationMediaManager.
1624 * Refresh or remove lockscreen artwork from media metadata or the lockscreen wallpaper.
1627 public void updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation) {
1628 Trace.beginSection("StatusBar#updateMediaMetaData");
1629 if (!SHOW_LOCKSCREEN_MEDIA_ARTWORK) {
1634 if (mBackdrop == null) {
1636 return; // called too early
1639 boolean wakeAndUnlock = mBiometricUnlockController != null
1640 && mBiometricUnlockController.isWakeAndUnlock();
1641 if (mLaunchTransitionFadingAway || wakeAndUnlock) {
1642 mBackdrop.setVisibility(View.INVISIBLE);
1647 MediaMetadata mediaMetadata = mMediaManager.getMediaMetadata();
1650 Log.v(TAG, "DEBUG_MEDIA: updating album art for notification "
1651 + mMediaManager.getMediaNotificationKey()
1652 + " metadata=" + mediaMetadata
1653 + " metaDataChanged=" + metaDataChanged
1654 + " state=" + mState);
1657 Drawable artworkDrawable = null;
1658 if (mediaMetadata != null) {
1659 Bitmap artworkBitmap = mediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ART);
1660 if (artworkBitmap == null) {
1661 artworkBitmap = mediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
1662 // might still be null
1664 if (artworkBitmap != null) {
1665 artworkDrawable = new BitmapDrawable(mBackdropBack.getResources(), artworkBitmap);
1668 boolean allowWhenShade = false;
1669 if (ENABLE_LOCKSCREEN_WALLPAPER && artworkDrawable == null) {
1670 Bitmap lockWallpaper = mLockscreenWallpaper.getBitmap();
1671 if (lockWallpaper != null) {
1672 artworkDrawable = new LockscreenWallpaper.WallpaperDrawable(
1673 mBackdropBack.getResources(), lockWallpaper);
1674 // We're in the SHADE mode on the SIM screen - yet we still need to show
1675 // the lockscreen wallpaper in that mode.
1676 allowWhenShade = mStatusBarKeyguardViewManager != null
1677 && mStatusBarKeyguardViewManager.isShowing();
1681 boolean hideBecauseOccluded = mStatusBarKeyguardViewManager != null
1682 && mStatusBarKeyguardViewManager.isOccluded();
1684 final boolean hasArtwork = artworkDrawable != null;
1685 mColorExtractor.setHasBackdrop(hasArtwork);
1686 if (mScrimController != null) {
1687 mScrimController.setHasBackdrop(hasArtwork);
1690 if ((hasArtwork || DEBUG_MEDIA_FAKE_ARTWORK)
1691 && (mState != StatusBarState.SHADE || allowWhenShade)
1692 && mBiometricUnlockController.getMode()
1693 != BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
1694 && !hideBecauseOccluded) {
1695 // time to show some art!
1696 if (mBackdrop.getVisibility() != View.VISIBLE) {
1697 mBackdrop.setVisibility(View.VISIBLE);
1698 if (allowEnterAnimation) {
1699 mBackdrop.setAlpha(SRC_MIN_ALPHA);
1700 mBackdrop.animate().alpha(1f);
1702 mBackdrop.animate().cancel();
1703 mBackdrop.setAlpha(1f);
1705 mStatusBarWindowManager.setBackdropShowing(true);
1706 metaDataChanged = true;
1708 Log.v(TAG, "DEBUG_MEDIA: Fading in album artwork");
1711 if (metaDataChanged) {
1712 if (mBackdropBack.getDrawable() != null) {
1714 mBackdropBack.getDrawable().getConstantState()
1715 .newDrawable(mBackdropFront.getResources()).mutate();
1716 mBackdropFront.setImageDrawable(drawable);
1717 if (mScrimSrcModeEnabled) {
1718 mBackdropFront.getDrawable().mutate().setXfermode(mSrcOverXferMode);
1720 mBackdropFront.setAlpha(1f);
1721 mBackdropFront.setVisibility(View.VISIBLE);
1723 mBackdropFront.setVisibility(View.INVISIBLE);
1726 if (DEBUG_MEDIA_FAKE_ARTWORK) {
1727 final int c = 0xFF000000 | (int)(Math.random() * 0xFFFFFF);
1728 Log.v(TAG, String.format("DEBUG_MEDIA: setting new color: 0x%08x", c));
1729 mBackdropBack.setBackgroundColor(0xFFFFFFFF);
1730 mBackdropBack.setImageDrawable(new ColorDrawable(c));
1732 mBackdropBack.setImageDrawable(artworkDrawable);
1734 if (mScrimSrcModeEnabled) {
1735 mBackdropBack.getDrawable().mutate().setXfermode(mSrcXferMode);
1738 if (mBackdropFront.getVisibility() == View.VISIBLE) {
1740 Log.v(TAG, "DEBUG_MEDIA: Crossfading album artwork from "
1741 + mBackdropFront.getDrawable()
1743 + mBackdropBack.getDrawable());
1745 mBackdropFront.animate()
1747 .alpha(0f).withEndAction(mHideBackdropFront);
1751 // need to hide the album art, either because we are unlocked, on AOD
1752 // or because the metadata isn't there to support it
1753 if (mBackdrop.getVisibility() != View.GONE) {
1755 Log.v(TAG, "DEBUG_MEDIA: Fading out album artwork");
1757 boolean cannotAnimateDoze = mDozing && !ScrimState.AOD.getAnimateChange();
1758 if (mBiometricUnlockController.getMode()
1759 == BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
1760 || hideBecauseOccluded || cannotAnimateDoze) {
1762 // We are unlocking directly - no animation!
1763 mBackdrop.setVisibility(View.GONE);
1764 mBackdropBack.setImageDrawable(null);
1765 mStatusBarWindowManager.setBackdropShowing(false);
1767 mStatusBarWindowManager.setBackdropShowing(false);
1769 .alpha(SRC_MIN_ALPHA)
1770 .setInterpolator(Interpolators.ACCELERATE_DECELERATE)
1773 .withEndAction(() -> {
1774 mBackdrop.setVisibility(View.GONE);
1775 mBackdropFront.animate().cancel();
1776 mBackdropBack.setImageDrawable(null);
1777 mHandler.post(mHideBackdropFront);
1779 if (mKeyguardFadingAway) {
1781 // Make it disappear faster, as the focus should be on the activity
1783 .setDuration(mKeyguardFadingAwayDuration / 2)
1784 .setStartDelay(mKeyguardFadingAwayDelay)
1785 .setInterpolator(Interpolators.LINEAR)
1794 private void updateReportRejectedTouchVisibility() {
1795 if (mReportRejectedTouch == null) {
1798 mReportRejectedTouch.setVisibility(mState == StatusBarState.KEYGUARD && !mDozing
1799 && mFalsingManager.isReportingEnabled() ? View.VISIBLE : View.INVISIBLE);
1803 * State is one or more of the DISABLE constants from StatusBarManager.
1806 public void disable(int state1, int state2, boolean animate) {
1807 state2 = mRemoteInputQuickSettingsDisabler.adjustDisableFlags(state2);
1809 animate &= mStatusBarWindowState != WINDOW_STATE_HIDDEN;
1810 final int old1 = mDisabled1;
1811 final int diff1 = state1 ^ old1;
1812 mDisabled1 = state1;
1814 final int old2 = mDisabled2;
1815 final int diff2 = state2 ^ old2;
1816 mDisabled2 = state2;
1819 Log.d(TAG, String.format("disable1: 0x%08x -> 0x%08x (diff1: 0x%08x)",
1820 old1, state1, diff1));
1821 Log.d(TAG, String.format("disable2: 0x%08x -> 0x%08x (diff2: 0x%08x)",
1822 old2, state2, diff2));
1825 StringBuilder flagdbg = new StringBuilder();
1826 flagdbg.append("disable<");
1827 flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_EXPAND)) ? 'E' : 'e');
1828 flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_EXPAND)) ? '!' : ' ');
1829 flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS)) ? 'I' : 'i');
1830 flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS)) ? '!' : ' ');
1831 flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS)) ? 'A' : 'a');
1832 flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS)) ? '!' : ' ');
1833 flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_SYSTEM_INFO)) ? 'S' : 's');
1834 flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_SYSTEM_INFO)) ? '!' : ' ');
1835 flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_BACK)) ? 'B' : 'b');
1836 flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_BACK)) ? '!' : ' ');
1837 flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_HOME)) ? 'H' : 'h');
1838 flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_HOME)) ? '!' : ' ');
1839 flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_RECENT)) ? 'R' : 'r');
1840 flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_RECENT)) ? '!' : ' ');
1841 flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_CLOCK)) ? 'C' : 'c');
1842 flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_CLOCK)) ? '!' : ' ');
1843 flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_SEARCH)) ? 'S' : 's');
1844 flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_SEARCH)) ? '!' : ' ');
1845 flagdbg.append("> disable2<");
1846 flagdbg.append(0 != ((state2 & StatusBarManager.DISABLE2_QUICK_SETTINGS)) ? 'Q' : 'q');
1847 flagdbg.append(0 != ((diff2 & StatusBarManager.DISABLE2_QUICK_SETTINGS)) ? '!' : ' ');
1848 flagdbg.append(0 != ((state2 & StatusBarManager.DISABLE2_SYSTEM_ICONS)) ? 'I' : 'i');
1849 flagdbg.append(0 != ((diff2 & StatusBarManager.DISABLE2_SYSTEM_ICONS)) ? '!' : ' ');
1850 flagdbg.append(0 != ((state2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE)) ? 'N' : 'n');
1851 flagdbg.append(0 != ((diff2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE)) ? '!' : ' ');
1852 flagdbg.append('>');
1853 Log.d(TAG, flagdbg.toString());
1855 if ((diff1 & StatusBarManager.DISABLE_EXPAND) != 0) {
1856 if ((state1 & StatusBarManager.DISABLE_EXPAND) != 0) {
1857 animateCollapsePanels();
1861 if ((diff1 & StatusBarManager.DISABLE_RECENT) != 0) {
1862 if ((state1 & StatusBarManager.DISABLE_RECENT) != 0) {
1863 // close recents if it's visible
1864 mHandler.removeMessages(MSG_HIDE_RECENT_APPS);
1865 mHandler.sendEmptyMessage(MSG_HIDE_RECENT_APPS);
1869 if ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) {
1870 mEntryManager.setDisableNotificationAlerts(
1871 (state1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0);
1874 if ((diff2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) {
1875 updateQsExpansionEnabled();
1878 if ((diff2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0) {
1879 updateQsExpansionEnabled();
1880 if ((state1 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0) {
1881 animateCollapsePanels();
1887 * Reapplies the disable flags as last requested by StatusBarManager.
1889 * This needs to be called if state used by {@link #adjustDisableFlags} changes.
1891 public void recomputeDisableFlags(boolean animate) {
1892 mCommandQueue.recomputeDisableFlags(animate);
1895 protected H createHandler() {
1896 return new StatusBar.H();
1899 private void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade,
1901 startActivityDismissingKeyguard(intent, onlyProvisioned, dismissShade, flags);
1905 public void startActivity(Intent intent, boolean dismissShade) {
1906 startActivityDismissingKeyguard(intent, false, dismissShade);
1910 public void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade) {
1911 startActivityDismissingKeyguard(intent, onlyProvisioned, dismissShade);
1915 public void startActivity(Intent intent, boolean dismissShade, Callback callback) {
1916 startActivityDismissingKeyguard(intent, false, dismissShade,
1917 false /* disallowEnterPictureInPictureWhileLaunching */, callback, 0);
1920 public void setQsExpanded(boolean expanded) {
1921 mStatusBarWindowManager.setQsExpanded(expanded);
1922 mNotificationPanel.setStatusAccessibilityImportance(expanded
1923 ? View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
1924 : View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
1927 public boolean isGoingToNotificationShade() {
1928 return mLeaveOpenOnKeyguardHide;
1931 public boolean isWakeUpComingFromTouch() {
1932 return mWakeUpComingFromTouch;
1935 public boolean isFalsingThresholdNeeded() {
1936 return getBarState() == StatusBarState.KEYGUARD;
1940 public boolean isDozing() {
1941 return mDozing && mStackScroller.isFullyDark();
1945 public boolean shouldPeek(Entry entry, StatusBarNotification sbn) {
1946 if (mIsOccluded && !isDozing()) {
1947 boolean devicePublic = mLockscreenUserManager.
1948 isLockscreenPublicMode(mLockscreenUserManager.getCurrentUserId());
1949 boolean userPublic = devicePublic
1950 || mLockscreenUserManager.isLockscreenPublicMode(sbn.getUserId());
1951 boolean needsRedaction = mLockscreenUserManager.needsRedaction(entry);
1952 if (userPublic && needsRedaction) {
1957 if (!panelsEnabled()) {
1959 Log.d(TAG, "No peeking: disabled panel : " + sbn.getKey());
1964 if (sbn.getNotification().fullScreenIntent != null) {
1965 if (mAccessibilityManager.isTouchExplorationEnabled()) {
1966 if (DEBUG) Log.d(TAG, "No peeking: accessible fullscreen: " + sbn.getKey());
1968 } else if (isDozing()) {
1969 // We never want heads up when we are dozing.
1972 // we only allow head-up on the lockscreen if it doesn't have a fullscreen intent
1973 return !mStatusBarKeyguardViewManager.isShowing()
1974 || mStatusBarKeyguardViewManager.isOccluded();
1980 @Override // NotificationData.Environment
1981 public String getCurrentMediaNotificationKey() {
1982 return mMediaManager.getMediaNotificationKey();
1985 public boolean isScrimSrcModeEnabled() {
1986 return mScrimSrcModeEnabled;
1990 * To be called when there's a state change in StatusBarKeyguardViewManager.
1992 public void onKeyguardViewManagerStatesUpdated() {
1993 logStateToEventlog();
1996 @Override // UnlockMethodCache.OnUnlockMethodChangedListener
1997 public void onUnlockMethodStateChanged() {
1998 logStateToEventlog();
2002 public void onHeadsUpPinnedModeChanged(boolean inPinnedMode) {
2004 mStatusBarWindowManager.setHeadsUpShowing(true);
2005 mStatusBarWindowManager.setForceStatusBarVisible(true);
2006 if (mNotificationPanel.isFullyCollapsed()) {
2007 // We need to ensure that the touchable region is updated before the window will be
2008 // resized, in order to not catch any touches. A layout will ensure that
2009 // onComputeInternalInsets will be called and after that we can resize the layout. Let's
2010 // make sure that the window stays small for one frame until the touchableRegion is set.
2011 mNotificationPanel.requestLayout();
2012 mStatusBarWindowManager.setForceWindowCollapsed(true);
2013 mNotificationPanel.post(() -> {
2014 mStatusBarWindowManager.setForceWindowCollapsed(false);
2018 if (!mNotificationPanel.isFullyCollapsed() || mNotificationPanel.isTracking()) {
2019 // We are currently tracking or is open and the shade doesn't need to be kept
2020 // open artificially.
2021 mStatusBarWindowManager.setHeadsUpShowing(false);
2023 // we need to keep the panel open artificially, let's wait until the animation
2025 mHeadsUpManager.setHeadsUpGoingAway(true);
2026 mStackScroller.runAfterAnimationFinished(() -> {
2027 if (!mHeadsUpManager.hasPinnedHeadsUp()) {
2028 mStatusBarWindowManager.setHeadsUpShowing(false);
2029 mHeadsUpManager.setHeadsUpGoingAway(false);
2031 mRemoteInputManager.removeRemoteInputEntriesKeptUntilCollapsed();
2038 public void onHeadsUpPinned(ExpandableNotificationRow headsUp) {
2039 dismissVolumeDialog();
2043 public void onHeadsUpUnPinned(ExpandableNotificationRow headsUp) {
2047 public void onHeadsUpStateChanged(Entry entry, boolean isHeadsUp) {
2048 mEntryManager.onHeadsUpStateChanged(entry, isHeadsUp);
2051 mDozeServiceHost.fireNotificationHeadsUp();
2055 protected void setHeadsUpUser(int newUserId) {
2056 if (mHeadsUpManager != null) {
2057 mHeadsUpManager.setUser(newUserId);
2061 public boolean isKeyguardCurrentlySecure() {
2062 return !mUnlockMethodCache.canSkipBouncer();
2065 public void setPanelExpanded(boolean isExpanded) {
2066 mPanelExpanded = isExpanded;
2067 updateHideIconsForBouncer(false /* animate */);
2068 mStatusBarWindowManager.setPanelExpanded(isExpanded);
2069 mVisualStabilityManager.setPanelExpanded(isExpanded);
2070 if (isExpanded && getBarState() != StatusBarState.KEYGUARD) {
2072 Log.v(TAG, "clearing notification effects from setExpandedHeight");
2074 clearNotificationEffects();
2078 mRemoteInputManager.removeRemoteInputEntriesKeptUntilCollapsed();
2082 public NotificationStackScrollLayout getNotificationScrollLayout() {
2083 return mStackScroller;
2086 public boolean isPulsing() {
2087 return mDozeScrimController != null && mDozeScrimController.isPulsing();
2090 public boolean isLaunchTransitionFadingAway() {
2091 return mLaunchTransitionFadingAway;
2094 public boolean hideStatusBarIconsWhenExpanded() {
2095 return mNotificationPanel.hideStatusBarIconsWhenExpanded();
2099 public void onColorsChanged(ColorExtractor extractor, int which) {
2104 public View getAmbientIndicationContainer() {
2105 return mAmbientIndicationContainer;
2108 public void setOccluded(boolean occluded) {
2109 mIsOccluded = occluded;
2110 mScrimController.setKeyguardOccluded(occluded);
2111 updateHideIconsForBouncer(false /* animate */);
2114 public boolean hideStatusBarIconsForBouncer() {
2115 return mHideIconsForBouncer || mWereIconsJustHidden;
2119 * Decides if the status bar (clock + notifications + signal cluster) should be visible
2120 * or not when showing the bouncer.
2122 * We want to hide it when:
2123 * • User swipes up on the keyguard
2124 * • Locked activity that doesn't show a status bar requests the bouncer
2126 * @param animate should the change of the icons be animated.
2128 private void updateHideIconsForBouncer(boolean animate) {
2129 boolean hideBecauseApp = mTopHidesStatusBar && mIsOccluded
2130 && (mStatusBarWindowHidden || mBouncerShowing);
2131 boolean hideBecauseKeyguard = !mPanelExpanded && !mIsOccluded && mBouncerShowing;
2132 boolean shouldHideIconsForBouncer = hideBecauseApp || hideBecauseKeyguard;
2133 if (mHideIconsForBouncer != shouldHideIconsForBouncer) {
2134 mHideIconsForBouncer = shouldHideIconsForBouncer;
2135 if (!shouldHideIconsForBouncer && mBouncerWasShowingWhenHidden) {
2136 // We're delaying the showing, since most of the time the fullscreen app will
2137 // hide the icons again and we don't want them to fade in and out immediately again.
2138 mWereIconsJustHidden = true;
2139 mHandler.postDelayed(() -> {
2140 mWereIconsJustHidden = false;
2141 recomputeDisableFlags(true);
2144 recomputeDisableFlags(animate);
2147 if (shouldHideIconsForBouncer) {
2148 mBouncerWasShowingWhenHidden = mBouncerShowing;
2152 public void onLaunchAnimationCancelled() {
2153 if (!isCollapsing()) {
2154 onClosingFinished();
2159 * All changes to the status bar and notifications funnel through here and are batched.
2161 protected class H extends Handler {
2163 public void handleMessage(Message m) {
2165 case MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU:
2166 toggleKeyboardShortcuts(m.arg1);
2168 case MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU:
2169 dismissKeyboardShortcuts();
2171 // End old BaseStatusBar.H handling.
2172 case MSG_OPEN_NOTIFICATION_PANEL:
2173 animateExpandNotificationsPanel();
2175 case MSG_OPEN_SETTINGS_PANEL:
2176 animateExpandSettingsPanel((String) m.obj);
2178 case MSG_CLOSE_PANELS:
2179 animateCollapsePanels();
2181 case MSG_LAUNCH_TRANSITION_TIMEOUT:
2182 onLaunchTransitionTimeout();
2188 public void maybeEscalateHeadsUp() {
2189 mHeadsUpManager.getAllEntries().forEach(entry -> {
2190 final StatusBarNotification sbn = entry.notification;
2191 final Notification notification = sbn.getNotification();
2192 if (notification.fullScreenIntent != null) {
2194 Log.d(TAG, "converting a heads up to fullScreen");
2197 EventLog.writeEvent(EventLogTags.SYSUI_HEADS_UP_ESCALATION,
2199 notification.fullScreenIntent.send();
2200 entry.notifyFullScreenIntentLaunched();
2201 } catch (PendingIntent.CanceledException e) {
2205 mHeadsUpManager.releaseAllImmediately();
2209 * Called for system navigation gestures. First action opens the panel, second opens
2210 * settings. Down action closes the entire panel.
2213 public void handleSystemKey(int key) {
2214 if (SPEW) Log.d(TAG, "handleNavigationKey: " + key);
2215 if (!panelsEnabled() || !mKeyguardMonitor.isDeviceInteractive()
2216 || mKeyguardMonitor.isShowing() && !mKeyguardMonitor.isOccluded()) {
2220 // Panels are not available in setup
2221 if (!mUserSetup) return;
2223 if (KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP == key) {
2224 mMetricsLogger.action(MetricsEvent.ACTION_SYSTEM_NAVIGATION_KEY_UP);
2225 mNotificationPanel.collapse(false /* delayed */, 1.0f /* speedUpFactor */);
2226 } else if (KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN == key) {
2227 mMetricsLogger.action(MetricsEvent.ACTION_SYSTEM_NAVIGATION_KEY_DOWN);
2228 if (mNotificationPanel.isFullyCollapsed()) {
2229 if (mVibrateOnOpening) {
2230 mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
2232 mNotificationPanel.expand(true /* animate */);
2233 mMetricsLogger.count(NotificationPanelView.COUNTER_PANEL_OPEN, 1);
2234 } else if (!mNotificationPanel.isInSettings() && !mNotificationPanel.isExpanding()){
2235 mNotificationPanel.flingSettings(0 /* velocity */, true /* expand */);
2236 mMetricsLogger.count(NotificationPanelView.COUNTER_PANEL_OPEN_QS, 1);
2243 public void showPinningEnterExitToast(boolean entering) {
2244 if (getNavigationBarView() != null) {
2245 getNavigationBarView().showPinningEnterExitToast(entering);
2250 public void showPinningEscapeToast() {
2251 if (getNavigationBarView() != null) {
2252 getNavigationBarView().showPinningEscapeToast();
2256 boolean panelsEnabled() {
2257 return (mDisabled1 & StatusBarManager.DISABLE_EXPAND) == 0
2258 && (mDisabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) == 0
2262 void makeExpandedVisible(boolean force) {
2263 if (SPEW) Log.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible);
2264 if (!force && (mExpandedVisible || !panelsEnabled())) {
2268 mExpandedVisible = true;
2270 // Expand the window to encompass the full screen in anticipation of the drag.
2271 // This is only possible to do atomically because the status bar is at the top of the screen!
2272 mStatusBarWindowManager.setPanelVisible(true);
2274 visibilityChanged(true);
2275 recomputeDisableFlags(!force /* animate */);
2276 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true);
2279 public void animateCollapsePanels() {
2280 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
2283 private final Runnable mAnimateCollapsePanels = this::animateCollapsePanels;
2285 public void postAnimateCollapsePanels() {
2286 mHandler.post(mAnimateCollapsePanels);
2289 public void postAnimateForceCollapsePanels() {
2290 mHandler.post(() -> {
2291 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */);
2295 public void postAnimateOpenPanels() {
2296 mHandler.sendEmptyMessage(MSG_OPEN_SETTINGS_PANEL);
2300 public void togglePanel() {
2301 if (mPanelExpanded) {
2302 animateCollapsePanels();
2304 animateExpandNotificationsPanel();
2309 public void animateCollapsePanels(int flags) {
2310 animateCollapsePanels(flags, false /* force */, false /* delayed */,
2311 1.0f /* speedUpFactor */);
2314 public void animateCollapsePanels(int flags, boolean force) {
2315 animateCollapsePanels(flags, force, false /* delayed */, 1.0f /* speedUpFactor */);
2318 public void animateCollapsePanels(int flags, boolean force, boolean delayed) {
2319 animateCollapsePanels(flags, force, delayed, 1.0f /* speedUpFactor */);
2322 public void animateCollapsePanels(int flags, boolean force, boolean delayed,
2323 float speedUpFactor) {
2324 if (!force && mState != StatusBarState.SHADE) {
2325 runPostCollapseRunnables();
2329 Log.d(TAG, "animateCollapse():"
2330 + " mExpandedVisible=" + mExpandedVisible
2331 + " flags=" + flags);
2334 if ((flags & CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL) == 0) {
2335 if (!mHandler.hasMessages(MSG_HIDE_RECENT_APPS)) {
2336 mHandler.removeMessages(MSG_HIDE_RECENT_APPS);
2337 mHandler.sendEmptyMessage(MSG_HIDE_RECENT_APPS);
2341 // TODO(b/62444020): remove when this bug is fixed
2342 Log.v(TAG, "mStatusBarWindow: " + mStatusBarWindow + " canPanelBeCollapsed(): "
2343 + mNotificationPanel.canPanelBeCollapsed());
2344 if (mStatusBarWindow != null && mNotificationPanel.canPanelBeCollapsed()) {
2345 // release focus immediately to kick off focus change transition
2346 mStatusBarWindowManager.setStatusBarFocusable(false);
2348 mStatusBarWindow.cancelExpandHelper();
2349 mStatusBarView.collapsePanel(true /* animate */, delayed, speedUpFactor);
2353 private void runPostCollapseRunnables() {
2354 ArrayList<Runnable> clonedList = new ArrayList<>(mPostCollapseRunnables);
2355 mPostCollapseRunnables.clear();
2356 int size = clonedList.size();
2357 for (int i = 0; i < size; i++) {
2358 clonedList.get(i).run();
2360 mStatusBarKeyguardViewManager.readyForKeyguardDone();
2364 public void animateExpandNotificationsPanel() {
2365 if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible);
2366 if (!panelsEnabled()) {
2370 mNotificationPanel.expandWithoutQs();
2372 if (false) postStartTracing();
2376 public void animateExpandSettingsPanel(String subPanel) {
2377 if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible);
2378 if (!panelsEnabled()) {
2382 // Settings are not available in setup
2383 if (!mUserSetup) return;
2386 if (subPanel != null) {
2387 mQSPanel.openDetails(subPanel);
2389 mNotificationPanel.expandWithQs();
2391 if (false) postStartTracing();
2394 public void animateCollapseQuickSettings() {
2395 if (mState == StatusBarState.SHADE) {
2396 mStatusBarView.collapsePanel(true, false /* delayed */, 1.0f /* speedUpFactor */);
2400 void makeExpandedInvisible() {
2401 if (SPEW) Log.d(TAG, "makeExpandedInvisible: mExpandedVisible=" + mExpandedVisible
2402 + " mExpandedVisible=" + mExpandedVisible);
2404 if (!mExpandedVisible || mStatusBarWindow == null) {
2408 // Ensure the panel is fully collapsed (just in case; bug 6765842, 7260868)
2409 mStatusBarView.collapsePanel(/*animate=*/ false, false /* delayed*/,
2410 1.0f /* speedUpFactor */);
2412 mNotificationPanel.closeQs();
2414 mExpandedVisible = false;
2415 visibilityChanged(false);
2417 // Shrink the window to the size of the status bar only
2418 mStatusBarWindowManager.setPanelVisible(false);
2419 mStatusBarWindowManager.setForceStatusBarVisible(false);
2421 // Close any guts that might be visible
2422 mGutsManager.closeAndSaveGuts(true /* removeLeavebehind */, true /* force */,
2423 true /* removeControls */, -1 /* x */, -1 /* y */, true /* resetMenu */);
2425 runPostCollapseRunnables();
2426 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
2427 showBouncerIfKeyguard();
2428 recomputeDisableFlags(mNotificationPanel.hideStatusBarIconsWhenExpanded() /* animate */);
2430 // Trimming will happen later if Keyguard is showing - doing it here might cause a jank in
2431 // the bouncer appear animation.
2432 if (!mStatusBarKeyguardViewManager.isShowing()) {
2433 WindowManagerGlobal.getInstance().trimMemory(ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
2437 public boolean interceptTouchEvent(MotionEvent event) {
2438 if (DEBUG_GESTURES) {
2439 if (event.getActionMasked() != MotionEvent.ACTION_MOVE) {
2440 EventLog.writeEvent(EventLogTags.SYSUI_STATUSBAR_TOUCH,
2441 event.getActionMasked(), (int) event.getX(), (int) event.getY(),
2442 mDisabled1, mDisabled2);
2448 Log.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled1="
2449 + mDisabled1 + " mDisabled2=" + mDisabled2);
2450 } else if (CHATTY) {
2451 if (event.getAction() != MotionEvent.ACTION_MOVE) {
2452 Log.d(TAG, String.format(
2453 "panel: %s at (%f, %f) mDisabled1=0x%08x mDisabled2=0x%08x",
2454 MotionEvent.actionToString(event.getAction()),
2455 event.getRawX(), event.getRawY(), mDisabled1, mDisabled2));
2459 if (DEBUG_GESTURES) {
2460 mGestureRec.add(event);
2463 if (mStatusBarWindowState == WINDOW_STATE_SHOWING) {
2464 final boolean upOrCancel =
2465 event.getAction() == MotionEvent.ACTION_UP ||
2466 event.getAction() == MotionEvent.ACTION_CANCEL;
2467 if (upOrCancel && !mExpandedVisible) {
2468 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
2470 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true);
2476 public GestureRecorder getGestureRecorder() {
2480 public BiometricUnlockController getBiometricUnlockController() {
2481 return mBiometricUnlockController;
2484 @Override // CommandQueue
2485 public void setWindowState(int window, int state) {
2486 boolean showing = state == WINDOW_STATE_SHOWING;
2487 if (mStatusBarWindow != null
2488 && window == StatusBarManager.WINDOW_STATUS_BAR
2489 && mStatusBarWindowState != state) {
2490 mStatusBarWindowState = state;
2491 if (DEBUG_WINDOW_STATE) Log.d(TAG, "Status bar " + windowStateToString(state));
2492 if (!showing && mState == StatusBarState.SHADE) {
2493 mStatusBarView.collapsePanel(false /* animate */, false /* delayed */,
2494 1.0f /* speedUpFactor */);
2496 if (mStatusBarView != null) {
2497 mStatusBarWindowHidden = state == WINDOW_STATE_HIDDEN;
2498 updateHideIconsForBouncer(false /* animate */);
2503 @Override // CommandQueue
2504 public void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis,
2505 int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
2506 final int oldVal = mSystemUiVisibility;
2507 final int newVal = (oldVal&~mask) | (vis&mask);
2508 final int diff = newVal ^ oldVal;
2509 if (DEBUG) Log.d(TAG, String.format(
2510 "setSystemUiVisibility vis=%s mask=%s oldVal=%s newVal=%s diff=%s",
2511 Integer.toHexString(vis), Integer.toHexString(mask),
2512 Integer.toHexString(oldVal), Integer.toHexString(newVal),
2513 Integer.toHexString(diff)));
2514 boolean sbModeChanged = false;
2516 mSystemUiVisibility = newVal;
2518 // update low profile
2519 if ((diff & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0) {
2520 setAreThereNotifications();
2524 if ((vis & View.STATUS_BAR_UNHIDE) != 0) {
2525 mSystemUiVisibility &= ~View.STATUS_BAR_UNHIDE;
2526 mNoAnimationOnNextBarModeChange = true;
2529 // update status bar mode
2530 final int sbMode = computeStatusBarMode(oldVal, newVal);
2532 sbModeChanged = sbMode != -1;
2533 if (sbModeChanged && sbMode != mStatusBarMode) {
2534 mStatusBarMode = sbMode;
2539 if ((vis & View.NAVIGATION_BAR_UNHIDE) != 0) {
2540 mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE;
2543 // send updated sysui visibility to window manager
2544 notifyUiVisibilityChanged(mSystemUiVisibility);
2547 mLightBarController.onSystemUiVisibilityChanged(fullscreenStackVis, dockedStackVis,
2548 mask, fullscreenStackBounds, dockedStackBounds, sbModeChanged, mStatusBarMode);
2552 public void showWirelessChargingAnimation(int batteryLevel) {
2553 if (mDozing || mKeyguardManager.isKeyguardLocked()) {
2554 // on ambient or lockscreen, hide notification panel
2555 WirelessChargingAnimation.makeWirelessChargingAnimation(mContext, null,
2556 batteryLevel, new WirelessChargingAnimation.Callback() {
2558 public void onAnimationStarting() {
2559 CrossFadeHelper.fadeOut(mNotificationPanel, 1);
2563 public void onAnimationEnded() {
2564 CrossFadeHelper.fadeIn(mNotificationPanel);
2569 WirelessChargingAnimation.makeWirelessChargingAnimation(mContext, null,
2570 batteryLevel, null, false).show();
2574 void touchAutoHide() {
2575 // update transient bar autohide
2576 if (mStatusBarMode == MODE_SEMI_TRANSPARENT || (mNavigationBar != null
2577 && mNavigationBar.isSemiTransparent())) {
2584 protected int computeStatusBarMode(int oldVal, int newVal) {
2585 return computeBarMode(oldVal, newVal, View.STATUS_BAR_TRANSIENT,
2586 View.STATUS_BAR_TRANSLUCENT, View.STATUS_BAR_TRANSPARENT);
2589 protected BarTransitions getStatusBarTransitions() {
2590 return mStatusBarView.getBarTransitions();
2593 protected int computeBarMode(int oldVis, int newVis,
2594 int transientFlag, int translucentFlag, int transparentFlag) {
2595 final int oldMode = barMode(oldVis, transientFlag, translucentFlag, transparentFlag);
2596 final int newMode = barMode(newVis, transientFlag, translucentFlag, transparentFlag);
2597 if (oldMode == newMode) {
2598 return -1; // no mode change
2603 private int barMode(int vis, int transientFlag, int translucentFlag, int transparentFlag) {
2604 int lightsOutTransparent = View.SYSTEM_UI_FLAG_LOW_PROFILE | transparentFlag;
2605 return (vis & transientFlag) != 0 ? MODE_SEMI_TRANSPARENT
2606 : (vis & translucentFlag) != 0 ? MODE_TRANSLUCENT
2607 : (vis & lightsOutTransparent) == lightsOutTransparent ? MODE_LIGHTS_OUT_TRANSPARENT
2608 : (vis & transparentFlag) != 0 ? MODE_TRANSPARENT
2609 : (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0 ? MODE_LIGHTS_OUT
2613 void checkBarModes() {
2614 if (mDemoMode) return;
2615 if (mStatusBarView != null) checkBarMode(mStatusBarMode, mStatusBarWindowState,
2616 getStatusBarTransitions());
2617 if (mNavigationBar != null) mNavigationBar.checkNavBarModes();
2618 mNoAnimationOnNextBarModeChange = false;
2621 // Called by NavigationBarFragment
2622 void setQsScrimEnabled(boolean scrimEnabled) {
2623 mNotificationPanel.setQsScrimEnabled(scrimEnabled);
2626 void checkBarMode(int mode, int windowState, BarTransitions transitions) {
2627 final boolean anim = !mNoAnimationOnNextBarModeChange && mDeviceInteractive
2628 && windowState != WINDOW_STATE_HIDDEN;
2629 transitions.transitionTo(mode, anim);
2632 private void finishBarAnimations() {
2633 if (mStatusBarView != null) {
2634 mStatusBarView.getBarTransitions().finishAnimations();
2636 if (mNavigationBar != null) {
2637 mNavigationBar.finishBarAnimations();
2641 private final Runnable mCheckBarModes = this::checkBarModes;
2643 public void setInteracting(int barWindow, boolean interacting) {
2644 final boolean changing = ((mInteractingWindows & barWindow) != 0) != interacting;
2645 mInteractingWindows = interacting
2646 ? (mInteractingWindows | barWindow)
2647 : (mInteractingWindows & ~barWindow);
2648 if (mInteractingWindows != 0) {
2651 resumeSuspendedAutohide();
2653 // manually dismiss the volume panel when interacting with the nav bar
2654 if (changing && interacting && barWindow == StatusBarManager.WINDOW_NAVIGATION_BAR) {
2656 dismissVolumeDialog();
2661 private void dismissVolumeDialog() {
2662 if (mVolumeComponent != null) {
2663 mVolumeComponent.dismissNow();
2667 private void resumeSuspendedAutohide() {
2668 if (mAutohideSuspended) {
2670 mHandler.postDelayed(mCheckBarModes, 500); // longer than home -> launcher
2674 private void suspendAutohide() {
2675 mHandler.removeCallbacks(mAutohide);
2676 mHandler.removeCallbacks(mCheckBarModes);
2677 mAutohideSuspended = (mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0;
2680 private void cancelAutohide() {
2681 mAutohideSuspended = false;
2682 mHandler.removeCallbacks(mAutohide);
2685 private void scheduleAutohide() {
2687 mHandler.postDelayed(mAutohide, AUTOHIDE_TIMEOUT_MS);
2690 public void touchAutoDim() {
2691 if (mNavigationBar != null) {
2692 mNavigationBar.getBarTransitions().setAutoDim(false);
2694 mHandler.removeCallbacks(mAutoDim);
2695 if (mState != StatusBarState.KEYGUARD && mState != StatusBarState.SHADE_LOCKED) {
2696 mHandler.postDelayed(mAutoDim, AUTOHIDE_TIMEOUT_MS);
2700 void checkUserAutohide(MotionEvent event) {
2701 if ((mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0 // a transient bar is revealed
2702 && event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar
2703 && event.getX() == 0 && event.getY() == 0 // a touch outside both bars
2704 && !mRemoteInputManager.getController()
2705 .isRemoteInputActive()) { // not due to typing in IME
2710 private void userAutohide() {
2712 mHandler.postDelayed(mAutohide, 350); // longer than app gesture -> flag clear
2715 private boolean areLightsOn() {
2716 return 0 == (mSystemUiVisibility & View.SYSTEM_UI_FLAG_LOW_PROFILE);
2719 public void setLightsOn(boolean on) {
2720 Log.v(TAG, "setLightsOn(" + on + ")");
2722 setSystemUiVisibility(0, 0, 0, View.SYSTEM_UI_FLAG_LOW_PROFILE,
2723 mLastFullscreenStackBounds, mLastDockedStackBounds);
2725 setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE, 0, 0,
2726 View.SYSTEM_UI_FLAG_LOW_PROFILE, mLastFullscreenStackBounds,
2727 mLastDockedStackBounds);
2731 private void notifyUiVisibilityChanged(int vis) {
2733 if (mLastDispatchedSystemUiVisibility != vis) {
2734 mWindowManagerService.statusBarVisibilityChanged(vis);
2735 mLastDispatchedSystemUiVisibility = vis;
2737 } catch (RemoteException ex) {
2742 public void topAppWindowChanged(boolean showMenu) {
2744 Log.d(TAG, (showMenu?"showing":"hiding") + " the MENU button");
2747 // See above re: lights-out policy for legacy apps.
2748 if (showMenu) setLightsOn(true);
2751 public static String viewInfo(View v) {
2752 return "[(" + v.getLeft() + "," + v.getTop() + ")(" + v.getRight() + "," + v.getBottom()
2753 + ") " + v.getWidth() + "x" + v.getHeight() + "]";
2757 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2758 synchronized (mQueueLock) {
2759 pw.println("Current Status Bar state:");
2760 pw.println(" mExpandedVisible=" + mExpandedVisible);
2761 pw.println(" mDisplayMetrics=" + mDisplayMetrics);
2762 pw.println(" mStackScroller: " + viewInfo(mStackScroller));
2763 pw.println(" mStackScroller: " + viewInfo(mStackScroller)
2764 + " scroll " + mStackScroller.getScrollX()
2765 + "," + mStackScroller.getScrollY());
2768 pw.print(" mInteractingWindows="); pw.println(mInteractingWindows);
2769 pw.print(" mStatusBarWindowState=");
2770 pw.println(windowStateToString(mStatusBarWindowState));
2771 pw.print(" mStatusBarMode=");
2772 pw.println(BarTransitions.modeToString(mStatusBarMode));
2773 pw.print(" mDozing="); pw.println(mDozing);
2774 pw.print(" mZenMode=");
2775 pw.println(Settings.Global.zenModeToString(Settings.Global.getInt(
2776 mContext.getContentResolver(), Settings.Global.ZEN_MODE,
2777 Settings.Global.ZEN_MODE_OFF)));
2779 if (mStatusBarView != null) {
2780 dumpBarTransitions(pw, "mStatusBarView", mStatusBarView.getBarTransitions());
2782 pw.println(" StatusBarWindowView: ");
2783 if (mStatusBarWindow != null) {
2784 mStatusBarWindow.dump(fd, pw, args);
2787 pw.println(" mMediaManager: ");
2788 if (mMediaManager != null) {
2789 mMediaManager.dump(fd, pw, args);
2792 pw.println(" Panels: ");
2793 if (mNotificationPanel != null) {
2794 pw.println(" mNotificationPanel=" +
2795 mNotificationPanel + " params=" + mNotificationPanel.getLayoutParams().debug(""));
2797 mNotificationPanel.dump(fd, pw, args);
2799 pw.println(" mStackScroller: ");
2800 if (mStackScroller != null) {
2802 mStackScroller.dump(fd, pw, args);
2804 pw.println(" Theme:");
2805 String nightMode = mUiModeManager == null ? "null" : mUiModeManager.getNightMode() + "";
2806 pw.println(" dark theme: " + nightMode +
2807 " (auto: " + UiModeManager.MODE_NIGHT_AUTO +
2808 ", yes: " + UiModeManager.MODE_NIGHT_YES +
2809 ", no: " + UiModeManager.MODE_NIGHT_NO + ")");
2810 final boolean lightWpTheme = mContext.getThemeResId() == R.style.Theme_SystemUI_Light;
2811 pw.println(" light wallpaper theme: " + lightWpTheme);
2815 if (mBiometricUnlockController != null) {
2816 mBiometricUnlockController.dump(pw);
2819 if (mKeyguardIndicationController != null) {
2820 mKeyguardIndicationController.dump(fd, pw, args);
2823 if (mScrimController != null) {
2824 mScrimController.dump(fd, pw, args);
2827 if (mStatusBarKeyguardViewManager != null) {
2828 mStatusBarKeyguardViewManager.dump(pw);
2832 synchronized (mEntryManager.getNotificationData()) {
2833 mEntryManager.getNotificationData().dump(pw, " ");
2837 pw.println("see the logcat for a dump of the views we have created.");
2838 // must happen on ui thread
2839 mHandler.post(() -> {
2840 mStatusBarView.getLocationOnScreen(mAbsPos);
2841 Log.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1] +
2842 ") " + mStatusBarView.getWidth() + "x" + getStatusBarHeight());
2843 mStatusBarView.debug();
2848 if (DEBUG_GESTURES) {
2849 pw.print(" status bar gestures: ");
2850 mGestureRec.dump(fd, pw, args);
2853 if (mHeadsUpManager != null) {
2854 mHeadsUpManager.dump(fd, pw, args);
2856 pw.println(" mHeadsUpManager: null");
2858 if (mGroupManager != null) {
2859 mGroupManager.dump(fd, pw, args);
2861 pw.println(" mGroupManager: null");
2864 if (mLightBarController != null) {
2865 mLightBarController.dump(fd, pw, args);
2868 if (KeyguardUpdateMonitor.getInstance(mContext) != null) {
2869 KeyguardUpdateMonitor.getInstance(mContext).dump(fd, pw, args);
2872 FalsingManager.getInstance(mContext).dump(pw);
2873 FalsingLog.dump(pw);
2875 pw.println("SharedPreferences:");
2876 for (Map.Entry<String, ?> entry : Prefs.getAll(mContext).entrySet()) {
2877 pw.print(" "); pw.print(entry.getKey()); pw.print("="); pw.println(entry.getValue());
2881 static void dumpBarTransitions(PrintWriter pw, String var, BarTransitions transitions) {
2882 pw.print(" "); pw.print(var); pw.print(".BarTransitions.mMode=");
2883 pw.println(BarTransitions.modeToString(transitions.getMode()));
2886 public void createAndAddWindows() {
2887 addStatusBarWindow();
2890 private void addStatusBarWindow() {
2891 makeStatusBarView();
2892 mStatusBarWindowManager = Dependency.get(StatusBarWindowManager.class);
2893 mRemoteInputManager.setUpWithPresenter(this, mEntryManager, this,
2894 new RemoteInputController.Delegate() {
2895 public void setRemoteInputActive(NotificationData.Entry entry,
2896 boolean remoteInputActive) {
2897 mHeadsUpManager.setRemoteInputActive(entry, remoteInputActive);
2898 entry.row.notifyHeightChanged(true /* needsAnimation */);
2901 public void lockScrollTo(NotificationData.Entry entry) {
2902 mStackScroller.lockScrollTo(entry.row);
2904 public void requestDisallowLongPressAndDismiss() {
2905 mStackScroller.requestDisallowLongPress();
2906 mStackScroller.requestDisallowDismiss();
2909 mRemoteInputManager.getController().addCallback(mStatusBarWindowManager);
2910 mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());
2913 // called by makeStatusbar and also by PhoneStatusBarView
2914 void updateDisplaySize() {
2915 mDisplay.getMetrics(mDisplayMetrics);
2916 mDisplay.getSize(mCurrentDisplaySize);
2917 if (DEBUG_GESTURES) {
2918 mGestureRec.tag("display",
2919 String.format("%dx%d", mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels));
2923 float getDisplayDensity() {
2924 return mDisplayMetrics.density;
2927 float getDisplayWidth() {
2928 return mDisplayMetrics.widthPixels;
2931 float getDisplayHeight() {
2932 return mDisplayMetrics.heightPixels;
2936 return mDisplay.getRotation();
2939 public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned,
2940 boolean dismissShade, int flags) {
2941 startActivityDismissingKeyguard(intent, onlyProvisioned, dismissShade,
2942 false /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */,
2946 public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned,
2947 boolean dismissShade) {
2948 startActivityDismissingKeyguard(intent, onlyProvisioned, dismissShade, 0);
2951 public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned,
2952 final boolean dismissShade, final boolean disallowEnterPictureInPictureWhileLaunching,
2953 final Callback callback, int flags) {
2954 if (onlyProvisioned && !isDeviceProvisioned()) return;
2956 final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity(
2957 mContext, intent, mLockscreenUserManager.getCurrentUserId());
2958 Runnable runnable = () -> {
2959 mAssistManager.hideAssist();
2961 Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
2962 intent.addFlags(flags);
2963 int result = ActivityManager.START_CANCELED;
2964 ActivityOptions options = new ActivityOptions(getActivityOptions(
2965 null /* remoteAnimation */));
2966 options.setDisallowEnterPictureInPictureWhileLaunching(
2967 disallowEnterPictureInPictureWhileLaunching);
2968 if (intent == KeyguardBottomAreaView.INSECURE_CAMERA_INTENT) {
2969 // Normally an activity will set it's requested rotation
2970 // animation on its window. However when launching an activity
2971 // causes the orientation to change this is too late. In these cases
2972 // the default animation is used. This doesn't look good for
2973 // the camera (as it rotates the camera contents out of sync
2974 // with physical reality). So, we ask the WindowManager to
2975 // force the crossfade animation if an orientation change
2976 // happens to occur during the launch.
2977 options.setRotationAnimationHint(
2978 WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS);
2981 result = ActivityTaskManager.getService().startActivityAsUser(
2982 null, mContext.getBasePackageName(),
2984 intent.resolveTypeIfNeeded(mContext.getContentResolver()),
2985 null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null,
2986 options.toBundle(), UserHandle.CURRENT.getIdentifier());
2987 } catch (RemoteException e) {
2988 Log.w(TAG, "Unable to start activity", e);
2990 if (callback != null) {
2991 callback.onActivityStarted(result);
2994 Runnable cancelRunnable = () -> {
2995 if (callback != null) {
2996 callback.onActivityStarted(ActivityManager.START_CANCELED);
2999 executeRunnableDismissingKeyguard(runnable, cancelRunnable, dismissShade,
3000 afterKeyguardGone, true /* deferred */);
3003 public void readyForKeyguardDone() {
3004 mStatusBarKeyguardViewManager.readyForKeyguardDone();
3007 public void executeRunnableDismissingKeyguard(final Runnable runnable,
3008 final Runnable cancelAction,
3009 final boolean dismissShade,
3010 final boolean afterKeyguardGone,
3011 final boolean deferred) {
3012 dismissKeyguardThenExecute(() -> {
3013 if (runnable != null) {
3014 if (mStatusBarKeyguardViewManager.isShowing()
3015 && mStatusBarKeyguardViewManager.isOccluded()) {
3016 mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(runnable);
3018 AsyncTask.execute(runnable);
3022 if (mExpandedVisible) {
3023 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */,
3027 // Do it after DismissAction has been processed to conserve the needed ordering.
3028 mHandler.post(this::runPostCollapseRunnables);
3030 } else if (isInLaunchTransition() && mNotificationPanel.isLaunchTransitionFinished()) {
3032 // We are not dismissing the shade, but the launch transition is already finished,
3033 // so nobody will call readyForKeyguardDone anymore. Post it such that
3034 // keyguardDonePending gets called first.
3035 mHandler.post(mStatusBarKeyguardViewManager::readyForKeyguardDone);
3038 }, cancelAction, afterKeyguardGone);
3041 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
3043 public void onReceive(Context context, Intent intent) {
3044 if (DEBUG) Log.v(TAG, "onReceive: " + intent);
3045 String action = intent.getAction();
3046 if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
3047 KeyboardShortcuts.dismiss();
3048 if (mRemoteInputManager.getController() != null) {
3049 mRemoteInputManager.getController().closeRemoteInputs();
3051 if (mLockscreenUserManager.isCurrentProfile(getSendingUserId())) {
3052 int flags = CommandQueue.FLAG_EXCLUDE_NONE;
3053 String reason = intent.getStringExtra("reason");
3054 if (reason != null && reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) {
3055 flags |= CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL;
3057 animateCollapsePanels(flags);
3060 else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
3061 finishBarAnimations();
3062 resetUserExpandedStates();
3064 else if (DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG.equals(action)) {
3065 mQSPanel.showDeviceMonitoringDialog();
3070 private final BroadcastReceiver mDemoReceiver = new BroadcastReceiver() {
3072 public void onReceive(Context context, Intent intent) {
3073 if (DEBUG) Log.v(TAG, "onReceive: " + intent);
3074 String action = intent.getAction();
3075 if (ACTION_DEMO.equals(action)) {
3076 Bundle bundle = intent.getExtras();
3077 if (bundle != null) {
3078 String command = bundle.getString("command", "").trim().toLowerCase();
3079 if (command.length() > 0) {
3081 dispatchDemoCommand(command, bundle);
3082 } catch (Throwable t) {
3083 Log.w(TAG, "Error running demo command, intent=" + intent, t);
3087 } else if (ACTION_FAKE_ARTWORK.equals(action)) {
3088 if (DEBUG_MEDIA_FAKE_ARTWORK) {
3089 updateMediaMetaData(true, true);
3095 public void resetUserExpandedStates() {
3096 ArrayList<Entry> activeNotifications = mEntryManager.getNotificationData()
3097 .getActiveNotifications();
3098 final int notificationCount = activeNotifications.size();
3099 for (int i = 0; i < notificationCount; i++) {
3100 NotificationData.Entry entry = activeNotifications.get(i);
3101 if (entry.row != null) {
3102 entry.row.resetUserExpansion();
3107 private void executeWhenUnlocked(OnDismissAction action) {
3108 if (mStatusBarKeyguardViewManager.isShowing()) {
3109 mLeaveOpenOnKeyguardHide = true;
3111 dismissKeyguardThenExecute(action, null /* cancelAction */, false /* afterKeyguardGone */);
3114 protected void dismissKeyguardThenExecute(OnDismissAction action, boolean afterKeyguardGone) {
3115 dismissKeyguardThenExecute(action, null /* cancelRunnable */, afterKeyguardGone);
3118 private void dismissKeyguardThenExecute(OnDismissAction action, Runnable cancelAction,
3119 boolean afterKeyguardGone) {
3120 if (mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_ASLEEP
3121 && mUnlockMethodCache.canSkipBouncer()
3122 && !mLeaveOpenOnKeyguardHide
3124 // Reuse the biometric wake-and-unlock transition if we dismiss keyguard from a pulse.
3125 // TODO: Factor this transition out of BiometricUnlockController.
3126 mBiometricUnlockController.startWakeAndUnlock(
3127 BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING);
3129 if (mStatusBarKeyguardViewManager.isShowing()) {
3130 mStatusBarKeyguardViewManager.dismissWithAction(action, cancelAction,
3137 // SystemUIService notifies SystemBars of configuration changes, which then calls down here
3139 public void onConfigChanged(Configuration newConfig) {
3141 updateDisplaySize(); // populates mDisplayMetrics
3144 Log.v(TAG, "configuration changed: " + mContext.getResources().getConfiguration());
3147 mViewHierarchyManager.updateRowStates();
3148 mScreenPinningRequest.onConfigurationChanged();
3152 public void onUserSwitched(int newUserId) {
3153 // Begin old BaseStatusBar.userSwitched
3154 setHeadsUpUser(newUserId);
3155 // End old BaseStatusBar.userSwitched
3156 if (MULTIUSER_DEBUG) mNotificationPanelDebugText.setText("USER " + newUserId);
3157 animateCollapsePanels();
3159 mEntryManager.getNotificationData().filterAndSort();
3160 if (mReinflateNotificationsOnUserSwitched) {
3161 mEntryManager.updateNotificationsOnDensityOrFontScaleChanged();
3162 mReinflateNotificationsOnUserSwitched = false;
3164 updateNotificationViews();
3165 mMediaManager.clearCurrentMediaNotification();
3166 setLockscreenUser(newUserId);
3167 mWallpaperChangedReceiver.onReceive(mContext, null);
3171 public NotificationLockscreenUserManager getNotificationLockscreenUserManager() {
3172 return mLockscreenUserManager;
3176 public void onBindRow(Entry entry, PackageManager pmUser,
3177 StatusBarNotification sbn, ExpandableNotificationRow row) {
3178 row.setAboveShelfChangedListener(mAboveShelfObserver);
3179 row.setSecureStateProvider(this::isKeyguardCurrentlySecure);
3182 protected void setLockscreenUser(int newUserId) {
3183 mLockscreenWallpaper.setCurrentUser(newUserId);
3184 mScrimController.setCurrentUser(newUserId);
3185 updateMediaMetaData(true, false);
3189 * Reload some of our resources when the configuration changes.
3191 * We don't reload everything when the configuration changes -- we probably
3192 * should, but getting that smooth is tough. Someday we'll fix that. In the
3193 * meantime, just update the things that we know change.
3195 void updateResources() {
3196 // Update the quick setting tiles
3197 if (mQSPanel != null) {
3198 mQSPanel.updateResources();
3203 if (mStatusBarView != null) {
3204 mStatusBarView.updateResources();
3206 if (mNotificationPanel != null) {
3207 mNotificationPanel.updateResources();
3209 if (mBrightnessMirrorController != null) {
3210 mBrightnessMirrorController.updateResources();
3214 protected void loadDimens() {
3215 final Resources res = mContext.getResources();
3217 int oldBarHeight = mNaturalBarHeight;
3218 mNaturalBarHeight = res.getDimensionPixelSize(
3219 com.android.internal.R.dimen.status_bar_height);
3220 if (mStatusBarWindowManager != null && mNaturalBarHeight != oldBarHeight) {
3221 mStatusBarWindowManager.setBarHeight(mNaturalBarHeight);
3223 mMaxAllowedKeyguardNotifications = res.getInteger(
3224 R.integer.keyguard_max_notification_count);
3226 if (DEBUG) Log.v(TAG, "defineSlots");
3229 // Visibility reporting
3231 protected void handleVisibleToUserChanged(boolean visibleToUser) {
3232 if (visibleToUser) {
3233 handleVisibleToUserChangedImpl(visibleToUser);
3234 mNotificationLogger.startNotificationLogging();
3236 mNotificationLogger.stopNotificationLogging();
3237 handleVisibleToUserChangedImpl(visibleToUser);
3241 void handlePeekToExpandTransistion() {
3243 // consider the transition from peek to expanded to be a panel open,
3244 // but not one that clears notification effects.
3245 int notificationLoad = mEntryManager.getNotificationData()
3246 .getActiveNotifications().size();
3247 mBarService.onPanelRevealed(false, notificationLoad);
3248 } catch (RemoteException ex) {
3249 // Won't fail unless the world has ended.
3254 * The LEDs are turned off when the notification panel is shown, even just a little bit.
3255 * See also StatusBar.setPanelExpanded for another place where we attempt to do this.
3257 private void handleVisibleToUserChangedImpl(boolean visibleToUser) {
3258 if (visibleToUser) {
3259 boolean pinnedHeadsUp = mHeadsUpManager.hasPinnedHeadsUp();
3260 boolean clearNotificationEffects =
3261 !isPresenterFullyCollapsed() &&
3262 (mState == StatusBarState.SHADE
3263 || mState == StatusBarState.SHADE_LOCKED);
3264 int notificationLoad = mEntryManager.getNotificationData().getActiveNotifications()
3266 if (pinnedHeadsUp && isPresenterFullyCollapsed()) {
3267 notificationLoad = 1;
3269 final int finalNotificationLoad = notificationLoad;
3270 mUiOffloadThread.submit(() -> {
3272 mBarService.onPanelRevealed(clearNotificationEffects,
3273 finalNotificationLoad);
3274 } catch (RemoteException ex) {
3275 // Won't fail unless the world has ended.
3279 mUiOffloadThread.submit(() -> {
3281 mBarService.onPanelHidden();
3282 } catch (RemoteException ex) {
3283 // Won't fail unless the world has ended.
3290 private void logStateToEventlog() {
3291 boolean isShowing = mStatusBarKeyguardViewManager.isShowing();
3292 boolean isOccluded = mStatusBarKeyguardViewManager.isOccluded();
3293 boolean isBouncerShowing = mStatusBarKeyguardViewManager.isBouncerShowing();
3294 boolean isSecure = mUnlockMethodCache.isMethodSecure();
3295 boolean canSkipBouncer = mUnlockMethodCache.canSkipBouncer();
3296 int stateFingerprint = getLoggingFingerprint(mState,
3302 if (stateFingerprint != mLastLoggedStateFingerprint) {
3303 if (mStatusBarStateLog == null) {
3304 mStatusBarStateLog = new LogMaker(MetricsEvent.VIEW_UNKNOWN);
3306 mMetricsLogger.write(mStatusBarStateLog
3307 .setCategory(isBouncerShowing ? MetricsEvent.BOUNCER : MetricsEvent.LOCKSCREEN)
3308 .setType(isShowing ? MetricsEvent.TYPE_OPEN : MetricsEvent.TYPE_CLOSE)
3309 .setSubtype(isSecure ? 1 : 0));
3310 EventLogTags.writeSysuiStatusBarState(mState,
3313 isBouncerShowing ? 1 : 0,
3315 canSkipBouncer ? 1 : 0);
3316 mLastLoggedStateFingerprint = stateFingerprint;
3321 * Returns a fingerprint of fields logged to eventlog
3323 private static int getLoggingFingerprint(int statusBarState, boolean keyguardShowing,
3324 boolean keyguardOccluded, boolean bouncerShowing, boolean secure,
3325 boolean currentlyInsecure) {
3326 // Reserve 8 bits for statusBarState. We'll never go higher than
3327 // that, right? Riiiight.
3328 return (statusBarState & 0xFF)
3329 | ((keyguardShowing ? 1 : 0) << 8)
3330 | ((keyguardOccluded ? 1 : 0) << 9)
3331 | ((bouncerShowing ? 1 : 0) << 10)
3332 | ((secure ? 1 : 0) << 11)
3333 | ((currentlyInsecure ? 1 : 0) << 12);
3340 void postStartTracing() {
3341 mHandler.postDelayed(mStartTracing, 3000);
3345 android.os.Vibrator vib = (android.os.Vibrator)mContext.getSystemService(
3346 Context.VIBRATOR_SERVICE);
3347 vib.vibrate(250, VIBRATION_ATTRIBUTES);
3350 final Runnable mStartTracing = new Runnable() {
3354 SystemClock.sleep(250);
3355 Log.d(TAG, "startTracing");
3356 android.os.Debug.startMethodTracing("/data/statusbar-traces/trace");
3357 mHandler.postDelayed(mStopTracing, 10000);
3361 final Runnable mStopTracing = () -> {
3362 android.os.Debug.stopMethodTracing();
3363 Log.d(TAG, "stopTracing");
3368 public void postQSRunnableDismissingKeyguard(final Runnable runnable) {
3369 mHandler.post(() -> {
3370 mLeaveOpenOnKeyguardHide = true;
3371 executeRunnableDismissingKeyguard(() -> mHandler.post(runnable), null, false, false,
3377 public void postStartActivityDismissingKeyguard(final PendingIntent intent) {
3378 mHandler.post(() -> startPendingIntentDismissingKeyguard(intent));
3382 public void postStartActivityDismissingKeyguard(final Intent intent, int delay) {
3383 mHandler.postDelayed(() ->
3384 handleStartActivityDismissingKeyguard(intent, true /*onlyProvisioned*/), delay);
3387 private void handleStartActivityDismissingKeyguard(Intent intent, boolean onlyProvisioned) {
3388 startActivityDismissingKeyguard(intent, onlyProvisioned, true /* dismissShade */);
3391 public void destroy() {
3392 // Begin old BaseStatusBar.destroy().
3393 mContext.unregisterReceiver(mBannerActionBroadcastReceiver);
3394 mLockscreenUserManager.destroy();
3396 mNotificationListener.unregisterAsSystemService();
3397 } catch (RemoteException e) {
3400 mEntryManager.destroy();
3401 // End old BaseStatusBar.destroy().
3402 if (mStatusBarWindow != null) {
3403 mWindowManager.removeViewImmediate(mStatusBarWindow);
3404 mStatusBarWindow = null;
3406 if (mNavigationBarView != null) {
3407 mWindowManager.removeViewImmediate(mNavigationBarView);
3408 mNavigationBarView = null;
3410 mContext.unregisterReceiver(mBroadcastReceiver);
3411 mContext.unregisterReceiver(mDemoReceiver);
3412 mAssistManager.destroy();
3414 if (mQSPanel != null && mQSPanel.getHost() != null) {
3415 mQSPanel.getHost().destroy();
3417 Dependency.get(ActivityStarterDelegate.class).setActivityStarterImpl(null);
3418 mDeviceProvisionedController.removeCallback(mUserSetupObserver);
3419 Dependency.get(ConfigurationController.class).removeCallback(this);
3420 mZenController.removeCallback(this);
3421 mAppOpsListener.destroy();
3424 private boolean mDemoModeAllowed;
3425 private boolean mDemoMode;
3428 public void dispatchDemoCommand(String command, Bundle args) {
3429 if (!mDemoModeAllowed) {
3430 mDemoModeAllowed = Settings.Global.getInt(mContext.getContentResolver(),
3431 DEMO_MODE_ALLOWED, 0) != 0;
3433 if (!mDemoModeAllowed) return;
3434 if (command.equals(COMMAND_ENTER)) {
3436 } else if (command.equals(COMMAND_EXIT)) {
3439 } else if (!mDemoMode) {
3440 // automatically enter demo mode on first demo command
3441 dispatchDemoCommand(COMMAND_ENTER, new Bundle());
3443 boolean modeChange = command.equals(COMMAND_ENTER) || command.equals(COMMAND_EXIT);
3444 if ((modeChange || command.equals(COMMAND_VOLUME)) && mVolumeComponent != null) {
3445 mVolumeComponent.dispatchDemoCommand(command, args);
3447 if (modeChange || command.equals(COMMAND_CLOCK)) {
3448 dispatchDemoCommandToView(command, args, R.id.clock);
3450 if (modeChange || command.equals(COMMAND_BATTERY)) {
3451 mBatteryController.dispatchDemoCommand(command, args);
3453 if (modeChange || command.equals(COMMAND_STATUS)) {
3454 ((StatusBarIconControllerImpl) mIconController).dispatchDemoCommand(command, args);
3456 if (mNetworkController != null && (modeChange || command.equals(COMMAND_NETWORK))) {
3457 mNetworkController.dispatchDemoCommand(command, args);
3459 if (modeChange || command.equals(COMMAND_NOTIFICATIONS)) {
3460 View notifications = mStatusBarView == null ? null
3461 : mStatusBarView.findViewById(R.id.notification_icon_area);
3462 if (notifications != null) {
3463 String visible = args.getString("visible");
3464 int vis = mDemoMode && "false".equals(visible) ? View.INVISIBLE : View.VISIBLE;
3465 notifications.setVisibility(vis);
3468 if (command.equals(COMMAND_BARS)) {
3469 String mode = args.getString("mode");
3470 int barMode = "opaque".equals(mode) ? MODE_OPAQUE :
3471 "translucent".equals(mode) ? MODE_TRANSLUCENT :
3472 "semi-transparent".equals(mode) ? MODE_SEMI_TRANSPARENT :
3473 "transparent".equals(mode) ? MODE_TRANSPARENT :
3474 "warning".equals(mode) ? MODE_WARNING :
3476 if (barMode != -1) {
3477 boolean animate = true;
3478 if (mStatusBarView != null) {
3479 mStatusBarView.getBarTransitions().transitionTo(barMode, animate);
3481 if (mNavigationBar != null) {
3482 mNavigationBar.getBarTransitions().transitionTo(barMode, animate);
3486 if (modeChange || command.equals(COMMAND_OPERATOR)) {
3487 dispatchDemoCommandToView(command, args, R.id.operator_name);
3491 private void dispatchDemoCommandToView(String command, Bundle args, int id) {
3492 if (mStatusBarView == null) return;
3493 View v = mStatusBarView.findViewById(id);
3494 if (v instanceof DemoMode) {
3495 ((DemoMode)v).dispatchDemoCommand(command, args);
3500 * @return The {@link StatusBarState} the status bar is in.
3502 public int getBarState() {
3507 public boolean isPresenterFullyCollapsed() {
3508 return mNotificationPanel.isFullyCollapsed();
3511 public void showKeyguard() {
3512 mKeyguardRequested = true;
3513 mLeaveOpenOnKeyguardHide = false;
3514 mPendingRemoteInputView = null;
3516 mAssistManager.onLockscreenShown();
3519 public boolean hideKeyguard() {
3520 mKeyguardRequested = false;
3521 return updateIsKeyguard();
3525 * @return True if StatusBar state is FULLSCREEN_USER_SWITCHER.
3527 public boolean isFullScreenUserSwitcherState() {
3528 return mState == StatusBarState.FULLSCREEN_USER_SWITCHER;
3531 private boolean updateIsKeyguard() {
3532 boolean wakeAndUnlocking = mBiometricUnlockController.getMode()
3533 == BiometricUnlockController.MODE_WAKE_AND_UNLOCK;
3535 // For dozing, keyguard needs to be shown whenever the device is non-interactive. Otherwise
3536 // there's no surface we can show to the user. Note that the device goes fully interactive
3537 // late in the transition, so we also allow the device to start dozing once the screen has
3538 // turned off fully.
3539 boolean keyguardForDozing = mDozingRequested &&
3540 (!mDeviceInteractive || isGoingToSleep() && (isScreenFullyOff() || mIsKeyguard));
3541 boolean shouldBeKeyguard = (mKeyguardRequested || keyguardForDozing) && !wakeAndUnlocking;
3542 if (keyguardForDozing) {
3543 updatePanelExpansionForKeyguard();
3545 if (shouldBeKeyguard) {
3546 if (isGoingToSleep()
3547 && mScreenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_TURNING_OFF) {
3548 // Delay showing the keyguard until screen turned off.
3553 return hideKeyguardImpl();
3558 public void showKeyguardImpl() {
3560 if (mLaunchTransitionFadingAway) {
3561 mNotificationPanel.animate().cancel();
3562 onLaunchTransitionFadingEnded();
3564 mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
3565 if (mUserSwitcherController != null && mUserSwitcherController.useFullscreenUserSwitcher()) {
3566 setBarState(StatusBarState.FULLSCREEN_USER_SWITCHER);
3568 setBarState(StatusBarState.KEYGUARD);
3570 updateKeyguardState(false /* goingToFullShade */, false /* fromShadeLocked */);
3571 updatePanelExpansionForKeyguard();
3572 if (mDraggedDownRow != null) {
3573 mDraggedDownRow.setUserLocked(false);
3574 mDraggedDownRow.notifyHeightChanged(false /* needsAnimation */);
3575 mDraggedDownRow = null;
3579 private void updatePanelExpansionForKeyguard() {
3580 if (mState == StatusBarState.KEYGUARD && mBiometricUnlockController.getMode()
3581 != BiometricUnlockController.MODE_WAKE_AND_UNLOCK) {
3582 instantExpandNotificationsPanel();
3583 } else if (mState == StatusBarState.FULLSCREEN_USER_SWITCHER) {
3584 instantCollapseNotificationPanel();
3588 private void onLaunchTransitionFadingEnded() {
3589 mNotificationPanel.setAlpha(1.0f);
3590 mNotificationPanel.onAffordanceLaunchEnded();
3591 releaseGestureWakeLock();
3592 runLaunchTransitionEndRunnable();
3593 mLaunchTransitionFadingAway = false;
3594 updateMediaMetaData(true /* metaDataChanged */, true);
3597 public boolean isCollapsing() {
3598 return mNotificationPanel.isCollapsing() || mActivityLaunchAnimator.isAnimationPending();
3601 public void addPostCollapseAction(Runnable r) {
3602 mPostCollapseRunnables.add(r);
3605 public boolean isInLaunchTransition() {
3606 return mNotificationPanel.isLaunchTransitionRunning()
3607 || mNotificationPanel.isLaunchTransitionFinished();
3611 * Fades the content of the keyguard away after the launch transition is done.
3613 * @param beforeFading the runnable to be run when the circle is fully expanded and the fading
3615 * @param endRunnable the runnable to be run when the transition is done
3617 public void fadeKeyguardAfterLaunchTransition(final Runnable beforeFading,
3618 Runnable endRunnable) {
3619 mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
3620 mLaunchTransitionEndRunnable = endRunnable;
3621 Runnable hideRunnable = () -> {
3622 mLaunchTransitionFadingAway = true;
3623 if (beforeFading != null) {
3626 updateScrimController();
3627 updateMediaMetaData(false, true);
3628 mNotificationPanel.setAlpha(1);
3629 mStackScroller.setParentNotFullyVisible(true);
3630 mNotificationPanel.animate()
3632 .setStartDelay(FADE_KEYGUARD_START_DELAY)
3633 .setDuration(FADE_KEYGUARD_DURATION)
3635 .withEndAction(this::onLaunchTransitionFadingEnded);
3636 mCommandQueue.appTransitionStarting(SystemClock.uptimeMillis(),
3637 LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true);
3639 if (mNotificationPanel.isLaunchTransitionRunning()) {
3640 mNotificationPanel.setLaunchTransitionEndRunnable(hideRunnable);
3647 * Fades the content of the Keyguard while we are dozing and makes it invisible when finished
3650 public void fadeKeyguardWhilePulsing() {
3651 mNotificationPanel.notifyStartFading();
3652 mNotificationPanel.animate()
3655 .setDuration(FADE_KEYGUARD_DURATION_PULSING)
3656 .setInterpolator(Interpolators.ALPHA_OUT)
3657 .withEndAction(()-> {
3659 mStatusBarKeyguardViewManager.onKeyguardFadedAway();
3664 * Plays the animation when an activity that was occluding Keyguard goes away.
3666 public void animateKeyguardUnoccluding() {
3667 mNotificationPanel.setExpandedFraction(0f);
3668 animateExpandNotificationsPanel();
3672 * Starts the timeout when we try to start the affordances on Keyguard. We usually rely that
3673 * Keyguard goes away via fadeKeyguardAfterLaunchTransition, however, that might not happen
3674 * because the launched app crashed or something else went wrong.
3676 public void startLaunchTransitionTimeout() {
3677 mHandler.sendEmptyMessageDelayed(MSG_LAUNCH_TRANSITION_TIMEOUT,
3678 LAUNCH_TRANSITION_TIMEOUT_MS);
3681 private void onLaunchTransitionTimeout() {
3682 Log.w(TAG, "Launch transition: Timeout!");
3683 mNotificationPanel.onAffordanceLaunchEnded();
3684 releaseGestureWakeLock();
3685 mNotificationPanel.resetViews();
3688 private void runLaunchTransitionEndRunnable() {
3689 if (mLaunchTransitionEndRunnable != null) {
3690 Runnable r = mLaunchTransitionEndRunnable;
3692 // mLaunchTransitionEndRunnable might call showKeyguard, which would execute it again,
3693 // which would lead to infinite recursion. Protect against it.
3694 mLaunchTransitionEndRunnable = null;
3700 * @return true if we would like to stay in the shade, false if it should go away entirely
3702 public boolean hideKeyguardImpl() {
3703 mIsKeyguard = false;
3704 Trace.beginSection("StatusBar#hideKeyguard");
3705 boolean staying = mLeaveOpenOnKeyguardHide;
3706 setBarState(StatusBarState.SHADE);
3707 View viewToClick = null;
3708 if (mLeaveOpenOnKeyguardHide) {
3709 if (!mKeyguardRequested) {
3710 mLeaveOpenOnKeyguardHide = false;
3712 long delay = calculateGoingToFullShadeDelay();
3713 mNotificationPanel.animateToFullShade(delay);
3714 if (mDraggedDownRow != null) {
3715 mDraggedDownRow.setUserLocked(false);
3716 mDraggedDownRow = null;
3718 if (!mKeyguardRequested) {
3719 viewToClick = mPendingRemoteInputView;
3720 mPendingRemoteInputView = null;
3723 // Disable layout transitions in navbar for this transition because the load is just
3724 // too heavy for the CPU and GPU on any device.
3725 if (mNavigationBar != null) {
3726 mNavigationBar.disableAnimationsDuringHide(delay);
3728 } else if (!mNotificationPanel.isCollapsing()) {
3729 instantCollapseNotificationPanel();
3731 updateKeyguardState(staying, false /* fromShadeLocked */);
3733 if (viewToClick != null && viewToClick.isAttachedToWindow()) {
3734 viewToClick.callOnClick();
3737 // Keyguard state has changed, but QS is not listening anymore. Make sure to update the tile
3738 // visibilities so next time we open the panel we know the correct height already.
3739 if (mQSPanel != null) {
3740 mQSPanel.refreshAllTiles();
3742 mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
3743 releaseGestureWakeLock();
3744 mNotificationPanel.onAffordanceLaunchEnded();
3745 mNotificationPanel.animate().cancel();
3746 mNotificationPanel.setAlpha(1f);
3751 private void releaseGestureWakeLock() {
3752 if (mGestureWakeLock.isHeld()) {
3753 mGestureWakeLock.release();
3757 public long calculateGoingToFullShadeDelay() {
3758 return mKeyguardFadingAwayDelay + mKeyguardFadingAwayDuration;
3762 * Notifies the status bar that Keyguard is going away very soon.
3764 public void keyguardGoingAway() {
3766 // Treat Keyguard exit animation as an app transition to achieve nice transition for status
3768 mKeyguardMonitor.notifyKeyguardGoingAway(true);
3769 mCommandQueue.appTransitionPending(true);
3773 * Notifies the status bar the Keyguard is fading away with the specified timings.
3775 * @param startTime the start time of the animations in uptime millis
3776 * @param delay the precalculated animation delay in milliseconds
3777 * @param fadeoutDuration the duration of the exit animation, in milliseconds
3779 public void setKeyguardFadingAway(long startTime, long delay, long fadeoutDuration) {
3780 mKeyguardFadingAway = true;
3781 mKeyguardFadingAwayDelay = delay;
3782 mKeyguardFadingAwayDuration = fadeoutDuration;
3783 mCommandQueue.appTransitionStarting(startTime + fadeoutDuration
3784 - LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION,
3785 LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true);
3786 recomputeDisableFlags(fadeoutDuration > 0 /* animate */);
3787 mCommandQueue.appTransitionStarting(
3788 startTime - LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION,
3789 LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true);
3790 mKeyguardMonitor.notifyKeyguardFadingAway(delay, fadeoutDuration);
3793 public boolean isKeyguardFadingAway() {
3794 return mKeyguardFadingAway;
3798 * Notifies that the Keyguard fading away animation is done.
3800 public void finishKeyguardFadingAway() {
3801 mKeyguardFadingAway = false;
3802 mKeyguardMonitor.notifyKeyguardDoneFading();
3803 mScrimController.setExpansionAffectsAlpha(true);
3806 // TODO: Move this to NotificationLockscreenUserManager.
3807 private void updatePublicMode() {
3808 final boolean showingKeyguard = mStatusBarKeyguardViewManager.isShowing();
3809 final boolean devicePublic = showingKeyguard
3810 && mStatusBarKeyguardViewManager.isSecure(
3811 mLockscreenUserManager.getCurrentUserId());
3813 // Look for public mode users. Users are considered public in either case of:
3814 // - device keyguard is shown in secure mode;
3815 // - profile is locked with a work challenge.
3816 SparseArray<UserInfo> currentProfiles = mLockscreenUserManager.getCurrentProfiles();
3817 for (int i = currentProfiles.size() - 1; i >= 0; i--) {
3818 final int userId = currentProfiles.valueAt(i).id;
3819 boolean isProfilePublic = devicePublic;
3820 if (!devicePublic && userId != mLockscreenUserManager.getCurrentUserId()) {
3821 // We can't rely on KeyguardManager#isDeviceLocked() for unified profile challenge
3822 // due to a race condition where this code could be called before
3823 // TrustManagerService updates its internal records, resulting in an incorrect
3824 // state being cached in mLockscreenPublicMode. (b/35951989)
3825 if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)
3826 && mStatusBarKeyguardViewManager.isSecure(userId)) {
3827 isProfilePublic = mKeyguardManager.isDeviceLocked(userId);
3830 mLockscreenUserManager.setLockscreenPublicMode(isProfilePublic, userId);
3834 protected void updateKeyguardState(boolean goingToFullShade, boolean fromShadeLocked) {
3835 Trace.beginSection("StatusBar#updateKeyguardState");
3836 if (mState == StatusBarState.KEYGUARD) {
3837 mKeyguardIndicationController.setVisible(true);
3838 mNotificationPanel.resetViews();
3839 if (mKeyguardUserSwitcher != null) {
3840 mKeyguardUserSwitcher.setKeyguard(true, fromShadeLocked);
3842 if (mStatusBarView != null) mStatusBarView.removePendingHideExpandedRunnables();
3843 if (mAmbientIndicationContainer != null) {
3844 mAmbientIndicationContainer.setVisibility(View.VISIBLE);
3847 mKeyguardIndicationController.setVisible(false);
3848 if (mKeyguardUserSwitcher != null) {
3849 mKeyguardUserSwitcher.setKeyguard(false,
3851 mState == StatusBarState.SHADE_LOCKED ||
3854 if (mAmbientIndicationContainer != null) {
3855 mAmbientIndicationContainer.setVisibility(View.INVISIBLE);
3858 mNotificationPanel.setBarState(mState, mKeyguardFadingAway, goingToFullShade);
3860 updateDozingState();
3862 updateStackScrollerState(goingToFullShade, fromShadeLocked);
3863 mEntryManager.updateNotifications();
3865 updateScrimController();
3866 updateMediaMetaData(false, mState != StatusBarState.KEYGUARD);
3867 mKeyguardMonitor.notifyKeyguardState(mStatusBarKeyguardViewManager.isShowing(),
3868 mUnlockMethodCache.isMethodSecure(),
3869 mStatusBarKeyguardViewManager.isOccluded());
3874 * Switches theme from light to dark and vice-versa.
3876 protected void updateTheme() {
3877 final boolean inflated = mStackScroller != null && mStatusBarWindowManager != null;
3879 // Lock wallpaper defines the color of the majority of the views, hence we'll use it
3880 // to set our default theme.
3881 final boolean lockDarkText = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK, true
3882 /* ignoreVisibility */).supportsDarkText();
3883 final int themeResId = lockDarkText ? R.style.Theme_SystemUI_Light : R.style.Theme_SystemUI;
3884 if (mContext.getThemeResId() != themeResId) {
3885 mContext.setTheme(themeResId);
3893 if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
3894 which = WallpaperManager.FLAG_LOCK;
3896 which = WallpaperManager.FLAG_SYSTEM;
3898 final boolean useDarkText = mColorExtractor.getColors(which,
3899 true /* ignoreVisibility */).supportsDarkText();
3900 mStackScroller.updateDecorViews(useDarkText);
3902 // Make sure we have the correct navbar/statusbar colors.
3903 mStatusBarWindowManager.setKeyguardDark(useDarkText);
3907 private void updateDozingState() {
3908 Trace.traceCounter(Trace.TRACE_TAG_APP, "dozing", mDozing ? 1 : 0);
3909 Trace.beginSection("StatusBar#updateDozingState");
3911 boolean sleepingFromKeyguard =
3912 mStatusBarKeyguardViewManager.isGoingToSleepVisibleNotOccluded();
3913 boolean animate = (!mDozing && mDozeServiceHost.shouldAnimateWakeup())
3914 || (mDozing && mDozeServiceHost.shouldAnimateScreenOff() && sleepingFromKeyguard);
3916 mStackScroller.setDark(mDozing, animate, mWakeUpTouchLocation);
3917 mDozeScrimController.setDozing(mDozing);
3918 mKeyguardIndicationController.setDozing(mDozing);
3919 mNotificationPanel.setDozing(mDozing, animate);
3920 updateQsExpansionEnabled();
3924 public void updateStackScrollerState(boolean goingToFullShade, boolean fromShadeLocked) {
3925 if (mStackScroller == null) return;
3926 boolean onKeyguard = mState == StatusBarState.KEYGUARD;
3927 boolean publicMode = mLockscreenUserManager.isAnyProfilePublicMode();
3928 if (mHeadsUpAppearanceController != null) {
3929 mHeadsUpAppearanceController.setPublicMode(publicMode);
3931 mStackScroller.setHideSensitive(publicMode, goingToFullShade);
3932 mStackScroller.setDimmed(onKeyguard, fromShadeLocked /* animate */);
3933 mStackScroller.setExpandingEnabled(!onKeyguard);
3934 ActivatableNotificationView activatedChild = mStackScroller.getActivatedChild();
3935 mStackScroller.setActivatedChild(null);
3936 if (activatedChild != null) {
3937 activatedChild.makeInactive(false /* animate */);
3941 public void userActivity() {
3942 if (mState == StatusBarState.KEYGUARD) {
3943 mKeyguardViewMediatorCallback.userActivity();
3947 public boolean interceptMediaKey(KeyEvent event) {
3948 return mState == StatusBarState.KEYGUARD
3949 && mStatusBarKeyguardViewManager.interceptMediaKey(event);
3952 protected boolean shouldUnlockOnMenuPressed() {
3953 return mDeviceInteractive && mState != StatusBarState.SHADE
3954 && mStatusBarKeyguardViewManager.shouldDismissOnMenuPressed();
3957 public boolean onMenuPressed() {
3958 if (shouldUnlockOnMenuPressed()) {
3959 animateCollapsePanels(
3960 CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL /* flags */, true /* force */);
3966 public void endAffordanceLaunch() {
3967 releaseGestureWakeLock();
3968 mNotificationPanel.onAffordanceLaunchEnded();
3971 public boolean onBackPressed() {
3972 boolean isScrimmedBouncer = mScrimController.getState() == ScrimState.BOUNCER_SCRIMMED;
3973 if (mStatusBarKeyguardViewManager.onBackPressed(isScrimmedBouncer /* hideImmediately */)) {
3974 if (!isScrimmedBouncer) {
3975 mNotificationPanel.expandWithoutQs();
3979 if (mNotificationPanel.isQsExpanded()) {
3980 if (mNotificationPanel.isQsDetailShowing()) {
3981 mNotificationPanel.closeQsDetail();
3983 mNotificationPanel.animateCloseQs();
3987 if (mState != StatusBarState.KEYGUARD && mState != StatusBarState.SHADE_LOCKED) {
3988 animateCollapsePanels();
3991 if (mKeyguardUserSwitcher != null && mKeyguardUserSwitcher.hideIfNotSimple(true)) {
3997 public boolean onSpacePressed() {
3998 if (mDeviceInteractive && mState != StatusBarState.SHADE) {
3999 animateCollapsePanels(
4000 CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL /* flags */, true /* force */);
4006 private void showBouncerIfKeyguard() {
4007 if ((mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)
4008 && !mKeyguardViewMediator.isHiding()) {
4009 showBouncer(true /* scrimmed */);
4013 protected void showBouncer(boolean scrimmed) {
4014 mStatusBarKeyguardViewManager.showBouncer(scrimmed);
4017 private void instantExpandNotificationsPanel() {
4018 // Make our window larger and the panel expanded.
4019 makeExpandedVisible(true);
4020 mNotificationPanel.expand(false /* animate */);
4021 recomputeDisableFlags(false /* animate */);
4024 private void instantCollapseNotificationPanel() {
4025 mNotificationPanel.instantCollapse();
4026 runPostCollapseRunnables();
4030 public void onActivated(ActivatableNotificationView view) {
4031 onActivated((View) view);
4032 mStackScroller.setActivatedChild(view);
4035 public void onActivated(View view) {
4036 mLockscreenGestureLogger.write(
4037 MetricsEvent.ACTION_LS_NOTE,
4038 0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */);
4039 mKeyguardIndicationController.showTransientIndication(R.string.notification_tap_again);
4040 ActivatableNotificationView previousView = mStackScroller.getActivatedChild();
4041 if (previousView != null) {
4042 previousView.makeInactive(true /* animate */);
4047 * @param state The {@link StatusBarState} to set.
4049 public void setBarState(int state) {
4050 // If we're visible and switched to SHADE_LOCKED (the user dragged
4051 // down on the lockscreen), clear notification LED, vibration,
4053 // Other transitions are covered in handleVisibleToUserChanged().
4054 if (state != mState && mVisible && (state == StatusBarState.SHADE_LOCKED
4055 || (state == StatusBarState.SHADE && isGoingToNotificationShade()))) {
4056 clearNotificationEffects();
4058 if (state == StatusBarState.KEYGUARD) {
4059 mRemoteInputManager.removeRemoteInputEntriesKeptUntilCollapsed();
4060 maybeEscalateHeadsUp();
4063 mGroupManager.setStatusBarState(state);
4064 mHeadsUpManager.setStatusBarState(state);
4065 mFalsingManager.setStatusBarState(state);
4066 mStatusBarWindowManager.setStatusBarState(state);
4067 mStackScroller.setStatusBarState(state);
4068 updateReportRejectedTouchVisibility();
4072 mNotificationShelf.setStatusBarState(state);
4076 public void onActivationReset(ActivatableNotificationView view) {
4077 if (view == mStackScroller.getActivatedChild()) {
4078 mStackScroller.setActivatedChild(null);
4079 onActivationReset((View)view);
4083 public void onActivationReset(View view) {
4084 mKeyguardIndicationController.hideTransientIndication();
4087 public void onTrackingStarted() {
4088 runPostCollapseRunnables();
4091 public void onClosingFinished() {
4092 runPostCollapseRunnables();
4093 if (!isPresenterFullyCollapsed()) {
4094 // if we set it not to be focusable when collapsing, we have to undo it when we aborted
4096 mStatusBarWindowManager.setStatusBarFocusable(true);
4100 public void onUnlockHintStarted() {
4101 mFalsingManager.onUnlockHintStarted();
4102 mKeyguardIndicationController.showTransientIndication(R.string.keyguard_unlock);
4105 public void onHintFinished() {
4106 // Delay the reset a bit so the user can read the text.
4107 mKeyguardIndicationController.hideTransientIndicationDelayed(HINT_RESET_DELAY_MS);
4110 public void onCameraHintStarted() {
4111 mFalsingManager.onCameraHintStarted();
4112 mKeyguardIndicationController.showTransientIndication(R.string.camera_hint);
4115 public void onVoiceAssistHintStarted() {
4116 mFalsingManager.onLeftAffordanceHintStarted();
4117 mKeyguardIndicationController.showTransientIndication(R.string.voice_hint);
4120 public void onPhoneHintStarted() {
4121 mFalsingManager.onLeftAffordanceHintStarted();
4122 mKeyguardIndicationController.showTransientIndication(R.string.phone_hint);
4125 public void onTrackingStopped(boolean expand) {
4126 if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
4127 if (!expand && !mUnlockMethodCache.canSkipBouncer()) {
4128 showBouncer(false /* scrimmed */);
4134 public int getMaxNotificationsWhileLocked(boolean recompute) {
4136 mMaxKeyguardNotifications = Math.max(1,
4137 mNotificationPanel.computeMaxKeyguardNotifications(
4138 mMaxAllowedKeyguardNotifications));
4139 return mMaxKeyguardNotifications;
4141 return mMaxKeyguardNotifications;
4144 public int getMaxNotificationsWhileLocked() {
4145 return getMaxNotificationsWhileLocked(false /* recompute */);
4148 // TODO: Figure out way to remove these.
4149 public NavigationBarView getNavigationBarView() {
4150 return (mNavigationBar != null ? (NavigationBarView) mNavigationBar.getView() : null);
4153 public View getNavigationBarWindow() {
4154 return mNavigationBarView;
4158 * TODO: Remove this method. Views should not be passed forward. Will cause theme issues.
4159 * @return bottom area view
4161 public KeyguardBottomAreaView getKeyguardBottomAreaView() {
4162 return mNotificationPanel.getKeyguardBottomAreaView();
4165 // ---------------------- DragDownHelper.OnDragDownListener ------------------------------------
4168 /* Only ever called as a consequence of a lockscreen expansion gesture. */
4170 public boolean onDraggedDown(View startingChild, int dragLengthY) {
4171 if (mState == StatusBarState.KEYGUARD
4172 && hasActiveNotifications() && (!isDozing() || isPulsing())) {
4173 mLockscreenGestureLogger.write(
4174 MetricsEvent.ACTION_LS_SHADE,
4175 (int) (dragLengthY / mDisplayMetrics.density),
4176 0 /* velocityDp - N/A */);
4178 // We have notifications, go to locked shade.
4179 goToLockedShade(startingChild);
4180 if (startingChild instanceof ExpandableNotificationRow) {
4181 ExpandableNotificationRow row = (ExpandableNotificationRow) startingChild;
4182 row.onExpandedByGesture(true /* drag down is always an open */);
4192 public void onDragDownReset() {
4193 mStackScroller.setDimmed(true /* dimmed */, true /* animated */);
4194 mStackScroller.resetScrollPosition();
4195 mStackScroller.resetCheckSnoozeLeavebehind();
4199 public void onCrossedThreshold(boolean above) {
4200 mStackScroller.setDimmed(!above /* dimmed */, true /* animate */);
4204 public void onTouchSlopExceeded() {
4205 mStackScroller.cancelLongPress();
4206 mStackScroller.checkSnoozeLeavebehind();
4210 public void setEmptyDragAmount(float amount) {
4211 mNotificationPanel.setEmptyDragAmount(amount);
4215 public boolean isFalsingCheckNeeded() {
4216 return mState == StatusBarState.KEYGUARD;
4220 * If secure with redaction: Show bouncer, go to unlocked shade.
4222 * <p>If secure without redaction or no security: Go to {@link StatusBarState#SHADE_LOCKED}.</p>
4224 * @param expandView The view to expand after going to the shade.
4226 public void goToLockedShade(View expandView) {
4227 if ((mDisabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0) {
4231 int userId = mLockscreenUserManager.getCurrentUserId();
4232 ExpandableNotificationRow row = null;
4233 if (expandView instanceof ExpandableNotificationRow) {
4234 row = (ExpandableNotificationRow) expandView;
4235 row.setUserExpanded(true /* userExpanded */, true /* allowChildExpansion */);
4236 // Indicate that the group expansion is changing at this time -- this way the group
4237 // and children backgrounds / divider animations will look correct.
4238 row.setGroupExpansionChanging(true);
4239 if (row.getStatusBarNotification() != null) {
4240 userId = row.getStatusBarNotification().getUserId();
4243 boolean fullShadeNeedsBouncer = !mLockscreenUserManager.
4244 userAllowsPrivateNotificationsInPublic(mLockscreenUserManager.getCurrentUserId())
4245 || !mLockscreenUserManager.shouldShowLockscreenNotifications()
4246 || mFalsingManager.shouldEnforceBouncer();
4247 if (mLockscreenUserManager.isLockscreenPublicMode(userId) && fullShadeNeedsBouncer) {
4248 mLeaveOpenOnKeyguardHide = true;
4249 showBouncerIfKeyguard();
4250 mDraggedDownRow = row;
4251 mPendingRemoteInputView = null;
4253 mNotificationPanel.animateToFullShade(0 /* delay */);
4254 setBarState(StatusBarState.SHADE_LOCKED);
4255 updateKeyguardState(false /* goingToFullShade */, false /* fromShadeLocked */);
4259 public void onLockedNotificationImportanceChange(OnDismissAction dismissAction) {
4260 mLeaveOpenOnKeyguardHide = true;
4261 dismissKeyguardThenExecute(dismissAction, true /* afterKeyguardGone */);
4265 public void onLockedRemoteInput(ExpandableNotificationRow row, View clicked) {
4266 mLeaveOpenOnKeyguardHide = true;
4267 showBouncer(true /* scrimmed */);
4268 mPendingRemoteInputView = clicked;
4272 public void onMakeExpandedVisibleForRemoteInput(ExpandableNotificationRow row,
4274 if (isKeyguardShowing()) {
4275 onLockedRemoteInput(row, clickedView);
4277 row.setUserExpanded(true);
4278 row.getPrivateLayout().setOnExpandedVisibleListener(clickedView::performClick);
4283 public boolean shouldHandleRemoteInput(View view, PendingIntent pendingIntent) {
4284 // Skip remote input as doing so will expand the notification shade.
4285 return (mDisabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0;
4289 public boolean handleRemoteViewClick(View view, PendingIntent pendingIntent,
4290 Intent fillInIntent, NotificationRemoteInputManager.ClickHandler defaultHandler) {
4291 final boolean isActivity = pendingIntent.isActivity();
4293 final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity(
4294 mContext, pendingIntent.getIntent(), mLockscreenUserManager.getCurrentUserId());
4295 dismissKeyguardThenExecute(() -> {
4297 ActivityManager.getService().resumeAppSwitches();
4298 } catch (RemoteException e) {
4301 boolean handled = defaultHandler.handleClick();
4303 // close the shade if it was open
4304 if (handled && !mNotificationPanel.isFullyCollapsed()) {
4305 animateCollapsePanels(
4306 CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */);
4307 visibilityChanged(false);
4308 mAssistManager.hideAssist();
4310 // Wait for activity start.
4316 }, afterKeyguardGone);
4319 return defaultHandler.handleClick();
4323 protected boolean startWorkChallengeIfNecessary(int userId, IntentSender intendSender,
4324 String notificationKey) {
4325 // Clear pending remote view, as we do not want to trigger pending remote input view when
4326 // it's called by other code
4327 mPendingWorkRemoteInputView = null;
4328 // Begin old BaseStatusBar.startWorkChallengeIfNecessary.
4329 final Intent newIntent = mKeyguardManager.createConfirmDeviceCredentialIntent(null,
4331 if (newIntent == null) {
4334 final Intent callBackIntent = new Intent(NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION);
4335 callBackIntent.putExtra(Intent.EXTRA_INTENT, intendSender);
4336 callBackIntent.putExtra(Intent.EXTRA_INDEX, notificationKey);
4337 callBackIntent.setPackage(mContext.getPackageName());
4339 PendingIntent callBackPendingIntent = PendingIntent.getBroadcast(
4343 PendingIntent.FLAG_CANCEL_CURRENT |
4344 PendingIntent.FLAG_ONE_SHOT |
4345 PendingIntent.FLAG_IMMUTABLE);
4347 Intent.EXTRA_INTENT,
4348 callBackPendingIntent.getIntentSender());
4350 ActivityManager.getService().startConfirmDeviceCredentialIntent(newIntent,
4352 } catch (RemoteException ex) {
4356 // End old BaseStatusBar.startWorkChallengeIfNecessary.
4360 public void onLockedWorkRemoteInput(int userId, ExpandableNotificationRow row,
4362 // Collapse notification and show work challenge
4363 animateCollapsePanels();
4364 startWorkChallengeIfNecessary(userId, null, null);
4365 // Add pending remote input view after starting work challenge, as starting work challenge
4366 // will clear all previous pending review view
4367 mPendingWorkRemoteInputView = clicked;
4371 public void onWorkChallengeChanged() {
4373 mEntryManager.updateNotifications();
4374 if (mPendingWorkRemoteInputView != null
4375 && !mLockscreenUserManager.isAnyProfilePublicMode()) {
4376 // Expand notification panel and the notification row, then click on remote input view
4377 final Runnable clickPendingViewRunnable = () -> {
4378 final View pendingWorkRemoteInputView = mPendingWorkRemoteInputView;
4379 if (pendingWorkRemoteInputView == null) {
4383 // Climb up the hierarchy until we get to the container for this row.
4384 ViewParent p = pendingWorkRemoteInputView.getParent();
4385 while (!(p instanceof ExpandableNotificationRow)) {
4392 final ExpandableNotificationRow row = (ExpandableNotificationRow) p;
4393 ViewParent viewParent = row.getParent();
4394 if (viewParent instanceof NotificationStackScrollLayout) {
4395 final NotificationStackScrollLayout scrollLayout =
4396 (NotificationStackScrollLayout) viewParent;
4397 row.makeActionsVisibile();
4399 final Runnable finishScrollingCallback = () -> {
4400 mPendingWorkRemoteInputView.callOnClick();
4401 mPendingWorkRemoteInputView = null;
4402 scrollLayout.setFinishScrollingCallback(null);
4404 if (scrollLayout.scrollTo(row)) {
4405 // It scrolls! So call it when it's finished.
4406 scrollLayout.setFinishScrollingCallback(finishScrollingCallback);
4408 // It does not scroll, so call it now!
4409 finishScrollingCallback.run();
4414 mNotificationPanel.getViewTreeObserver().addOnGlobalLayoutListener(
4415 new ViewTreeObserver.OnGlobalLayoutListener() {
4417 public void onGlobalLayout() {
4418 if (mNotificationPanel.mStatusBar.getStatusBarWindow()
4419 .getHeight() != mNotificationPanel.mStatusBar
4420 .getStatusBarHeight()) {
4421 mNotificationPanel.getViewTreeObserver()
4422 .removeOnGlobalLayoutListener(this);
4423 mNotificationPanel.post(clickPendingViewRunnable);
4427 instantExpandNotificationsPanel();
4432 public void onExpandClicked(Entry clickedEntry, boolean nowExpanded) {
4433 mHeadsUpManager.setExpanded(clickedEntry, nowExpanded);
4434 if (mState == StatusBarState.KEYGUARD && nowExpanded) {
4435 goToLockedShade(clickedEntry.row);
4440 * Goes back to the keyguard after hanging around in {@link StatusBarState#SHADE_LOCKED}.
4442 public void goToKeyguard() {
4443 if (mState == StatusBarState.SHADE_LOCKED) {
4444 mStackScroller.onGoToKeyguard();
4445 setBarState(StatusBarState.KEYGUARD);
4446 updateKeyguardState(false /* goingToFullShade */, true /* fromShadeLocked*/);
4450 public long getKeyguardFadingAwayDelay() {
4451 return mKeyguardFadingAwayDelay;
4454 public long getKeyguardFadingAwayDuration() {
4455 return mKeyguardFadingAwayDuration;
4458 public void setBouncerShowing(boolean bouncerShowing) {
4459 mBouncerShowing = bouncerShowing;
4460 if (mStatusBarView != null) mStatusBarView.setBouncerShowing(bouncerShowing);
4461 updateHideIconsForBouncer(true /* animate */);
4462 recomputeDisableFlags(true /* animate */);
4463 updateScrimController();
4467 * Collapses the notification shade if it is tracking or expanded.
4469 public void collapseShade() {
4470 if (mNotificationPanel.isTracking()) {
4471 mStatusBarWindow.cancelCurrentTouch();
4473 if (mPanelExpanded && mState == StatusBarState.SHADE) {
4474 animateCollapsePanels();
4478 final WakefulnessLifecycle.Observer mWakefulnessObserver = new WakefulnessLifecycle.Observer() {
4480 public void onFinishedGoingToSleep() {
4481 mNotificationPanel.onAffordanceLaunchEnded();
4482 releaseGestureWakeLock();
4483 mLaunchCameraOnScreenTurningOn = false;
4484 mDeviceInteractive = false;
4485 mWakeUpComingFromTouch = false;
4486 mWakeUpTouchLocation = null;
4487 mStackScroller.setAnimationsEnabled(false);
4488 mVisualStabilityManager.setScreenOn(false);
4489 updateVisibleToUser();
4491 // We need to disable touch events because these might
4492 // collapse the panel after we expanded it, and thus we would end up with a blank
4494 mNotificationPanel.setTouchDisabled(true);
4495 mStatusBarWindow.cancelCurrentTouch();
4496 if (mLaunchCameraOnFinishedGoingToSleep) {
4497 mLaunchCameraOnFinishedGoingToSleep = false;
4499 // This gets executed before we will show Keyguard, so post it in order that the state
4501 mHandler.post(() -> onCameraLaunchGestureDetected(mLastCameraLaunchSource));
4507 public void onStartedGoingToSleep() {
4508 notifyHeadsUpGoingToSleep();
4509 dismissVolumeDialog();
4513 public void onStartedWakingUp() {
4514 mDeviceInteractive = true;
4515 mStackScroller.setAnimationsEnabled(true);
4516 mVisualStabilityManager.setScreenOn(true);
4517 mNotificationPanel.setTouchDisabled(false);
4518 mDozeServiceHost.stopDozing();
4519 updateVisibleToUser();
4521 updateScrimController();
4525 final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() {
4527 public void onScreenTurningOn() {
4528 mFalsingManager.onScreenTurningOn();
4529 mNotificationPanel.onScreenTurningOn();
4531 if (mLaunchCameraOnScreenTurningOn) {
4532 mNotificationPanel.launchCamera(false, mLastCameraLaunchSource);
4533 mLaunchCameraOnScreenTurningOn = false;
4536 updateScrimController();
4540 public void onScreenTurnedOn() {
4541 mScrimController.onScreenTurnedOn();
4545 public void onScreenTurnedOff() {
4546 mFalsingManager.onScreenOff();
4547 mScrimController.onScreenTurnedOff();
4548 // If we pulse in from AOD, we turn the screen off first. However, updatingIsKeyguard
4549 // in that case destroys the HeadsUpManager state, so don't do it in that case.
4556 public int getWakefulnessState() {
4557 return mWakefulnessLifecycle.getWakefulness();
4560 private void vibrateForCameraGesture() {
4561 // Make sure to pass -1 for repeat so VibratorService doesn't stop us when going to sleep.
4562 mVibrator.vibrate(mCameraLaunchGestureVibePattern, -1 /* repeat */);
4566 * @return true if the screen is currently fully off, i.e. has finished turning off and has
4567 * since not started turning on.
4569 public boolean isScreenFullyOff() {
4570 return mScreenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_OFF;
4574 public void showScreenPinningRequest(int taskId) {
4575 if (mKeyguardMonitor.isShowing()) {
4576 // Don't allow apps to trigger this from keyguard.
4579 // Show screen pinning request, since this comes from an app, show 'no thanks', button.
4580 showScreenPinningRequest(taskId, true);
4583 public void showScreenPinningRequest(int taskId, boolean allowCancel) {
4584 mScreenPinningRequest.showPrompt(taskId, allowCancel);
4587 public boolean hasActiveNotifications() {
4588 return !mEntryManager.getNotificationData().getActiveNotifications().isEmpty();
4592 public void wakeUpIfDozing(long time, View where) {
4594 PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
4595 pm.wakeUp(time, "com.android.systemui:NODOZE");
4596 mWakeUpComingFromTouch = true;
4597 where.getLocationInWindow(mTmpInt2);
4598 mWakeUpTouchLocation = new PointF(mTmpInt2[0] + where.getWidth() / 2,
4599 mTmpInt2[1] + where.getHeight() / 2);
4600 mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested();
4601 mFalsingManager.onScreenOnFromTouch();
4606 public boolean isDeviceLocked(int userId) {
4607 return mKeyguardManager.isDeviceLocked(userId);
4611 public void appTransitionCancelled() {
4612 EventBus.getDefault().send(new AppTransitionFinishedEvent());
4616 public void appTransitionFinished() {
4617 EventBus.getDefault().send(new AppTransitionFinishedEvent());
4621 public void onCameraLaunchGestureDetected(int source) {
4622 mLastCameraLaunchSource = source;
4623 if (isGoingToSleep()) {
4624 if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Finish going to sleep before launching camera");
4625 mLaunchCameraOnFinishedGoingToSleep = true;
4628 if (!mNotificationPanel.canCameraGestureBeLaunched(
4629 mStatusBarKeyguardViewManager.isShowing() && mExpandedVisible)) {
4630 if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Can't launch camera right now, mExpandedVisible: " +
4634 if (!mDeviceInteractive) {
4635 PowerManager pm = mContext.getSystemService(PowerManager.class);
4636 pm.wakeUp(SystemClock.uptimeMillis(), "com.android.systemui:CAMERA_GESTURE");
4637 mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested();
4639 vibrateForCameraGesture();
4640 if (!mStatusBarKeyguardViewManager.isShowing()) {
4641 startActivityDismissingKeyguard(KeyguardBottomAreaView.INSECURE_CAMERA_INTENT,
4642 false /* onlyProvisioned */, true /* dismissShade */,
4643 true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */, 0);
4645 if (!mDeviceInteractive) {
4646 // Avoid flickering of the scrim when we instant launch the camera and the bouncer
4648 mGestureWakeLock.acquire(LAUNCH_TRANSITION_TIMEOUT_MS + 1000L);
4650 if (isScreenTurningOnOrOn()) {
4651 if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Launching camera");
4652 if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
4653 mStatusBarKeyguardViewManager.reset(true /* hide */);
4655 mNotificationPanel.launchCamera(mDeviceInteractive /* animate */, source);
4656 updateScrimController();
4658 // We need to defer the camera launch until the screen comes on, since otherwise
4659 // we will dismiss us too early since we are waiting on an activity to be drawn and
4660 // incorrectly get notified because of the screen on event (which resumes and pauses
4662 if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Deferring until screen turns on");
4663 mLaunchCameraOnScreenTurningOn = true;
4668 boolean isCameraAllowedByAdmin() {
4669 if (mDevicePolicyManager.getCameraDisabled(null,
4670 mLockscreenUserManager.getCurrentUserId())) {
4672 } else if (mStatusBarKeyguardViewManager == null ||
4673 (isKeyguardShowing() && isKeyguardSecure())) {
4674 // Check if the admin has disabled the camera specifically for the keyguard
4675 return (mDevicePolicyManager.
4676 getKeyguardDisabledFeatures(null, mLockscreenUserManager.getCurrentUserId())
4677 & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) == 0;
4683 private boolean isGoingToSleep() {
4684 return mWakefulnessLifecycle.getWakefulness()
4685 == WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP;
4688 private boolean isScreenTurningOnOrOn() {
4689 return mScreenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_TURNING_ON
4690 || mScreenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_ON;
4693 public void notifyBiometricAuthModeChanged() {
4695 updateScrimController();
4698 private void updateDozing() {
4699 Trace.beginSection("StatusBar#updateDozing");
4700 // When in wake-and-unlock while pulsing, keep dozing state until fully unlocked.
4701 boolean dozing = mDozingRequested && mState == StatusBarState.KEYGUARD
4702 || mBiometricUnlockController.getMode()
4703 == BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING;
4704 // When in wake-and-unlock we may not have received a change to mState
4705 // but we still should not be dozing, manually set to false.
4706 if (mBiometricUnlockController.getMode() ==
4707 mBiometricUnlockController.MODE_WAKE_AND_UNLOCK) {
4710 if (mDozing != dozing) {
4712 mKeyguardViewMediator.setAodShowing(mDozing);
4713 mStatusBarWindowManager.setDozing(mDozing);
4714 mStatusBarKeyguardViewManager.setDozing(mDozing);
4715 if (mAmbientIndicationContainer instanceof DozeReceiver) {
4716 ((DozeReceiver) mAmbientIndicationContainer).setDozing(mDozing);
4718 mEntryManager.updateNotifications();
4719 updateDozingState();
4720 updateReportRejectedTouchVisibility();
4726 void updateScrimController() {
4727 Trace.beginSection("StatusBar#updateScrimController");
4729 // We don't want to end up in KEYGUARD state when we're unlocking with
4730 // fingerprint from doze. We should cross fade directly from black.
4731 boolean wakeAndUnlocking = mBiometricUnlockController.isWakeAndUnlock();
4733 // Do not animate the scrim expansion when triggered by the fingerprint sensor.
4734 mScrimController.setExpansionAffectsAlpha(
4735 !mBiometricUnlockController.isBiometricUnlock());
4737 boolean launchingAffordanceWithPreview =
4738 mNotificationPanel.isLaunchingAffordanceWithPreview();
4739 mScrimController.setLaunchingAffordanceWithPreview(launchingAffordanceWithPreview);
4741 if (mBouncerShowing) {
4742 // Bouncer needs the front scrim when it's on top of an activity,
4743 // tapping on a notification, editing QS or being dismissed by
4744 // FLAG_DISMISS_KEYGUARD_ACTIVITY.
4745 ScrimState state = mStatusBarKeyguardViewManager.bouncerNeedsScrimming()
4746 ? ScrimState.BOUNCER_SCRIMMED : ScrimState.BOUNCER;
4747 mScrimController.transitionTo(state);
4748 } else if (isInLaunchTransition() || mLaunchCameraOnScreenTurningOn
4749 || launchingAffordanceWithPreview) {
4750 mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback);
4751 } else if (mBrightnessMirrorVisible) {
4752 mScrimController.transitionTo(ScrimState.BRIGHTNESS_MIRROR);
4753 } else if (isPulsing()) {
4754 // Handled in DozeScrimController#setPulsing
4755 } else if (mDozing) {
4756 mScrimController.transitionTo(ScrimState.AOD);
4757 } else if (mIsKeyguard && !wakeAndUnlocking) {
4758 mScrimController.transitionTo(ScrimState.KEYGUARD);
4760 mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback);
4765 public boolean isKeyguardShowing() {
4766 if (mStatusBarKeyguardViewManager == null) {
4767 Slog.i(TAG, "isKeyguardShowing() called before startKeyguard(), returning true");
4770 return mStatusBarKeyguardViewManager.isShowing();
4773 private final class DozeServiceHost implements DozeHost {
4774 private final ArrayList<Callback> mCallbacks = new ArrayList<>();
4775 private boolean mAnimateWakeup;
4776 private boolean mAnimateScreenOff;
4777 private boolean mIgnoreTouchWhilePulsing;
4780 public String toString() {
4781 return "PSB.DozeServiceHost[mCallbacks=" + mCallbacks.size() + "]";
4784 public void firePowerSaveChanged(boolean active) {
4785 for (Callback callback : mCallbacks) {
4786 callback.onPowerSaveChanged(active);
4790 public void fireNotificationHeadsUp() {
4791 for (Callback callback : mCallbacks) {
4792 callback.onNotificationHeadsUp();
4797 public void addCallback(@NonNull Callback callback) {
4798 mCallbacks.add(callback);
4802 public void removeCallback(@NonNull Callback callback) {
4803 mCallbacks.remove(callback);
4807 public void startDozing() {
4808 if (!mDozingRequested) {
4809 mDozingRequested = true;
4810 DozeLog.traceDozing(mContext, mDozing);
4817 public void pulseWhileDozing(@NonNull PulseCallback callback, int reason) {
4818 if (reason == DozeLog.PULSE_REASON_SENSOR_LONG_PRESS) {
4819 mPowerManager.wakeUp(SystemClock.uptimeMillis(), "com.android.systemui:NODOZE");
4820 startAssist(new Bundle());
4824 mDozeScrimController.pulse(new PulseCallback() {
4826 public void onPulseStarted() {
4827 callback.onPulseStarted();
4828 if (mHeadsUpManager.hasHeadsUpNotifications()) {
4829 // Only pulse the stack scroller if there's actually something to show.
4830 // Otherwise just show the always-on screen.
4836 public void onPulseFinished() {
4837 callback.onPulseFinished();
4841 private void setPulsing(boolean pulsing) {
4842 mKeyguardViewMediator.setPulsing(pulsing);
4843 mNotificationPanel.setPulsing(pulsing);
4844 mVisualStabilityManager.setPulsing(pulsing);
4845 mIgnoreTouchWhilePulsing = false;
4851 public void stopDozing() {
4852 if (mDozingRequested) {
4853 mDozingRequested = false;
4854 DozeLog.traceDozing(mContext, mDozing);
4855 mWakefulnessLifecycle.dispatchStartedWakingUp();
4861 public void onIgnoreTouchWhilePulsing(boolean ignore) {
4862 if (ignore != mIgnoreTouchWhilePulsing) {
4863 DozeLog.tracePulseTouchDisabledByProx(mContext, ignore);
4865 mIgnoreTouchWhilePulsing = ignore;
4866 if (isDozing() && ignore) {
4867 mStatusBarWindow.cancelCurrentTouch();
4872 public void dozeTimeTick() {
4873 mNotificationPanel.dozeTimeTick();
4877 public boolean isPowerSaveActive() {
4878 return mBatteryController.isAodPowerSave();
4882 public boolean isPulsingBlocked() {
4883 return mBiometricUnlockController.getMode()
4884 == BiometricUnlockController.MODE_WAKE_AND_UNLOCK;
4888 public boolean isProvisioned() {
4889 return mDeviceProvisionedController.isDeviceProvisioned()
4890 && mDeviceProvisionedController.isCurrentUserSetup();
4894 public boolean isBlockingDoze() {
4895 if (mBiometricUnlockController.hasPendingAuthentication()) {
4896 Log.i(TAG, "Blocking AOD because fingerprint has authenticated");
4903 public void startPendingIntentDismissingKeyguard(PendingIntent intent) {
4904 StatusBar.this.startPendingIntentDismissingKeyguard(intent);
4908 public void extendPulse() {
4909 mDozeScrimController.extendPulse();
4913 public void setAnimateWakeup(boolean animateWakeup) {
4914 if (mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_AWAKE
4915 || mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_WAKING) {
4916 // Too late to change the wakeup animation.
4919 mAnimateWakeup = animateWakeup;
4923 public void setAnimateScreenOff(boolean animateScreenOff) {
4924 mAnimateScreenOff = animateScreenOff;
4928 public void onDoubleTap(float screenX, float screenY) {
4929 if (screenX > 0 && screenY > 0 && mAmbientIndicationContainer != null
4930 && mAmbientIndicationContainer.getVisibility() == View.VISIBLE) {
4931 mAmbientIndicationContainer.getLocationOnScreen(mTmpInt2);
4932 float viewX = screenX - mTmpInt2[0];
4933 float viewY = screenY - mTmpInt2[1];
4934 if (0 <= viewX && viewX <= mAmbientIndicationContainer.getWidth()
4935 && 0 <= viewY && viewY <= mAmbientIndicationContainer.getHeight()) {
4936 dispatchDoubleTap(viewX, viewY);
4942 public void setDozeScreenBrightness(int value) {
4943 mStatusBarWindowManager.setDozeScreenBrightness(value);
4947 public void setAodDimmingScrim(float scrimOpacity) {
4948 mScrimController.setAodFrontScrimAlpha(scrimOpacity);
4951 public void dispatchDoubleTap(float viewX, float viewY) {
4952 dispatchTap(mAmbientIndicationContainer, viewX, viewY);
4953 dispatchTap(mAmbientIndicationContainer, viewX, viewY);
4956 private void dispatchTap(View view, float x, float y) {
4957 long now = SystemClock.elapsedRealtime();
4958 dispatchTouchEvent(view, x, y, now, MotionEvent.ACTION_DOWN);
4959 dispatchTouchEvent(view, x, y, now, MotionEvent.ACTION_UP);
4962 private void dispatchTouchEvent(View view, float x, float y, long now, int action) {
4963 MotionEvent ev = MotionEvent.obtain(now, now, action, x, y, 0 /* meta */);
4964 view.dispatchTouchEvent(ev);
4968 private boolean shouldAnimateWakeup() {
4969 return mAnimateWakeup;
4972 public boolean shouldAnimateScreenOff() {
4973 return mAnimateScreenOff;
4977 public boolean shouldIgnoreTouch() {
4978 return isDozing() && mDozeServiceHost.mIgnoreTouchWhilePulsing;
4981 // Begin Extra BaseStatusBar methods.
4983 protected CommandQueue mCommandQueue;
4984 protected IStatusBarService mBarService;
4986 // all notifications
4987 protected NotificationStackScrollLayout mStackScroller;
4989 protected NotificationGroupManager mGroupManager;
4992 // for heads up notifications
4993 protected HeadsUpManagerPhone mHeadsUpManager;
4995 private AboveShelfObserver mAboveShelfObserver;
4997 // handling reordering
4998 protected VisualStabilityManager mVisualStabilityManager;
5000 protected AccessibilityManager mAccessibilityManager;
5002 protected boolean mDeviceInteractive;
5004 protected boolean mVisible;
5006 // mScreenOnFromKeyguard && mVisible.
5007 private boolean mVisibleToUser;
5009 protected DevicePolicyManager mDevicePolicyManager;
5010 protected PowerManager mPowerManager;
5011 protected StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
5013 protected KeyguardManager mKeyguardManager;
5014 private LockPatternUtils mLockPatternUtils;
5015 private DeviceProvisionedController mDeviceProvisionedController
5016 = Dependency.get(DeviceProvisionedController.class);
5018 // UI-specific methods
5020 protected WindowManager mWindowManager;
5021 protected IWindowManager mWindowManagerService;
5023 protected Display mDisplay;
5025 protected RecentsComponent mRecents;
5027 protected NotificationShelf mNotificationShelf;
5028 protected FooterView mFooterView;
5029 protected EmptyShadeView mEmptyShadeView;
5031 protected AssistManager mAssistManager;
5033 protected boolean mVrMode;
5035 public boolean isDeviceInteractive() {
5036 return mDeviceInteractive;
5039 @Override // NotificationData.Environment
5040 public boolean isDeviceProvisioned() {
5041 return mDeviceProvisionedController.isDeviceProvisioned();
5044 private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
5046 public void onVrStateChanged(boolean enabled) {
5051 public boolean isDeviceInVrMode() {
5055 private final BroadcastReceiver mBannerActionBroadcastReceiver = new BroadcastReceiver() {
5057 public void onReceive(Context context, Intent intent) {
5058 String action = intent.getAction();
5059 if (BANNER_ACTION_CANCEL.equals(action) || BANNER_ACTION_SETUP.equals(action)) {
5060 NotificationManager noMan = (NotificationManager)
5061 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
5062 noMan.cancel(com.android.internal.messages.nano.SystemMessageProto.SystemMessage.
5063 NOTE_HIDDEN_NOTIFICATIONS);
5065 Settings.Secure.putInt(mContext.getContentResolver(),
5066 Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0);
5067 if (BANNER_ACTION_SETUP.equals(action)) {
5068 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
5070 mContext.startActivity(new Intent(Settings.ACTION_APP_NOTIFICATION_REDACTION)
5071 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
5080 public void onNotificationClicked(StatusBarNotification sbn, ExpandableNotificationRow row) {
5081 RemoteInputController controller = mRemoteInputManager.getController();
5082 if (controller.isRemoteInputActive(row.getEntry())
5083 && !TextUtils.isEmpty(row.getActiveRemoteInputText())) {
5084 // We have an active remote input typed and the user clicked on the notification.
5085 // this was probably unintentional, so we're closing the edit text instead.
5086 controller.closeRemoteInputs();
5089 Notification notification = sbn.getNotification();
5090 final PendingIntent intent = notification.contentIntent != null
5091 ? notification.contentIntent
5092 : notification.fullScreenIntent;
5093 final String notificationKey = sbn.getKey();
5095 final boolean afterKeyguardGone = intent.isActivity()
5096 && PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
5097 mLockscreenUserManager.getCurrentUserId());
5098 final boolean wasOccluded = mIsOccluded;
5099 dismissKeyguardThenExecute(() -> {
5100 // TODO: Some of this code may be able to move to NotificationEntryManager.
5101 if (mHeadsUpManager != null && mHeadsUpManager.isHeadsUp(notificationKey)) {
5102 // Release the HUN notification to the shade.
5104 if (isPresenterFullyCollapsed()) {
5105 HeadsUpUtil.setIsClickedHeadsUpNotification(row, true);
5108 // In most cases, when FLAG_AUTO_CANCEL is set, the notification will
5109 // become canceled shortly by NoMan, but we can't assume that.
5110 mHeadsUpManager.releaseImmediately(notificationKey);
5112 StatusBarNotification parentToCancel = null;
5113 if (shouldAutoCancel(sbn) && mGroupManager.isOnlyChildInGroup(sbn)) {
5114 StatusBarNotification summarySbn =
5115 mGroupManager.getLogicalGroupSummary(sbn).getStatusBarNotification();
5116 if (shouldAutoCancel(summarySbn)) {
5117 parentToCancel = summarySbn;
5120 final StatusBarNotification parentToCancelFinal = parentToCancel;
5121 final Runnable runnable = () -> {
5123 // The intent we are sending is for the application, which
5124 // won't have permission to immediately start an activity after
5125 // the user switches to home. We know it is safe to do at this
5126 // point, so make sure new activity switches are now allowed.
5127 ActivityManager.getService().resumeAppSwitches();
5128 } catch (RemoteException e) {
5130 int launchResult = ActivityManager.START_CANCELED;
5131 if (intent != null) {
5132 // If we are launching a work activity and require to launch
5133 // separate work challenge, we defer the activity action and cancel
5134 // notification until work challenge is unlocked.
5135 if (intent.isActivity()) {
5136 final int userId = intent.getCreatorUserHandle().getIdentifier();
5137 if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)
5138 && mKeyguardManager.isDeviceLocked(userId)) {
5139 // TODO(b/28935539): should allow certain activities to
5140 // bypass work challenge
5141 if (startWorkChallengeIfNecessary(userId, intent.getIntentSender(),
5143 // Show work challenge, do not run PendingIntent and
5144 // remove notification
5145 collapseOnMainThread();
5150 Intent fillInIntent = null;
5151 Entry entry = row.getEntry();
5152 CharSequence remoteInputText = null;
5153 if (!TextUtils.isEmpty(entry.remoteInputText)) {
5154 remoteInputText = entry.remoteInputText;
5156 if (!TextUtils.isEmpty(remoteInputText)
5157 && !controller.isSpinning(entry.key)) {
5158 fillInIntent = new Intent().putExtra(Notification.EXTRA_REMOTE_INPUT_DRAFT,
5159 remoteInputText.toString());
5161 RemoteAnimationAdapter adapter = mActivityLaunchAnimator.getLaunchAnimation(
5164 if (adapter != null) {
5165 ActivityTaskManager.getService()
5166 .registerRemoteAnimationForNextActivityStart(
5167 intent.getCreatorPackage(), adapter);
5169 launchResult = intent.sendAndReturnResult(mContext, 0, fillInIntent, null,
5170 null, null, getActivityOptions(adapter));
5171 mActivityLaunchAnimator.setLaunchResult(launchResult);
5172 } catch (RemoteException | PendingIntent.CanceledException e) {
5173 // the stack trace isn't very helpful here.
5174 // Just log the exception message.
5175 Log.w(TAG, "Sending contentIntent failed: " + e);
5177 // TODO: Dismiss Keyguard.
5179 if (intent.isActivity()) {
5180 mAssistManager.hideAssist();
5183 if (shouldCollapse()) {
5184 collapseOnMainThread();
5188 mEntryManager.getNotificationData().getActiveNotifications().size();
5189 final int rank = mEntryManager.getNotificationData().getRank(notificationKey);
5190 final NotificationVisibility nv = NotificationVisibility.obtain(notificationKey,
5193 mBarService.onNotificationClick(notificationKey, nv);
5194 } catch (RemoteException ex) {
5195 // system process is dead if we're here.
5197 if (parentToCancelFinal != null) {
5198 removeNotification(parentToCancelFinal);
5200 if (shouldAutoCancel(sbn)
5201 || mEntryManager.isNotificationKeptForRemoteInput(notificationKey)) {
5202 // Automatically remove all notifications that we may have kept around longer
5203 removeNotification(sbn);
5207 if (mStatusBarKeyguardViewManager.isShowing()
5208 && mStatusBarKeyguardViewManager.isOccluded()) {
5209 mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(runnable);
5210 collapsePanel(true /* animate */);
5212 new Thread(runnable).start();
5215 return !mNotificationPanel.isFullyCollapsed();
5216 }, afterKeyguardGone);
5219 private void collapseOnMainThread() {
5220 if (Looper.getMainLooper().isCurrentThread()) {
5223 mStackScroller.post(this::collapsePanel);
5227 private boolean shouldCollapse() {
5228 return mState != StatusBarState.SHADE || !mActivityLaunchAnimator.isAnimationPending();
5231 public void collapsePanel(boolean animate) {
5234 } else if (!isPresenterFullyCollapsed()) {
5235 instantCollapseNotificationPanel();
5236 visibilityChanged(false);
5238 runPostCollapseRunnables();
5242 private boolean collapsePanel() {
5243 if (!mNotificationPanel.isFullyCollapsed()) {
5244 // close the shade if it was open
5245 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */,
5246 true /* delayed */);
5247 visibilityChanged(false);
5255 private void removeNotification(StatusBarNotification notification) {
5256 // We have to post it to the UI thread for synchronization
5257 mHandler.post(() -> {
5258 Runnable removeRunnable =
5259 () -> mEntryManager.performRemoveNotification(notification);
5260 if (isCollapsing()) {
5261 // To avoid lags we're only performing the remove
5262 // after the shade was collapsed
5263 addPostCollapseAction(removeRunnable);
5265 removeRunnable.run();
5270 protected NotificationListener mNotificationListener;
5272 @Override // NotificationData.Environment
5273 public boolean isNotificationForCurrentProfiles(StatusBarNotification n) {
5274 final int notificationUserId = n.getUserId();
5275 if (DEBUG && MULTIUSER_DEBUG) {
5276 Log.v(TAG, String.format("%s: current userid: %d, notification userid: %d", n,
5277 mLockscreenUserManager.getCurrentUserId(), notificationUserId));
5279 return mLockscreenUserManager.isCurrentProfile(notificationUserId);
5283 public NotificationGroupManager getGroupManager() {
5284 return mGroupManager;
5288 public void startNotificationGutsIntent(final Intent intent, final int appUid,
5289 ExpandableNotificationRow row) {
5290 dismissKeyguardThenExecute(() -> {
5291 AsyncTask.execute(() -> {
5292 int launchResult = TaskStackBuilder.create(mContext)
5293 .addNextIntentWithParentStack(intent)
5294 .startActivities(getActivityOptions(
5295 mActivityLaunchAnimator.getLaunchAnimation(row, mIsOccluded)),
5296 new UserHandle(UserHandle.getUserId(appUid)));
5297 mActivityLaunchAnimator.setLaunchResult(launchResult);
5298 if (shouldCollapse()) {
5299 // Putting it back on the main thread, since we're touching views
5300 mStatusBarWindow.post(() -> animateCollapsePanels(
5301 CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */));
5305 }, false /* afterKeyguardGone */);
5308 public void setNotificationSnoozed(StatusBarNotification sbn, SnoozeOption snoozeOption) {
5309 if (snoozeOption.getSnoozeCriterion() != null) {
5310 mNotificationListener.snoozeNotification(sbn.getKey(),
5311 snoozeOption.getSnoozeCriterion().getId());
5313 mNotificationListener.snoozeNotification(sbn.getKey(),
5314 snoozeOption.getMinutesToSnoozeFor() * 60 * 1000);
5319 public void toggleSplitScreen() {
5320 toggleSplitScreenMode(-1 /* metricsDockAction */, -1 /* metricsUndockAction */);
5323 void awakenDreams() {
5324 SystemServicesProxy.getInstance(mContext).awakenDreamsAsync();
5328 public void preloadRecentApps() {
5329 int msg = MSG_PRELOAD_RECENT_APPS;
5330 mHandler.removeMessages(msg);
5331 mHandler.sendEmptyMessage(msg);
5335 public void cancelPreloadRecentApps() {
5336 int msg = MSG_CANCEL_PRELOAD_RECENT_APPS;
5337 mHandler.removeMessages(msg);
5338 mHandler.sendEmptyMessage(msg);
5342 public void dismissKeyboardShortcutsMenu() {
5343 int msg = MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU;
5344 mHandler.removeMessages(msg);
5345 mHandler.sendEmptyMessage(msg);
5349 public void toggleKeyboardShortcutsMenu(int deviceId) {
5350 int msg = MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU;
5351 mHandler.removeMessages(msg);
5352 mHandler.obtainMessage(msg, deviceId, 0).sendToTarget();
5356 public void setTopAppHidesStatusBar(boolean topAppHidesStatusBar) {
5357 mTopHidesStatusBar = topAppHidesStatusBar;
5358 if (!topAppHidesStatusBar && mWereIconsJustHidden) {
5359 // Immediately update the icon hidden state, since that should only apply if we're
5360 // staying fullscreen.
5361 mWereIconsJustHidden = false;
5362 recomputeDisableFlags(true);
5364 updateHideIconsForBouncer(true /* animate */);
5367 protected void toggleKeyboardShortcuts(int deviceId) {
5368 KeyboardShortcuts.toggle(mContext, deviceId);
5371 protected void dismissKeyboardShortcuts() {
5372 KeyboardShortcuts.dismiss();
5375 @Override // NotificationData.Environment
5376 public boolean shouldHideNotifications(int userId) {
5377 return mLockscreenUserManager.shouldHideNotifications(userId);
5380 @Override // NotificationDate.Environment
5381 public boolean shouldHideNotifications(String key) {
5382 return mLockscreenUserManager.shouldHideNotifications(key);
5386 * Returns true if we're on a secure lockscreen.
5388 @Override // NotificationData.Environment
5389 public boolean isSecurelyLocked(int userId) {
5390 return mLockscreenUserManager.isLockscreenPublicMode(userId);
5394 * Called when the notification panel layouts
5396 public void onPanelLaidOut() {
5397 updateKeyguardMaxNotifications();
5400 public void updateKeyguardMaxNotifications() {
5401 if (mState == StatusBarState.KEYGUARD) {
5402 // Since the number of notifications is determined based on the height of the view, we
5403 // need to update them.
5404 int maxBefore = getMaxNotificationsWhileLocked(false /* recompute */);
5405 int maxNotifications = getMaxNotificationsWhileLocked(true /* recompute */);
5406 if (maxBefore != maxNotifications) {
5407 mViewHierarchyManager.updateRowStates();
5412 public void startPendingIntentDismissingKeyguard(final PendingIntent intent) {
5413 if (!isDeviceProvisioned()) return;
5415 final boolean afterKeyguardGone = intent.isActivity()
5416 && PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
5417 mLockscreenUserManager.getCurrentUserId());
5418 dismissKeyguardThenExecute(() -> {
5421 // The intent we are sending is for the application, which
5422 // won't have permission to immediately start an activity after
5423 // the user switches to home. We know it is safe to do at this
5424 // point, so make sure new activity switches are now allowed.
5425 ActivityManager.getService().resumeAppSwitches();
5426 } catch (RemoteException e) {
5429 intent.send(null, 0, null, null, null, null, getActivityOptions(
5430 null /* animationAdapter */));
5431 } catch (PendingIntent.CanceledException e) {
5432 // the stack trace isn't very helpful here.
5433 // Just log the exception message.
5434 Log.w(TAG, "Sending intent failed: " + e);
5436 // TODO: Dismiss Keyguard.
5438 if (intent.isActivity()) {
5439 mAssistManager.hideAssist();
5443 return collapsePanel();
5444 }, afterKeyguardGone);
5447 private boolean shouldAutoCancel(StatusBarNotification sbn) {
5448 int flags = sbn.getNotification().flags;
5449 if ((flags & Notification.FLAG_AUTO_CANCEL) != Notification.FLAG_AUTO_CANCEL) {
5452 if ((flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
5458 protected Bundle getActivityOptions(@Nullable RemoteAnimationAdapter animationAdapter) {
5459 ActivityOptions options;
5460 if (animationAdapter != null) {
5461 options = ActivityOptions.makeRemoteAnimation(animationAdapter);
5463 options = ActivityOptions.makeBasic();
5465 // Anything launched from the notification shade should always go into the secondary
5466 // split-screen windowing mode.
5467 options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY);
5468 return options.toBundle();
5471 protected void visibilityChanged(boolean visible) {
5472 if (mVisible != visible) {
5475 mGutsManager.closeAndSaveGuts(true /* removeLeavebehind */, true /* force */,
5476 true /* removeControls */, -1 /* x */, -1 /* y */, true /* resetMenu */);
5479 updateVisibleToUser();
5482 protected void updateVisibleToUser() {
5483 boolean oldVisibleToUser = mVisibleToUser;
5484 mVisibleToUser = mVisible && mDeviceInteractive;
5486 if (oldVisibleToUser != mVisibleToUser) {
5487 handleVisibleToUserChanged(mVisibleToUser);
5492 * Clear Buzz/Beep/Blink.
5494 public void clearNotificationEffects() {
5496 mBarService.clearNotificationEffects();
5497 } catch (RemoteException e) {
5498 // Won't fail unless the world has ended.
5503 * Updates expanded, dimmed and locked states of notification rows.
5506 public void onUpdateRowStates() {
5507 // The following views will be moved to the end of mStackScroller. This counter represents
5508 // the offset from the last child. Initialized to 1 for the very last position. It is post-
5509 // incremented in the following "changeViewPosition" calls so that its value is correct for
5510 // subsequent calls.
5511 int offsetFromEnd = 1;
5512 if (mFooterView != null) {
5513 mStackScroller.changeViewPosition(mFooterView,
5514 mStackScroller.getChildCount() - offsetFromEnd++);
5517 mStackScroller.changeViewPosition(mEmptyShadeView,
5518 mStackScroller.getChildCount() - offsetFromEnd++);
5520 // No post-increment for this call because it is the last one. Make sure to add one if
5521 // another "changeViewPosition" call is ever added.
5522 mStackScroller.changeViewPosition(mNotificationShelf,
5523 mStackScroller.getChildCount() - offsetFromEnd);
5525 // Scrim opacity varies based on notification count
5526 mScrimController.setNotificationCount(mStackScroller.getNotGoneChildCount());
5529 protected void notifyHeadsUpGoingToSleep() {
5530 maybeEscalateHeadsUp();
5534 * @return Whether the security bouncer from Keyguard is showing.
5536 public boolean isBouncerShowing() {
5537 return mBouncerShowing;
5541 * @return a PackageManger for userId or if userId is < 0 (USER_ALL etc) then
5542 * return PackageManager for mContext
5544 public static PackageManager getPackageManagerForUser(Context context, int userId) {
5545 Context contextForUser = context;
5546 // UserHandle defines special userId as negative values, e.g. USER_ALL
5549 // Create a context for the correct user so if a package isn't installed
5550 // for user 0 we can still load information about the package.
5552 context.createPackageContextAsUser(context.getPackageName(),
5553 Context.CONTEXT_RESTRICTED,
5554 new UserHandle(userId));
5555 } catch (NameNotFoundException e) {
5556 // Shouldn't fail to find the package name for system ui.
5559 return contextForUser.getPackageManager();
5562 public boolean isKeyguardSecure() {
5563 if (mStatusBarKeyguardViewManager == null) {
5564 // startKeyguard() hasn't been called yet, so we don't know.
5565 // Make sure anything that needs to know isKeyguardSecure() checks and re-checks this
5566 // value onVisibilityChanged().
5567 Slog.w(TAG, "isKeyguardSecure() called before startKeyguard(), returning false",
5571 return mStatusBarKeyguardViewManager.isSecure();
5575 public void onZenChanged(int zen) {
5576 updateEmptyShadeView();
5580 public void showAssistDisclosure() {
5581 if (mAssistManager != null) {
5582 mAssistManager.showDisclosure();
5586 public NotificationPanelView getPanel() {
5587 return mNotificationPanel;
5591 public void startAssist(Bundle args) {
5592 if (mAssistManager != null) {
5593 mAssistManager.startAssist(args);
5596 // End Extra BaseStatusBarMethods.
5598 private final Runnable mAutoDim = () -> {
5599 if (mNavigationBar != null) {
5600 mNavigationBar.getBarTransitions().setAutoDim(true);
5604 public NotificationGutsManager getGutsManager() {
5605 return mGutsManager;
5609 public boolean isPresenterLocked() {
5610 return mState == StatusBarState.KEYGUARD;
5614 public Handler getHandler() {
5618 private final NotificationInfo.CheckSaveListener mCheckSaveListener =
5619 (Runnable saveImportance, StatusBarNotification sbn) -> {
5620 // If the user has security enabled, show challenge if the setting is changed.
5621 if (mLockscreenUserManager.isLockscreenPublicMode(sbn.getUser().getIdentifier())
5622 && (mState == StatusBarState.KEYGUARD ||
5623 mState == StatusBarState.SHADE_LOCKED)) {
5624 onLockedNotificationImportanceChange(() -> {
5625 saveImportance.run();
5629 saveImportance.run();