1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.statusbar.phone;
18 
19 import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
20 import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
21 import static android.app.StatusBarManager.windowStateToString;
22 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
23 
24 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP;
25 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
26 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_WAKING;
27 import static com.android.systemui.shared.system.WindowManagerWrapper.NAV_BAR_POS_LEFT;
28 import static com.android.systemui.shared.system.WindowManagerWrapper.NAV_BAR_POS_INVALID;
29 import static com.android.systemui.statusbar.NotificationLockscreenUserManager
30         .NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION;
31 import static com.android.systemui.statusbar.NotificationLockscreenUserManager.PERMISSION_SELF;
32 import static com.android.systemui.statusbar.NotificationMediaManager.DEBUG_MEDIA;
33 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
34 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
35 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
36 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
37 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSLUCENT;
38 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
39 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_WARNING;
40 
41 import android.animation.Animator;
42 import android.animation.AnimatorListenerAdapter;
43 import android.annotation.NonNull;
44 import android.annotation.Nullable;
45 import android.app.ActivityManager;
46 import android.app.ActivityOptions;
47 import android.app.AlarmManager;
48 import android.app.IWallpaperManager;
49 import android.app.KeyguardManager;
50 import android.app.Notification;
51 import android.app.NotificationManager;
52 import android.app.PendingIntent;
53 import android.app.StatusBarManager;
54 import android.app.TaskStackBuilder;
55 import android.app.WallpaperColors;
56 import android.app.WallpaperInfo;
57 import android.app.WallpaperManager;
58 import android.app.admin.DevicePolicyManager;
59 import android.content.BroadcastReceiver;
60 import android.content.ComponentCallbacks2;
61 import android.content.ComponentName;
62 import android.content.Context;
63 import android.content.Intent;
64 import android.content.IntentFilter;
65 import android.content.IntentSender;
66 import android.content.om.IOverlayManager;
67 import android.content.om.OverlayInfo;
68 import android.content.pm.IPackageManager;
69 import android.content.pm.PackageManager;
70 import android.content.pm.PackageManager.NameNotFoundException;
71 import android.content.pm.UserInfo;
72 import android.content.res.Configuration;
73 import android.content.res.Resources;
74 import android.graphics.Bitmap;
75 import android.graphics.Point;
76 import android.graphics.PointF;
77 import android.graphics.PorterDuff;
78 import android.graphics.PorterDuffXfermode;
79 import android.graphics.Rect;
80 import android.graphics.drawable.BitmapDrawable;
81 import android.graphics.drawable.ColorDrawable;
82 import android.graphics.drawable.Drawable;
83 import android.media.AudioAttributes;
84 import android.media.MediaMetadata;
85 import android.metrics.LogMaker;
86 import android.net.Uri;
87 import android.os.AsyncTask;
88 import android.os.Bundle;
89 import android.os.Handler;
90 import android.os.IBinder;
91 import android.os.Looper;
92 import android.os.Message;
93 import android.os.PowerManager;
94 import android.os.RemoteException;
95 import android.os.ServiceManager;
96 import android.os.SystemClock;
97 import android.os.SystemProperties;
98 import android.os.Trace;
99 import android.os.UserHandle;
100 import android.os.UserManager;
101 import android.os.VibrationEffect;
102 import android.os.Vibrator;
103 import android.provider.Settings;
104 import android.service.notification.StatusBarNotification;
105 import android.service.vr.IVrManager;
106 import android.service.vr.IVrStateCallbacks;
107 import android.text.TextUtils;
108 import android.util.DisplayMetrics;
109 import android.util.EventLog;
110 import android.util.Log;
111 import android.util.Slog;
112 import android.util.SparseArray;
113 import android.view.Display;
114 import android.view.IWindowManager;
115 import android.view.KeyEvent;
116 import android.view.LayoutInflater;
117 import android.view.MotionEvent;
118 import android.view.RemoteAnimationAdapter;
119 import android.view.ThreadedRenderer;
120 import android.view.View;
121 import android.view.ViewGroup;
122 import android.view.ViewParent;
123 import android.view.ViewTreeObserver;
124 import android.view.WindowManager;
125 import android.view.WindowManagerGlobal;
126 import android.view.accessibility.AccessibilityManager;
127 import android.view.animation.AccelerateInterpolator;
128 import android.widget.DateTimeView;
129 import android.widget.ImageView;
130 import android.widget.TextView;
131 
132 import com.android.internal.annotations.VisibleForTesting;
133 import com.android.internal.colorextraction.ColorExtractor;
134 import com.android.internal.logging.MetricsLogger;
135 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
136 import com.android.internal.statusbar.IStatusBarService;
137 import com.android.internal.statusbar.NotificationVisibility;
138 import com.android.internal.statusbar.StatusBarIcon;
139 import com.android.internal.widget.LockPatternUtils;
140 import com.android.internal.widget.MessagingGroup;
141 import com.android.internal.widget.MessagingMessage;
142 import com.android.keyguard.KeyguardHostView.OnDismissAction;
143 import com.android.keyguard.KeyguardUpdateMonitor;
144 import com.android.keyguard.KeyguardUpdateMonitorCallback;
145 import com.android.keyguard.ViewMediatorCallback;
146 import com.android.systemui.ActivityStarterDelegate;
147 import com.android.systemui.AutoReinflateContainer;
148 import com.android.systemui.DemoMode;
149 import com.android.systemui.Dependency;
150 import com.android.systemui.EventLogTags;
151 import com.android.systemui.Interpolators;
152 import com.android.systemui.Prefs;
153 import com.android.systemui.R;
154 import com.android.systemui.RecentsComponent;
155 import com.android.systemui.SystemUI;
156 import com.android.systemui.SystemUIFactory;
157 import com.android.systemui.UiOffloadThread;
158 import com.android.systemui.assist.AssistManager;
159 import com.android.systemui.charging.WirelessChargingAnimation;
160 import com.android.systemui.classifier.FalsingLog;
161 import com.android.systemui.classifier.FalsingManager;
162 import com.android.systemui.colorextraction.SysuiColorExtractor;
163 import com.android.systemui.doze.DozeHost;
164 import com.android.systemui.doze.DozeLog;
165 import com.android.systemui.doze.DozeReceiver;
166 import com.android.systemui.fragments.ExtensionFragmentListener;
167 import com.android.systemui.fragments.FragmentHostManager;
168 import com.android.systemui.keyguard.KeyguardViewMediator;
169 import com.android.systemui.keyguard.ScreenLifecycle;
170 import com.android.systemui.keyguard.WakefulnessLifecycle;
171 import com.android.systemui.plugins.ActivityStarter;
172 import com.android.systemui.plugins.qs.QS;
173 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption;
174 import com.android.systemui.qs.QSFragment;
175 import com.android.systemui.qs.QSPanel;
176 import com.android.systemui.qs.QSTileHost;
177 import com.android.systemui.qs.car.CarQSFragment;
178 import com.android.systemui.recents.Recents;
179 import com.android.systemui.recents.ScreenPinningRequest;
180 import com.android.systemui.recents.events.EventBus;
181 import com.android.systemui.recents.events.activity.AppTransitionFinishedEvent;
182 import com.android.systemui.recents.events.activity.UndockingTaskEvent;
183 import com.android.systemui.recents.misc.SystemServicesProxy;
184 import com.android.systemui.shared.system.WindowManagerWrapper;
185 import com.android.systemui.stackdivider.Divider;
186 import com.android.systemui.stackdivider.WindowManagerProxy;
187 import com.android.systemui.statusbar.ActivatableNotificationView;
188 import com.android.systemui.statusbar.AppOpsListener;
189 import com.android.systemui.statusbar.BackDropView;
190 import com.android.systemui.statusbar.CommandQueue;
191 import com.android.systemui.statusbar.CrossFadeHelper;
192 import com.android.systemui.statusbar.DragDownHelper;
193 import com.android.systemui.statusbar.EmptyShadeView;
194 import com.android.systemui.statusbar.ExpandableNotificationRow;
195 import com.android.systemui.statusbar.FooterView;
196 import com.android.systemui.statusbar.GestureRecorder;
197 import com.android.systemui.statusbar.KeyboardShortcuts;
198 import com.android.systemui.statusbar.KeyguardIndicationController;
199 import com.android.systemui.statusbar.NotificationData;
200 import com.android.systemui.statusbar.NotificationData.Entry;
201 import com.android.systemui.statusbar.NotificationEntryManager;
202 import com.android.systemui.statusbar.NotificationGutsManager;
203 import com.android.systemui.statusbar.NotificationInfo;
204 import com.android.systemui.statusbar.NotificationListener;
205 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
206 import com.android.systemui.statusbar.NotificationLogger;
207 import com.android.systemui.statusbar.NotificationMediaManager;
208 import com.android.systemui.statusbar.NotificationPresenter;
209 import com.android.systemui.statusbar.NotificationRemoteInputManager;
210 import com.android.systemui.statusbar.NotificationShelf;
211 import com.android.systemui.statusbar.NotificationViewHierarchyManager;
212 import com.android.systemui.statusbar.RemoteInputController;
213 import com.android.systemui.statusbar.ScrimView;
214 import com.android.systemui.statusbar.StatusBarState;
215 import com.android.systemui.statusbar.VibratorHelper;
216 import com.android.systemui.statusbar.notification.AboveShelfObserver;
217 import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
218 import com.android.systemui.statusbar.notification.VisualStabilityManager;
219 import com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChangedListener;
220 import com.android.systemui.statusbar.policy.BatteryController;
221 import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
222 import com.android.systemui.statusbar.policy.BrightnessMirrorController;
223 import com.android.systemui.statusbar.policy.ConfigurationController;
224 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
225 import com.android.systemui.statusbar.policy.DarkIconDispatcher;
226 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
227 import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
228 import com.android.systemui.statusbar.policy.ExtensionController;
229 import com.android.systemui.statusbar.policy.HeadsUpManager;
230 import com.android.systemui.statusbar.policy.HeadsUpUtil;
231 import com.android.systemui.statusbar.policy.KeyguardMonitor;
232 import com.android.systemui.statusbar.policy.KeyguardMonitorImpl;
233 import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
234 import com.android.systemui.statusbar.policy.NetworkController;
235 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
236 import com.android.systemui.statusbar.policy.PreviewInflater;
237 import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
238 import com.android.systemui.statusbar.policy.UserInfoController;
239 import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
240 import com.android.systemui.statusbar.policy.UserSwitcherController;
241 import com.android.systemui.statusbar.policy.ZenModeController;
242 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
243 import com.android.systemui.volume.VolumeComponent;
244 
245 import java.io.FileDescriptor;
246 import java.io.PrintWriter;
247 import java.io.StringWriter;
248 import java.util.ArrayList;
249 import java.util.List;
250 import java.util.Map;
251 
252 public class StatusBar extends SystemUI implements DemoMode,
253         DragDownHelper.DragDownCallback, ActivityStarter, OnUnlockMethodChangedListener,
254         OnHeadsUpChangedListener, CommandQueue.Callbacks, ZenModeController.Callback,
255         ColorExtractor.OnColorsChangedListener, ConfigurationListener, NotificationPresenter {
256     public static final boolean MULTIUSER_DEBUG = false;
257 
258     public static final boolean ENABLE_CHILD_NOTIFICATIONS
259             = SystemProperties.getBoolean("debug.child_notifs", true);
260 
261     protected static final int MSG_HIDE_RECENT_APPS = 1020;
262     protected static final int MSG_PRELOAD_RECENT_APPS = 1022;
263     protected static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 1023;
264     protected static final int MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU = 1026;
265     protected static final int MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU = 1027;
266 
267     // Should match the values in PhoneWindowManager
268     public static final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
269     public static final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
270     static public final String SYSTEM_DIALOG_REASON_SCREENSHOT = "screenshot";
271 
272     private static final String BANNER_ACTION_CANCEL =
273             "com.android.systemui.statusbar.banner_action_cancel";
274     private static final String BANNER_ACTION_SETUP =
275             "com.android.systemui.statusbar.banner_action_setup";
276     public static final String TAG = "StatusBar";
277     public static final boolean DEBUG = false;
278     public static final boolean SPEW = false;
279     public static final boolean DUMPTRUCK = true; // extra dumpsys info
280     public static final boolean DEBUG_GESTURES = false;
281     public static final boolean DEBUG_MEDIA_FAKE_ARTWORK = false;
282     public static final boolean DEBUG_CAMERA_LIFT = false;
283 
284     public static final boolean DEBUG_WINDOW_STATE = false;
285 
286     // additional instrumentation for testing purposes; intended to be left on during development
287     public static final boolean CHATTY = DEBUG;
288 
289     public static final boolean SHOW_LOCKSCREEN_MEDIA_ARTWORK = true;
290 
291     public static final String ACTION_FAKE_ARTWORK = "fake_artwork";
292 
293     private static final int MSG_OPEN_NOTIFICATION_PANEL = 1000;
294     private static final int MSG_CLOSE_PANELS = 1001;
295     private static final int MSG_OPEN_SETTINGS_PANEL = 1002;
296     private static final int MSG_LAUNCH_TRANSITION_TIMEOUT = 1003;
297     // 1020-1040 reserved for BaseStatusBar
298 
299     // Time after we abort the launch transition.
300     private static final long LAUNCH_TRANSITION_TIMEOUT_MS = 5000;
301 
302     protected static final boolean CLOSE_PANEL_WHEN_EMPTIED = true;
303 
304     private static final int STATUS_OR_NAV_TRANSIENT =
305             View.STATUS_BAR_TRANSIENT | View.NAVIGATION_BAR_TRANSIENT;
306     private static final long AUTOHIDE_TIMEOUT_MS = 2250;
307 
308     /**
309      * The delay to reset the hint text when the hint animation is finished running.
310      */
311     private static final int HINT_RESET_DELAY_MS = 1200;
312 
313     private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
314             .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
315             .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
316             .build();
317 
318     public static final int FADE_KEYGUARD_START_DELAY = 100;
319     public static final int FADE_KEYGUARD_DURATION = 300;
320     public static final int FADE_KEYGUARD_DURATION_PULSING = 96;
321 
322     /** If true, the system is in the half-boot-to-decryption-screen state.
323      * Prudently disable QS and notifications.  */
324     private static final boolean ONLY_CORE_APPS;
325 
326     /** If true, the lockscreen will show a distinct wallpaper */
327     private static final boolean ENABLE_LOCKSCREEN_WALLPAPER = true;
328 
329     /**
330      * Never let the alpha become zero for surfaces that draw with SRC - otherwise the RenderNode
331      * won't draw anything and uninitialized memory will show through
332      * if mScrimSrcModeEnabled. Note that 0.001 is rounded down to 0 in
333      * libhwui.
334      */
335     private static final float SRC_MIN_ALPHA = 0.002f;
336 
337     static {
338         boolean onlyCoreApps;
339         try {
340             IPackageManager packageManager =
341                     IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
342             onlyCoreApps = packageManager.isOnlyCoreApps();
343         } catch (RemoteException e) {
344             onlyCoreApps = false;
345         }
346         ONLY_CORE_APPS = onlyCoreApps;
347     }
348 
349     /**
350      * The {@link StatusBarState} of the status bar.
351      */
352     protected int mState;
353     protected boolean mBouncerShowing;
354 
355     private PhoneStatusBarPolicy mIconPolicy;
356     private StatusBarSignalPolicy mSignalPolicy;
357 
358     private VolumeComponent mVolumeComponent;
359     private BrightnessMirrorController mBrightnessMirrorController;
360     private boolean mBrightnessMirrorVisible;
361     protected FingerprintUnlockController mFingerprintUnlockController;
362     private LightBarController mLightBarController;
363     protected LockscreenWallpaper mLockscreenWallpaper;
364 
365     private int mNaturalBarHeight = -1;
366 
367     private final Point mCurrentDisplaySize = new Point();
368 
369     protected StatusBarWindowView mStatusBarWindow;
370     protected PhoneStatusBarView mStatusBarView;
371     private int mStatusBarWindowState = WINDOW_STATE_SHOWING;
372     protected StatusBarWindowManager mStatusBarWindowManager;
373     protected UnlockMethodCache mUnlockMethodCache;
374     private DozeServiceHost mDozeServiceHost = new DozeServiceHost();
375     private boolean mWakeUpComingFromTouch;
376     private PointF mWakeUpTouchLocation;
377 
378     private final Object mQueueLock = new Object();
379 
380     protected StatusBarIconController mIconController;
381 
382     // expanded notifications
383     protected NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
384     private TextView mNotificationPanelDebugText;
385 
386     // settings
387     private QSPanel mQSPanel;
388 
389     // top bar
390     private KeyguardStatusBarView mKeyguardStatusBar;
391     private boolean mLeaveOpenOnKeyguardHide;
392     KeyguardIndicationController mKeyguardIndicationController;
393 
394     // Keyguard is actually fading away now.
395     protected boolean mKeyguardFadingAway;
396     protected long mKeyguardFadingAwayDelay;
397     protected long mKeyguardFadingAwayDuration;
398 
399     // RemoteInputView to be activated after unlock
400     private View mPendingRemoteInputView;
401     private View mPendingWorkRemoteInputView;
402 
403     private RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler =
404             Dependency.get(RemoteInputQuickSettingsDisabler.class);
405 
406     private View mReportRejectedTouch;
407 
408     private int mMaxAllowedKeyguardNotifications;
409 
410     private boolean mExpandedVisible;
411 
412     private final int[] mAbsPos = new int[2];
413     private final ArrayList<Runnable> mPostCollapseRunnables = new ArrayList<>();
414 
415     private NotificationGutsManager mGutsManager;
416     protected NotificationLogger mNotificationLogger;
417     protected NotificationEntryManager mEntryManager;
418     protected NotificationViewHierarchyManager mViewHierarchyManager;
419     protected AppOpsListener mAppOpsListener;
420     protected KeyguardViewMediator mKeyguardViewMediator;
421     private ZenModeController mZenController;
422 
423     /**
424      * Helper that is responsible for showing the right toast when a disallowed activity operation
425      * occurred. In pinned mode, we show instructions on how to break out of this mode, whilst in
426      * fully locked mode we only show that unlocking is blocked.
427      */
428     private ScreenPinningNotify mScreenPinningNotify;
429 
430     // for disabling the status bar
431     private int mDisabled1 = 0;
432     private int mDisabled2 = 0;
433 
434     // tracking calls to View.setSystemUiVisibility()
435     private int mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE;
436     private final Rect mLastFullscreenStackBounds = new Rect();
437     private final Rect mLastDockedStackBounds = new Rect();
438     private final Rect mTmpRect = new Rect();
439 
440     // last value sent to window manager
441     private int mLastDispatchedSystemUiVisibility = ~View.SYSTEM_UI_FLAG_VISIBLE;
442 
443     private final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
444 
445     // XXX: gesture research
446     private final GestureRecorder mGestureRec = DEBUG_GESTURES
447         ? new GestureRecorder("/sdcard/statusbar_gestures.dat")
448         : null;
449 
450     private ScreenPinningRequest mScreenPinningRequest;
451 
452     private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
453 
454     // ensure quick settings is disabled until the current user makes it through the setup wizard
455     @VisibleForTesting
456     protected boolean mUserSetup = false;
457     private final DeviceProvisionedListener mUserSetupObserver = new DeviceProvisionedListener() {
458         @Override
459         public void onUserSetupChanged() {
460             final boolean userSetup = mDeviceProvisionedController.isUserSetup(
461                     mDeviceProvisionedController.getCurrentUser());
462             if (MULTIUSER_DEBUG) {
463                 Log.d(TAG, String.format("User setup changed: userSetup=%s mUserSetup=%s",
464                         userSetup, mUserSetup));
465             }
466 
467             if (userSetup != mUserSetup) {
468                 mUserSetup = userSetup;
469                 if (!mUserSetup && mStatusBarView != null)
470                     animateCollapseQuickSettings();
471                 if (mNotificationPanel != null) {
472                     mNotificationPanel.setUserSetupComplete(mUserSetup);
473                 }
474                 updateQsExpansionEnabled();
475             }
476         }
477     };
478 
479     protected final H mHandler = createHandler();
480 
481     private int mInteractingWindows;
482     private boolean mAutohideSuspended;
483     private int mStatusBarMode;
484     private int mMaxKeyguardNotifications;
485 
486     private ViewMediatorCallback mKeyguardViewMediatorCallback;
487     protected ScrimController mScrimController;
488     protected DozeScrimController mDozeScrimController;
489     private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class);
490 
491     private final Runnable mAutohide = () -> {
492         int requested = mSystemUiVisibility & ~STATUS_OR_NAV_TRANSIENT;
493         if (mSystemUiVisibility != requested) {
494             notifyUiVisibilityChanged(requested);
495         }
496     };
497 
498     protected boolean mDozing;
499     private boolean mDozingRequested;
500     protected boolean mScrimSrcModeEnabled;
501 
502     protected BackDropView mBackdrop;
503     protected ImageView mBackdropFront, mBackdropBack;
504     protected final PorterDuffXfermode mSrcXferMode = new PorterDuffXfermode(PorterDuff.Mode.SRC);
505     protected final PorterDuffXfermode mSrcOverXferMode =
506             new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER);
507 
508     private NotificationMediaManager mMediaManager;
509     protected NotificationLockscreenUserManager mLockscreenUserManager;
510     protected NotificationRemoteInputManager mRemoteInputManager;
511 
512     private BroadcastReceiver mWallpaperChangedReceiver = new BroadcastReceiver() {
513         @Override
514         public void onReceive(Context context, Intent intent) {
515             WallpaperManager wallpaperManager = context.getSystemService(WallpaperManager.class);
516             if (wallpaperManager == null) {
517                 Log.w(TAG, "WallpaperManager not available");
518                 return;
519             }
520             WallpaperInfo info = wallpaperManager.getWallpaperInfo();
521             final boolean supportsAmbientMode = info != null &&
522                     info.getSupportsAmbientMode();
523 
524             mStatusBarWindowManager.setWallpaperSupportsAmbientMode(supportsAmbientMode);
525             mScrimController.setWallpaperSupportsAmbientMode(supportsAmbientMode);
526         }
527     };
528 
529     private Runnable mLaunchTransitionEndRunnable;
530     protected boolean mLaunchTransitionFadingAway;
531     private ExpandableNotificationRow mDraggedDownRow;
532     private boolean mLaunchCameraOnScreenTurningOn;
533     private boolean mLaunchCameraOnFinishedGoingToSleep;
534     private int mLastCameraLaunchSource;
535     private PowerManager.WakeLock mGestureWakeLock;
536     private Vibrator mVibrator;
537     private long[] mCameraLaunchGestureVibePattern;
538 
539     private final int[] mTmpInt2 = new int[2];
540 
541     // Fingerprint (as computed by getLoggingFingerprint() of the last logged state.
542     private int mLastLoggedStateFingerprint;
543     private boolean mTopHidesStatusBar;
544     private boolean mStatusBarWindowHidden;
545     private boolean mHideIconsForBouncer;
546     private boolean mIsOccluded;
547     private boolean mWereIconsJustHidden;
548     private boolean mBouncerWasShowingWhenHidden;
549 
550     // Notifies StatusBarKeyguardViewManager every time the keyguard transition is over,
551     // this animation is tied to the scrim for historic reasons.
552     // TODO: notify when keyguard has faded away instead of the scrim.
553     private final ScrimController.Callback mUnlockScrimCallback = new ScrimController
554             .Callback() {
555         @Override
556         public void onFinished() {
557             if (mStatusBarKeyguardViewManager == null) {
558                 Log.w(TAG, "Tried to notify keyguard visibility when "
559                         + "mStatusBarKeyguardViewManager was null");
560                 return;
561             }
562             if (mKeyguardFadingAway) {
563                 mStatusBarKeyguardViewManager.onKeyguardFadedAway();
564             }
565         }
566 
567         @Override
568         public void onCancelled() {
569             onFinished();
570         }
571     };
572 
573     private KeyguardUserSwitcher mKeyguardUserSwitcher;
574     protected UserSwitcherController mUserSwitcherController;
575     private NetworkController mNetworkController;
576     private KeyguardMonitorImpl mKeyguardMonitor
577             = (KeyguardMonitorImpl) Dependency.get(KeyguardMonitor.class);
578     private BatteryController mBatteryController;
579     protected boolean mPanelExpanded;
580     private IOverlayManager mOverlayManager;
581     private boolean mKeyguardRequested;
582     private boolean mIsKeyguard;
583     private LogMaker mStatusBarStateLog;
584     private final LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
585     protected NotificationIconAreaController mNotificationIconAreaController;
586     private boolean mReinflateNotificationsOnUserSwitched;
587     protected boolean mClearAllEnabled;
588     @Nullable private View mAmbientIndicationContainer;
589     private SysuiColorExtractor mColorExtractor;
590     private ScreenLifecycle mScreenLifecycle;
591     @VisibleForTesting WakefulnessLifecycle mWakefulnessLifecycle;
592 
593     private final View.OnClickListener mGoToLockedShadeListener = v -> {
594         if (mState == StatusBarState.KEYGUARD) {
595             wakeUpIfDozing(SystemClock.uptimeMillis(), v);
596             goToLockedShade(null);
597         }
598     };
599     private boolean mNoAnimationOnNextBarModeChange;
600     protected FalsingManager mFalsingManager;
601 
602     private final KeyguardUpdateMonitorCallback mUpdateCallback =
603             new KeyguardUpdateMonitorCallback() {
604                 @Override
605                 public void onDreamingStateChanged(boolean dreaming) {
606                     if (dreaming) {
607                         maybeEscalateHeadsUp();
608                     }
609                 }
610 
611                 @Override
612                 public void onStrongAuthStateChanged(int userId) {
613                     super.onStrongAuthStateChanged(userId);
614                     mEntryManager.updateNotifications();
615                 }
616             };
617 
618     private NavigationBarFragment mNavigationBar;
619     private View mNavigationBarView;
620     protected ActivityLaunchAnimator mActivityLaunchAnimator;
621     private HeadsUpAppearanceController mHeadsUpAppearanceController;
622     private boolean mVibrateOnOpening;
623     private VibratorHelper mVibratorHelper;
624 
625     @Override
start()626     public void start() {
627         mGroupManager = Dependency.get(NotificationGroupManager.class);
628         mVisualStabilityManager = Dependency.get(VisualStabilityManager.class);
629         mNotificationLogger = Dependency.get(NotificationLogger.class);
630         mRemoteInputManager = Dependency.get(NotificationRemoteInputManager.class);
631         mNotificationListener =  Dependency.get(NotificationListener.class);
632         mGroupManager = Dependency.get(NotificationGroupManager.class);
633         mNetworkController = Dependency.get(NetworkController.class);
634         mUserSwitcherController = Dependency.get(UserSwitcherController.class);
635         mScreenLifecycle = Dependency.get(ScreenLifecycle.class);
636         mScreenLifecycle.addObserver(mScreenObserver);
637         mWakefulnessLifecycle = Dependency.get(WakefulnessLifecycle.class);
638         mWakefulnessLifecycle.addObserver(mWakefulnessObserver);
639         mBatteryController = Dependency.get(BatteryController.class);
640         mAssistManager = Dependency.get(AssistManager.class);
641         mOverlayManager = IOverlayManager.Stub.asInterface(
642                 ServiceManager.getService(Context.OVERLAY_SERVICE));
643         mLockscreenUserManager = Dependency.get(NotificationLockscreenUserManager.class);
644         mGutsManager = Dependency.get(NotificationGutsManager.class);
645         mMediaManager = Dependency.get(NotificationMediaManager.class);
646         mEntryManager = Dependency.get(NotificationEntryManager.class);
647         mViewHierarchyManager = Dependency.get(NotificationViewHierarchyManager.class);
648         mAppOpsListener = Dependency.get(AppOpsListener.class);
649         mAppOpsListener.setUpWithPresenter(this, mEntryManager);
650         mZenController = Dependency.get(ZenModeController.class);
651         mKeyguardViewMediator = getComponent(KeyguardViewMediator.class);
652 
653         mColorExtractor = Dependency.get(SysuiColorExtractor.class);
654         mColorExtractor.addOnColorsChangedListener(this);
655 
656         mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
657 
658         mDisplay = mWindowManager.getDefaultDisplay();
659         updateDisplaySize();
660 
661         Resources res = mContext.getResources();
662         mVibrateOnOpening = mContext.getResources().getBoolean(
663                 R.bool.config_vibrateOnIconAnimation);
664         mVibratorHelper = Dependency.get(VibratorHelper.class);
665         mScrimSrcModeEnabled = res.getBoolean(R.bool.config_status_bar_scrim_behind_use_src);
666         mClearAllEnabled = res.getBoolean(R.bool.config_enableNotificationsClearAll);
667 
668         DateTimeView.setReceiverHandler(Dependency.get(Dependency.TIME_TICK_HANDLER));
669         putComponent(StatusBar.class, this);
670 
671         // start old BaseStatusBar.start().
672         mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
673         mDevicePolicyManager = (DevicePolicyManager) mContext.getSystemService(
674                 Context.DEVICE_POLICY_SERVICE);
675 
676         mAccessibilityManager = (AccessibilityManager)
677                 mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
678 
679         mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
680 
681         mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
682 
683         mBarService = IStatusBarService.Stub.asInterface(
684                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
685 
686         mRecents = getComponent(Recents.class);
687 
688         mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
689         mLockPatternUtils = new LockPatternUtils(mContext);
690 
691         mMediaManager.setUpWithPresenter(this, mEntryManager);
692 
693         // Connect in to the status bar manager service
694         mCommandQueue = getComponent(CommandQueue.class);
695         mCommandQueue.addCallbacks(this);
696 
697         int[] switches = new int[9];
698         ArrayList<IBinder> binders = new ArrayList<>();
699         ArrayList<String> iconSlots = new ArrayList<>();
700         ArrayList<StatusBarIcon> icons = new ArrayList<>();
701         Rect fullscreenStackBounds = new Rect();
702         Rect dockedStackBounds = new Rect();
703         try {
704             mBarService.registerStatusBar(mCommandQueue, iconSlots, icons, switches, binders,
705                     fullscreenStackBounds, dockedStackBounds);
706         } catch (RemoteException ex) {
707             // If the system process isn't there we're doomed anyway.
708         }
709 
710         createAndAddWindows();
711 
712         // Make sure we always have the most current wallpaper info.
713         IntentFilter wallpaperChangedFilter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED);
714         mContext.registerReceiver(mWallpaperChangedReceiver, wallpaperChangedFilter);
715         mWallpaperChangedReceiver.onReceive(mContext, null);
716 
717         mLockscreenUserManager.setUpWithPresenter(this, mEntryManager);
718         mCommandQueue.disable(switches[0], switches[6], false /* animate */);
719         setSystemUiVisibility(switches[1], switches[7], switches[8], 0xffffffff,
720                 fullscreenStackBounds, dockedStackBounds);
721         topAppWindowChanged(switches[2] != 0);
722         // StatusBarManagerService has a back up of IME token and it's restored here.
723         setImeWindowStatus(binders.get(0), switches[3], switches[4], switches[5] != 0);
724 
725         // Set up the initial icon state
726         int N = iconSlots.size();
727         for (int i=0; i < N; i++) {
728             mCommandQueue.setIcon(iconSlots.get(i), icons.get(i));
729         }
730 
731         // Set up the initial notification state.
732         mNotificationListener.setUpWithPresenter(this, mEntryManager);
733 
734         if (DEBUG) {
735             Log.d(TAG, String.format(
736                     "init: icons=%d disabled=0x%08x lights=0x%08x menu=0x%08x imeButton=0x%08x",
737                    icons.size(),
738                    switches[0],
739                    switches[1],
740                    switches[2],
741                    switches[3]
742                    ));
743         }
744 
745         setHeadsUpUser(mLockscreenUserManager.getCurrentUserId());
746 
747         IntentFilter internalFilter = new IntentFilter();
748         internalFilter.addAction(BANNER_ACTION_CANCEL);
749         internalFilter.addAction(BANNER_ACTION_SETUP);
750         mContext.registerReceiver(mBannerActionBroadcastReceiver, internalFilter, PERMISSION_SELF,
751                 null);
752 
753         IVrManager vrManager = IVrManager.Stub.asInterface(ServiceManager.getService(
754                 Context.VR_SERVICE));
755         try {
756             vrManager.registerListener(mVrStateCallbacks);
757         } catch (RemoteException e) {
758             Slog.e(TAG, "Failed to register VR mode state listener: " + e);
759         }
760 
761         IWallpaperManager wallpaperManager = IWallpaperManager.Stub.asInterface(
762                 ServiceManager.getService(Context.WALLPAPER_SERVICE));
763         try {
764             wallpaperManager.setInAmbientMode(false /* ambientMode */, false /* animated */);
765         } catch (RemoteException e) {
766             // Just pass, nothing critical.
767         }
768 
769         // end old BaseStatusBar.start().
770 
771         // Lastly, call to the icon policy to install/update all the icons.
772         mIconPolicy = new PhoneStatusBarPolicy(mContext, mIconController);
773         mSignalPolicy = new StatusBarSignalPolicy(mContext, mIconController);
774 
775         mUnlockMethodCache = UnlockMethodCache.getInstance(mContext);
776         mUnlockMethodCache.addListener(this);
777         startKeyguard();
778 
779         KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateCallback);
780         putComponent(DozeHost.class, mDozeServiceHost);
781 
782         mScreenPinningRequest = new ScreenPinningRequest(mContext);
783         mFalsingManager = FalsingManager.getInstance(mContext);
784 
785         Dependency.get(ActivityStarterDelegate.class).setActivityStarterImpl(this);
786 
787         Dependency.get(ConfigurationController.class).addCallback(this);
788     }
789 
790     // ================================================================================
791     // Constructing the view
792     // ================================================================================
makeStatusBarView()793     protected void makeStatusBarView() {
794         final Context context = mContext;
795         updateDisplaySize(); // populates mDisplayMetrics
796         updateResources();
797         updateTheme();
798 
799         inflateStatusBarWindow(context);
800         mStatusBarWindow.setService(this);
801         mStatusBarWindow.setOnTouchListener(getStatusBarWindowTouchListener());
802 
803         // TODO: Deal with the ugliness that comes from having some of the statusbar broken out
804         // into fragments, but the rest here, it leaves some awkward lifecycle and whatnot.
805         mNotificationPanel = mStatusBarWindow.findViewById(R.id.notification_panel);
806         mStackScroller = mStatusBarWindow.findViewById(R.id.notification_stack_scroller);
807         mZenController.addCallback(this);
808         mActivityLaunchAnimator = new ActivityLaunchAnimator(mStatusBarWindow,
809                 this,
810                 mNotificationPanel,
811                 mStackScroller);
812         mGutsManager.setUpWithPresenter(this, mEntryManager, mStackScroller, mCheckSaveListener,
813                 key -> {
814                     try {
815                         mBarService.onNotificationSettingsViewed(key);
816                     } catch (RemoteException e) {
817                         // if we're here we're dead
818                     }
819                 });
820         mNotificationLogger.setUpWithEntryManager(mEntryManager, mStackScroller);
821         mNotificationPanel.setStatusBar(this);
822         mNotificationPanel.setGroupManager(mGroupManager);
823         mAboveShelfObserver = new AboveShelfObserver(mStackScroller);
824         mAboveShelfObserver.setListener(mStatusBarWindow.findViewById(
825                 R.id.notification_container_parent));
826         mKeyguardStatusBar = mStatusBarWindow.findViewById(R.id.keyguard_header);
827 
828         mNotificationIconAreaController = SystemUIFactory.getInstance()
829                 .createNotificationIconAreaController(context, this);
830         inflateShelf();
831         mNotificationIconAreaController.setupShelf(mNotificationShelf);
832         Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mNotificationIconAreaController);
833         FragmentHostManager.get(mStatusBarWindow)
834                 .addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> {
835                     CollapsedStatusBarFragment statusBarFragment =
836                             (CollapsedStatusBarFragment) fragment;
837                     statusBarFragment.initNotificationIconArea(mNotificationIconAreaController);
838                     mStatusBarView = (PhoneStatusBarView) fragment.getView();
839                     mStatusBarView.setBar(this);
840                     mStatusBarView.setPanel(mNotificationPanel);
841                     mStatusBarView.setScrimController(mScrimController);
842                     mStatusBarView.setBouncerShowing(mBouncerShowing);
843                     if (mHeadsUpAppearanceController != null) {
844                         // This view is being recreated, let's destroy the old one
845                         mHeadsUpAppearanceController.destroy();
846                     }
847                     mHeadsUpAppearanceController = new HeadsUpAppearanceController(
848                             mNotificationIconAreaController, mHeadsUpManager, mStatusBarWindow);
849                     setAreThereNotifications();
850                     checkBarModes();
851                 }).getFragmentManager()
852                 .beginTransaction()
853                 .replace(R.id.status_bar_container, new CollapsedStatusBarFragment(),
854                         CollapsedStatusBarFragment.TAG)
855                 .commit();
856         mIconController = Dependency.get(StatusBarIconController.class);
857 
858         mHeadsUpManager = new HeadsUpManagerPhone(context, mStatusBarWindow, mGroupManager, this,
859                 mVisualStabilityManager);
860         Dependency.get(ConfigurationController.class).addCallback(mHeadsUpManager);
861         mHeadsUpManager.addListener(this);
862         mHeadsUpManager.addListener(mNotificationPanel);
863         mHeadsUpManager.addListener(mGroupManager);
864         mHeadsUpManager.addListener(mVisualStabilityManager);
865         mNotificationPanel.setHeadsUpManager(mHeadsUpManager);
866         mGroupManager.setHeadsUpManager(mHeadsUpManager);
867         putComponent(HeadsUpManager.class, mHeadsUpManager);
868 
869         mEntryManager.setUpWithPresenter(this, mStackScroller, this, mHeadsUpManager);
870         mViewHierarchyManager.setUpWithPresenter(this, mEntryManager, mStackScroller);
871 
872         if (MULTIUSER_DEBUG) {
873             mNotificationPanelDebugText = mNotificationPanel.findViewById(R.id.header_debug_info);
874             mNotificationPanelDebugText.setVisibility(View.VISIBLE);
875         }
876 
877         try {
878             boolean showNav = mWindowManagerService.hasNavigationBar();
879             if (DEBUG) Log.v(TAG, "hasNavigationBar=" + showNav);
880             if (showNav) {
881                 createNavigationBar();
882             }
883         } catch (RemoteException ex) {
884             // no window manager? good luck with that
885         }
886         mScreenPinningNotify = new ScreenPinningNotify(mContext);
887         mStackScroller.setLongPressListener(mEntryManager.getNotificationLongClicker());
888         mStackScroller.setStatusBar(this);
889         mStackScroller.setGroupManager(mGroupManager);
890         mStackScroller.setHeadsUpManager(mHeadsUpManager);
891         mGroupManager.setOnGroupChangeListener(mStackScroller);
892         mVisualStabilityManager.setVisibilityLocationProvider(mStackScroller);
893 
894         inflateEmptyShadeView();
895         inflateFooterView();
896 
897         mBackdrop = mStatusBarWindow.findViewById(R.id.backdrop);
898         mBackdropFront = mBackdrop.findViewById(R.id.backdrop_front);
899         mBackdropBack = mBackdrop.findViewById(R.id.backdrop_back);
900 
901         if (ENABLE_LOCKSCREEN_WALLPAPER) {
902             mLockscreenWallpaper = new LockscreenWallpaper(mContext, this, mHandler);
903         }
904 
905         mKeyguardIndicationController =
906                 SystemUIFactory.getInstance().createKeyguardIndicationController(mContext,
907                         mStatusBarWindow.findViewById(R.id.keyguard_indication_area),
908                         mNotificationPanel.getLockIcon());
909         mNotificationPanel.setKeyguardIndicationController(mKeyguardIndicationController);
910 
911 
912         mAmbientIndicationContainer = mStatusBarWindow.findViewById(
913                 R.id.ambient_indication_container);
914 
915         // set the initial view visibility
916         setAreThereNotifications();
917 
918         // TODO: Find better place for this callback.
919         mBatteryController.addCallback(new BatteryStateChangeCallback() {
920             @Override
921             public void onPowerSaveChanged(boolean isPowerSave) {
922                 mHandler.post(mCheckBarModes);
923                 if (mDozeServiceHost != null) {
924                     mDozeServiceHost.firePowerSaveChanged(isPowerSave);
925                 }
926             }
927 
928             @Override
929             public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
930                 // noop
931             }
932         });
933 
934         mLightBarController = Dependency.get(LightBarController.class);
935         if (mNavigationBar != null) {
936             mNavigationBar.setLightBarController(mLightBarController);
937         }
938 
939         ScrimView scrimBehind = mStatusBarWindow.findViewById(R.id.scrim_behind);
940         ScrimView scrimInFront = mStatusBarWindow.findViewById(R.id.scrim_in_front);
941         mScrimController = SystemUIFactory.getInstance().createScrimController(
942                 scrimBehind, scrimInFront, mLockscreenWallpaper,
943                 (state, alpha, color) -> mLightBarController.setScrimState(state, alpha, color),
944                 scrimsVisible -> {
945                     if (mStatusBarWindowManager != null) {
946                         mStatusBarWindowManager.setScrimsVisibility(scrimsVisible);
947                     }
948                 }, DozeParameters.getInstance(mContext),
949                 mContext.getSystemService(AlarmManager.class));
950         if (mScrimSrcModeEnabled) {
951             Runnable runnable = () -> {
952                 boolean asSrc = mBackdrop.getVisibility() != View.VISIBLE;
953                 mScrimController.setDrawBehindAsSrc(asSrc);
954                 mStackScroller.setDrawBackgroundAsSrc(asSrc);
955             };
956             mBackdrop.setOnVisibilityChangedRunnable(runnable);
957             runnable.run();
958         }
959         mStackScroller.setScrimController(mScrimController);
960         mDozeScrimController = new DozeScrimController(mScrimController, context,
961                 DozeParameters.getInstance(context));
962 
963         // Other icons
964         mVolumeComponent = getComponent(VolumeComponent.class);
965 
966         mNotificationPanel.setUserSetupComplete(mUserSetup);
967         if (UserManager.get(mContext).isUserSwitcherEnabled()) {
968             createUserSwitcher();
969         }
970 
971         // Set up the quick settings tile panel
972         View container = mStatusBarWindow.findViewById(R.id.qs_frame);
973         if (container != null) {
974             FragmentHostManager fragmentHostManager = FragmentHostManager.get(container);
975             ExtensionFragmentListener.attachExtensonToFragment(container, QS.TAG, R.id.qs_frame,
976                     Dependency.get(ExtensionController.class)
977                             .newExtension(QS.class)
978                             .withPlugin(QS.class)
979                             .withFeature(PackageManager.FEATURE_AUTOMOTIVE, CarQSFragment::new)
980                             .withDefault(QSFragment::new)
981                             .build());
982             final QSTileHost qsh = SystemUIFactory.getInstance().createQSTileHost(mContext, this,
983                     mIconController);
984             mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow,
985                     (visible) -> {
986                         mBrightnessMirrorVisible = visible;
987                         updateScrimController();
988                     });
989             fragmentHostManager.addTagListener(QS.TAG, (tag, f) -> {
990                 QS qs = (QS) f;
991                 if (qs instanceof QSFragment) {
992                     ((QSFragment) qs).setHost(qsh);
993                     mQSPanel = ((QSFragment) qs).getQsPanel();
994                     mQSPanel.setBrightnessMirror(mBrightnessMirrorController);
995                     mKeyguardStatusBar.setQSPanel(mQSPanel);
996                 }
997             });
998         }
999 
1000         mReportRejectedTouch = mStatusBarWindow.findViewById(R.id.report_rejected_touch);
1001         if (mReportRejectedTouch != null) {
1002             updateReportRejectedTouchVisibility();
1003             mReportRejectedTouch.setOnClickListener(v -> {
1004                 Uri session = mFalsingManager.reportRejectedTouch();
1005                 if (session == null) { return; }
1006 
1007                 StringWriter message = new StringWriter();
1008                 message.write("Build info: ");
1009                 message.write(SystemProperties.get("ro.build.description"));
1010                 message.write("\nSerial number: ");
1011                 message.write(SystemProperties.get("ro.serialno"));
1012                 message.write("\n");
1013 
1014                 PrintWriter falsingPw = new PrintWriter(message);
1015                 FalsingLog.dump(falsingPw);
1016                 falsingPw.flush();
1017 
1018                 startActivityDismissingKeyguard(Intent.createChooser(new Intent(Intent.ACTION_SEND)
1019                                 .setType("*/*")
1020                                 .putExtra(Intent.EXTRA_SUBJECT, "Rejected touch report")
1021                                 .putExtra(Intent.EXTRA_STREAM, session)
1022                                 .putExtra(Intent.EXTRA_TEXT, message.toString()),
1023                         "Share rejected touch report")
1024                                 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK),
1025                         true /* onlyProvisioned */, true /* dismissShade */);
1026             });
1027         }
1028 
1029         PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
1030         if (!pm.isScreenOn()) {
1031             mBroadcastReceiver.onReceive(mContext, new Intent(Intent.ACTION_SCREEN_OFF));
1032         }
1033         mGestureWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
1034                 "GestureWakeLock");
1035         mVibrator = mContext.getSystemService(Vibrator.class);
1036         int[] pattern = mContext.getResources().getIntArray(
1037                 R.array.config_cameraLaunchGestureVibePattern);
1038         mCameraLaunchGestureVibePattern = new long[pattern.length];
1039         for (int i = 0; i < pattern.length; i++) {
1040             mCameraLaunchGestureVibePattern[i] = pattern[i];
1041         }
1042 
1043         // receive broadcasts
1044         IntentFilter filter = new IntentFilter();
1045         filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
1046         filter.addAction(Intent.ACTION_SCREEN_OFF);
1047         filter.addAction(DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG);
1048         context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
1049 
1050         IntentFilter demoFilter = new IntentFilter();
1051         if (DEBUG_MEDIA_FAKE_ARTWORK) {
1052             demoFilter.addAction(ACTION_FAKE_ARTWORK);
1053         }
1054         demoFilter.addAction(ACTION_DEMO);
1055         context.registerReceiverAsUser(mDemoReceiver, UserHandle.ALL, demoFilter,
1056                 android.Manifest.permission.DUMP, null);
1057 
1058         // listen for USER_SETUP_COMPLETE setting (per-user)
1059         mDeviceProvisionedController.addCallback(mUserSetupObserver);
1060         mUserSetupObserver.onUserSetupChanged();
1061 
1062         // disable profiling bars, since they overlap and clutter the output on app windows
1063         ThreadedRenderer.overrideProperty("disableProfileBars", "true");
1064 
1065         // Private API call to make the shadows look better for Recents
1066         ThreadedRenderer.overrideProperty("ambientRatio", String.valueOf(1.5f));
1067     }
1068 
createNavigationBar()1069     protected void createNavigationBar() {
1070         mNavigationBarView = NavigationBarFragment.create(mContext, (tag, fragment) -> {
1071             mNavigationBar = (NavigationBarFragment) fragment;
1072             if (mLightBarController != null) {
1073                 mNavigationBar.setLightBarController(mLightBarController);
1074             }
1075             mNavigationBar.setCurrentSysuiVisibility(mSystemUiVisibility);
1076         });
1077     }
1078 
1079     /**
1080      * Returns the {@link android.view.View.OnTouchListener} that will be invoked when the
1081      * background window of the status bar is clicked.
1082      */
getStatusBarWindowTouchListener()1083     protected View.OnTouchListener getStatusBarWindowTouchListener() {
1084         return (v, event) -> {
1085             checkUserAutohide(event);
1086             mRemoteInputManager.checkRemoteInputOutside(event);
1087             if (event.getAction() == MotionEvent.ACTION_DOWN) {
1088                 if (mExpandedVisible) {
1089                     animateCollapsePanels();
1090                 }
1091             }
1092             return mStatusBarWindow.onTouchEvent(event);
1093         };
1094     }
1095 
inflateShelf()1096     private void inflateShelf() {
1097         mNotificationShelf =
1098                 (NotificationShelf) LayoutInflater.from(mContext).inflate(
1099                         R.layout.status_bar_notification_shelf, mStackScroller, false);
1100         mNotificationShelf.setOnActivatedListener(this);
1101         mStackScroller.setShelf(mNotificationShelf);
1102         mNotificationShelf.setOnClickListener(mGoToLockedShadeListener);
1103         mNotificationShelf.setStatusBarState(mState);
1104     }
1105 
onDensityOrFontScaleChanged()1106     public void onDensityOrFontScaleChanged() {
1107         MessagingMessage.dropCache();
1108         MessagingGroup.dropCache();
1109         // start old BaseStatusBar.onDensityOrFontScaleChanged().
1110         if (!KeyguardUpdateMonitor.getInstance(mContext).isSwitchingUser()) {
1111             mEntryManager.updateNotificationsOnDensityOrFontScaleChanged();
1112         } else {
1113             mReinflateNotificationsOnUserSwitched = true;
1114         }
1115         // end old BaseStatusBar.onDensityOrFontScaleChanged().
1116         // TODO: Remove this.
1117         if (mBrightnessMirrorController != null) {
1118             mBrightnessMirrorController.onDensityOrFontScaleChanged();
1119         }
1120         mStatusBarKeyguardViewManager.onDensityOrFontScaleChanged();
1121         // TODO: Bring these out of StatusBar.
1122         ((UserInfoControllerImpl) Dependency.get(UserInfoController.class))
1123                 .onDensityOrFontScaleChanged();
1124         Dependency.get(UserSwitcherController.class).onDensityOrFontScaleChanged();
1125         if (mKeyguardUserSwitcher != null) {
1126             mKeyguardUserSwitcher.onDensityOrFontScaleChanged();
1127         }
1128         mNotificationIconAreaController.onDensityOrFontScaleChanged(mContext);
1129         mHeadsUpManager.onDensityOrFontScaleChanged();
1130 
1131         reevaluateStyles();
1132     }
1133 
onThemeChanged()1134     private void onThemeChanged() {
1135         reevaluateStyles();
1136 
1137         // Clock and bottom icons
1138         mNotificationPanel.onThemeChanged();
1139         // The status bar on the keyguard is a special layout.
1140         if (mKeyguardStatusBar != null) mKeyguardStatusBar.onThemeChanged();
1141         // Recreate Indication controller because internal references changed
1142         mKeyguardIndicationController =
1143                 SystemUIFactory.getInstance().createKeyguardIndicationController(mContext,
1144                         mStatusBarWindow.findViewById(R.id.keyguard_indication_area),
1145                         mNotificationPanel.getLockIcon());
1146         mNotificationPanel.setKeyguardIndicationController(mKeyguardIndicationController);
1147         mKeyguardIndicationController
1148                 .setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
1149         mKeyguardIndicationController.setVisible(mState == StatusBarState.KEYGUARD);
1150         mKeyguardIndicationController.setDozing(mDozing);
1151         if (mStatusBarKeyguardViewManager != null) {
1152             mStatusBarKeyguardViewManager.onThemeChanged();
1153         }
1154         if (mAmbientIndicationContainer instanceof AutoReinflateContainer) {
1155             ((AutoReinflateContainer) mAmbientIndicationContainer).inflateLayout();
1156         }
1157     }
1158 
reevaluateStyles()1159     protected void reevaluateStyles() {
1160         inflateFooterView();
1161         updateFooter();
1162         inflateEmptyShadeView();
1163         updateEmptyShadeView();
1164     }
1165 
1166     @Override
onOverlayChanged()1167     public void onOverlayChanged() {
1168         if (mBrightnessMirrorController != null) {
1169             mBrightnessMirrorController.onOverlayChanged();
1170         }
1171     }
1172 
inflateEmptyShadeView()1173     private void inflateEmptyShadeView() {
1174         if (mStackScroller == null) {
1175             return;
1176         }
1177         mEmptyShadeView = (EmptyShadeView) LayoutInflater.from(mContext).inflate(
1178                 R.layout.status_bar_no_notifications, mStackScroller, false);
1179         mEmptyShadeView.setText(R.string.empty_shade_text);
1180         mStackScroller.setEmptyShadeView(mEmptyShadeView);
1181     }
1182 
inflateFooterView()1183     private void inflateFooterView() {
1184         if (mStackScroller == null) {
1185             return;
1186         }
1187 
1188         mFooterView = (FooterView) LayoutInflater.from(mContext).inflate(
1189                 R.layout.status_bar_notification_footer, mStackScroller, false);
1190         mFooterView.setDismissButtonClickListener(v -> {
1191             mMetricsLogger.action(MetricsEvent.ACTION_DISMISS_ALL_NOTES);
1192             clearAllNotifications();
1193         });
1194         mFooterView.setManageButtonClickListener(v -> {
1195             manageNotifications();
1196         });
1197         mStackScroller.setFooterView(mFooterView);
1198     }
1199 
createUserSwitcher()1200     protected void createUserSwitcher() {
1201         mKeyguardUserSwitcher = new KeyguardUserSwitcher(mContext,
1202                 mStatusBarWindow.findViewById(R.id.keyguard_user_switcher), mKeyguardStatusBar,
1203                 mNotificationPanel);
1204     }
1205 
inflateStatusBarWindow(Context context)1206     protected void inflateStatusBarWindow(Context context) {
1207         mStatusBarWindow = (StatusBarWindowView) View.inflate(context,
1208                 R.layout.super_status_bar, null);
1209     }
1210 
manageNotifications()1211     public void manageNotifications() {
1212         Intent intent = new Intent(Settings.ACTION_ALL_APPS_NOTIFICATION_SETTINGS);
1213         startActivity(intent, true, true, Intent.FLAG_ACTIVITY_SINGLE_TOP);
1214     }
1215 
clearAllNotifications()1216     public void clearAllNotifications() {
1217         // animate-swipe all dismissable notifications, then animate the shade closed
1218         int numChildren = mStackScroller.getChildCount();
1219 
1220         final ArrayList<View> viewsToHide = new ArrayList<>(numChildren);
1221         final ArrayList<ExpandableNotificationRow> viewsToRemove = new ArrayList<>(numChildren);
1222         for (int i = 0; i < numChildren; i++) {
1223             final View child = mStackScroller.getChildAt(i);
1224             if (child instanceof ExpandableNotificationRow) {
1225                 ExpandableNotificationRow row = (ExpandableNotificationRow) child;
1226                 boolean parentVisible = false;
1227                 boolean hasClipBounds = child.getClipBounds(mTmpRect);
1228                 if (mStackScroller.canChildBeDismissed(child)) {
1229                     viewsToRemove.add(row);
1230                     if (child.getVisibility() == View.VISIBLE
1231                             && (!hasClipBounds || mTmpRect.height() > 0)) {
1232                         viewsToHide.add(child);
1233                         parentVisible = true;
1234                     }
1235                 } else if (child.getVisibility() == View.VISIBLE
1236                         && (!hasClipBounds || mTmpRect.height() > 0)) {
1237                     parentVisible = true;
1238                 }
1239                 List<ExpandableNotificationRow> children = row.getNotificationChildren();
1240                 if (children != null) {
1241                     for (ExpandableNotificationRow childRow : children) {
1242                         viewsToRemove.add(childRow);
1243                         if (parentVisible && row.areChildrenExpanded()
1244                                 && mStackScroller.canChildBeDismissed(childRow)) {
1245                             hasClipBounds = childRow.getClipBounds(mTmpRect);
1246                             if (childRow.getVisibility() == View.VISIBLE
1247                                     && (!hasClipBounds || mTmpRect.height() > 0)) {
1248                                 viewsToHide.add(childRow);
1249                             }
1250                         }
1251                     }
1252                 }
1253             }
1254         }
1255         if (viewsToRemove.isEmpty()) {
1256             animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
1257             return;
1258         }
1259 
1260         addPostCollapseAction(() -> {
1261             mStackScroller.setDismissAllInProgress(false);
1262             for (ExpandableNotificationRow rowToRemove : viewsToRemove) {
1263                 if (mStackScroller.canChildBeDismissed(rowToRemove)) {
1264                     mEntryManager.removeNotification(rowToRemove.getEntry().key, null);
1265                 } else {
1266                     rowToRemove.resetTranslation();
1267                 }
1268             }
1269             try {
1270                 mBarService.onClearAllNotifications(mLockscreenUserManager.getCurrentUserId());
1271             } catch (Exception ex) {
1272             }
1273         });
1274 
1275         performDismissAllAnimations(viewsToHide);
1276 
1277     }
1278 
performDismissAllAnimations(ArrayList<View> hideAnimatedList)1279     private void performDismissAllAnimations(ArrayList<View> hideAnimatedList) {
1280         Runnable animationFinishAction = () -> {
1281             animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
1282         };
1283 
1284         if (hideAnimatedList.isEmpty()) {
1285             animationFinishAction.run();
1286             return;
1287         }
1288 
1289         // let's disable our normal animations
1290         mStackScroller.setDismissAllInProgress(true);
1291 
1292         // Decrease the delay for every row we animate to give the sense of
1293         // accelerating the swipes
1294         int rowDelayDecrement = 10;
1295         int currentDelay = 140;
1296         int totalDelay = 180;
1297         int numItems = hideAnimatedList.size();
1298         for (int i = numItems - 1; i >= 0; i--) {
1299             View view = hideAnimatedList.get(i);
1300             Runnable endRunnable = null;
1301             if (i == 0) {
1302                 endRunnable = animationFinishAction;
1303             }
1304             mStackScroller.dismissViewAnimated(view, endRunnable, totalDelay, 260);
1305             currentDelay = Math.max(50, currentDelay - rowDelayDecrement);
1306             totalDelay += currentDelay;
1307         }
1308     }
1309 
startKeyguard()1310     protected void startKeyguard() {
1311         Trace.beginSection("StatusBar#startKeyguard");
1312         KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class);
1313         mFingerprintUnlockController = new FingerprintUnlockController(mContext,
1314                 mDozeScrimController, keyguardViewMediator,
1315                 mScrimController, this, UnlockMethodCache.getInstance(mContext));
1316         mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this,
1317                 getBouncerContainer(), mNotificationPanel, mFingerprintUnlockController);
1318         mKeyguardIndicationController
1319                 .setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
1320         mFingerprintUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
1321         mRemoteInputManager.getController().addCallback(mStatusBarKeyguardViewManager);
1322 
1323         mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback();
1324         mLightBarController.setFingerprintUnlockController(mFingerprintUnlockController);
1325         Dependency.get(KeyguardDismissUtil.class).setDismissHandler(this::executeWhenUnlocked);
1326         Trace.endSection();
1327     }
1328 
getStatusBarView()1329     protected View getStatusBarView() {
1330         return mStatusBarView;
1331     }
1332 
getStatusBarWindow()1333     public StatusBarWindowView getStatusBarWindow() {
1334         return mStatusBarWindow;
1335     }
1336 
getBouncerContainer()1337     protected ViewGroup getBouncerContainer() {
1338         return mStatusBarWindow;
1339     }
1340 
getStatusBarHeight()1341     public int getStatusBarHeight() {
1342         if (mNaturalBarHeight < 0) {
1343             final Resources res = mContext.getResources();
1344             mNaturalBarHeight =
1345                     res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
1346         }
1347         return mNaturalBarHeight;
1348     }
1349 
toggleSplitScreenMode(int metricsDockAction, int metricsUndockAction)1350     protected boolean toggleSplitScreenMode(int metricsDockAction, int metricsUndockAction) {
1351         if (mRecents == null) {
1352             return false;
1353         }
1354         int dockSide = WindowManagerProxy.getInstance().getDockSide();
1355         if (dockSide == WindowManager.DOCKED_INVALID) {
1356             final int navbarPos = WindowManagerWrapper.getInstance().getNavBarPosition();
1357             if (navbarPos == NAV_BAR_POS_INVALID) {
1358                 return false;
1359             }
1360             int createMode = navbarPos == NAV_BAR_POS_LEFT
1361                     ? ActivityManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT
1362                     : ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
1363             return mRecents.splitPrimaryTask(NavigationBarGestureHelper.DRAG_MODE_NONE, createMode,
1364                     null, metricsDockAction);
1365         } else {
1366             Divider divider = getComponent(Divider.class);
1367             if (divider != null && divider.isMinimized() && !divider.isHomeStackResizable()) {
1368                 // Undocking from the minimized state is not supported
1369                 return false;
1370             } else {
1371                 EventBus.getDefault().send(new UndockingTaskEvent());
1372                 if (metricsUndockAction != -1) {
1373                     mMetricsLogger.action(metricsUndockAction);
1374                 }
1375             }
1376         }
1377         return true;
1378     }
1379 
1380     @Override
onPerformRemoveNotification(StatusBarNotification n)1381     public void onPerformRemoveNotification(StatusBarNotification n) {
1382         if (mStackScroller.hasPulsingNotifications() &&
1383                     !mHeadsUpManager.hasHeadsUpNotifications()) {
1384             // We were showing a pulse for a notification, but no notifications are pulsing anymore.
1385             // Finish the pulse.
1386             mDozeScrimController.pulseOutNow();
1387         }
1388     }
1389 
1390     @Override
updateNotificationViews()1391     public void updateNotificationViews() {
1392         // The function updateRowStates depends on both of these being non-null, so check them here.
1393         // We may be called before they are set from DeviceProvisionedController's callback.
1394         if (mStackScroller == null || mScrimController == null) return;
1395 
1396         // Do not modify the notifications during collapse.
1397         if (isCollapsing()) {
1398             addPostCollapseAction(this::updateNotificationViews);
1399             return;
1400         }
1401 
1402         mViewHierarchyManager.updateNotificationViews();
1403 
1404         updateSpeedBumpIndex();
1405         updateFooter();
1406         updateEmptyShadeView();
1407 
1408         updateQsExpansionEnabled();
1409 
1410         // Let's also update the icons
1411         mNotificationIconAreaController.updateNotificationIcons();
1412     }
1413 
1414     @Override
onNotificationAdded(Entry shadeEntry)1415     public void onNotificationAdded(Entry shadeEntry) {
1416         // Recalculate the position of the sliding windows and the titles.
1417         setAreThereNotifications();
1418     }
1419 
1420     @Override
onNotificationUpdated(StatusBarNotification notification)1421     public void onNotificationUpdated(StatusBarNotification notification) {
1422         setAreThereNotifications();
1423     }
1424 
1425     @Override
onNotificationRemoved(String key, StatusBarNotification old)1426     public void onNotificationRemoved(String key, StatusBarNotification old) {
1427         if (SPEW) Log.d(TAG, "removeNotification key=" + key + " old=" + old);
1428 
1429         if (old != null) {
1430             if (CLOSE_PANEL_WHEN_EMPTIED && !hasActiveNotifications()
1431                     && !mNotificationPanel.isTracking() && !mNotificationPanel.isQsExpanded()) {
1432                 if (mState == StatusBarState.SHADE) {
1433                     animateCollapsePanels();
1434                 } else if (mState == StatusBarState.SHADE_LOCKED && !isCollapsing()) {
1435                     goToKeyguard();
1436                 }
1437             }
1438         }
1439         setAreThereNotifications();
1440     }
1441 
1442     /**
1443      * Disable QS if device not provisioned.
1444      * If the user switcher is simple then disable QS during setup because
1445      * the user intends to use the lock screen user switcher, QS in not needed.
1446      */
updateQsExpansionEnabled()1447     private void updateQsExpansionEnabled() {
1448         mNotificationPanel.setQsExpansionEnabled(isDeviceProvisioned()
1449                 && (mUserSetup || mUserSwitcherController == null
1450                         || !mUserSwitcherController.isSimpleUserSwitcher())
1451                 && ((mDisabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) == 0)
1452                 && ((mDisabled2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) == 0)
1453                 && !mDozing
1454                 && !ONLY_CORE_APPS);
1455     }
1456 
addQsTile(ComponentName tile)1457     public void addQsTile(ComponentName tile) {
1458         if (mQSPanel != null && mQSPanel.getHost() != null) {
1459             mQSPanel.getHost().addTile(tile);
1460         }
1461     }
1462 
remQsTile(ComponentName tile)1463     public void remQsTile(ComponentName tile) {
1464         if (mQSPanel != null && mQSPanel.getHost() != null) {
1465             mQSPanel.getHost().removeTile(tile);
1466         }
1467     }
1468 
clickTile(ComponentName tile)1469     public void clickTile(ComponentName tile) {
1470         mQSPanel.clickTile(tile);
1471     }
1472 
1473     @VisibleForTesting
updateFooter()1474     protected void updateFooter() {
1475         boolean showDismissView = mClearAllEnabled && hasActiveClearableNotifications();
1476         boolean showFooterView = (showDismissView ||
1477                         mEntryManager.getNotificationData().getActiveNotifications().size() != 0)
1478                 && mState != StatusBarState.KEYGUARD
1479                 && !mRemoteInputManager.getController().isRemoteInputActive();
1480 
1481         mStackScroller.updateFooterView(showFooterView, showDismissView);
1482     }
1483 
1484     /**
1485      * Return whether there are any clearable notifications
1486      */
hasActiveClearableNotifications()1487     private boolean hasActiveClearableNotifications() {
1488         int childCount = mStackScroller.getChildCount();
1489         for (int i = 0; i < childCount; i++) {
1490             View child = mStackScroller.getChildAt(i);
1491             if (!(child instanceof ExpandableNotificationRow)) {
1492                 continue;
1493             }
1494             if (((ExpandableNotificationRow) child).canViewBeDismissed()) {
1495                     return true;
1496             }
1497         }
1498         return false;
1499     }
1500 
updateEmptyShadeView()1501     private void updateEmptyShadeView() {
1502         boolean showEmptyShadeView =
1503                 mState != StatusBarState.KEYGUARD &&
1504                         mEntryManager.getNotificationData().getActiveNotifications().size() == 0;
1505         mNotificationPanel.showEmptyShadeView(showEmptyShadeView);
1506     }
1507 
updateSpeedBumpIndex()1508     private void updateSpeedBumpIndex() {
1509         int speedBumpIndex = 0;
1510         int currentIndex = 0;
1511         final int N = mStackScroller.getChildCount();
1512         for (int i = 0; i < N; i++) {
1513             View view = mStackScroller.getChildAt(i);
1514             if (view.getVisibility() == View.GONE || !(view instanceof ExpandableNotificationRow)) {
1515                 continue;
1516             }
1517             ExpandableNotificationRow row = (ExpandableNotificationRow) view;
1518             currentIndex++;
1519             if (!mEntryManager.getNotificationData().isAmbient(
1520                     row.getStatusBarNotification().getKey())) {
1521                 speedBumpIndex = currentIndex;
1522             }
1523         }
1524         boolean noAmbient = speedBumpIndex == N;
1525         mStackScroller.updateSpeedBumpIndex(speedBumpIndex, noAmbient);
1526     }
1527 
isTopLevelChild(Entry entry)1528     public static boolean isTopLevelChild(Entry entry) {
1529         return entry.row.getParent() instanceof NotificationStackScrollLayout;
1530     }
1531 
areNotificationsHidden()1532     public boolean areNotificationsHidden() {
1533         return mZenController.areNotificationsHiddenInShade();
1534     }
1535 
requestNotificationUpdate()1536     public void requestNotificationUpdate() {
1537         mEntryManager.updateNotifications();
1538     }
1539 
setAreThereNotifications()1540     protected void setAreThereNotifications() {
1541 
1542         if (SPEW) {
1543             final boolean clearable = hasActiveNotifications() &&
1544                     hasActiveClearableNotifications();
1545             Log.d(TAG, "setAreThereNotifications: N=" +
1546                     mEntryManager.getNotificationData().getActiveNotifications().size() + " any=" +
1547                     hasActiveNotifications() + " clearable=" + clearable);
1548         }
1549 
1550         if (mStatusBarView != null) {
1551             final View nlo = mStatusBarView.findViewById(R.id.notification_lights_out);
1552             final boolean showDot = hasActiveNotifications() && !areLightsOn();
1553             if (showDot != (nlo.getAlpha() == 1.0f)) {
1554                 if (showDot) {
1555                     nlo.setAlpha(0f);
1556                     nlo.setVisibility(View.VISIBLE);
1557                 }
1558                 nlo.animate()
1559                         .alpha(showDot ? 1 : 0)
1560                         .setDuration(showDot ? 750 : 250)
1561                         .setInterpolator(new AccelerateInterpolator(2.0f))
1562                         .setListener(showDot ? null : new AnimatorListenerAdapter() {
1563                             @Override
1564                             public void onAnimationEnd(Animator _a) {
1565                                 nlo.setVisibility(View.GONE);
1566                             }
1567                         })
1568                         .start();
1569             }
1570         }
1571 
1572         mMediaManager.findAndUpdateMediaNotifications();
1573     }
1574 
1575 
1576     /**
1577      * Hide the album artwork that is fading out and release its bitmap.
1578      */
1579     protected final Runnable mHideBackdropFront = new Runnable() {
1580         @Override
1581         public void run() {
1582             if (DEBUG_MEDIA) {
1583                 Log.v(TAG, "DEBUG_MEDIA: removing fade layer");
1584             }
1585             mBackdropFront.setVisibility(View.INVISIBLE);
1586             mBackdropFront.animate().cancel();
1587             mBackdropFront.setImageDrawable(null);
1588         }
1589     };
1590 
1591     // TODO: Move this to NotificationMediaManager.
1592     /**
1593      * Refresh or remove lockscreen artwork from media metadata or the lockscreen wallpaper.
1594      */
1595     @Override
updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation)1596     public void updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation) {
1597         Trace.beginSection("StatusBar#updateMediaMetaData");
1598         if (!SHOW_LOCKSCREEN_MEDIA_ARTWORK) {
1599             Trace.endSection();
1600             return;
1601         }
1602 
1603         if (mBackdrop == null) {
1604             Trace.endSection();
1605             return; // called too early
1606         }
1607 
1608         boolean wakeAndUnlock = mFingerprintUnlockController != null
1609             && mFingerprintUnlockController.isWakeAndUnlock();
1610         if (mLaunchTransitionFadingAway || wakeAndUnlock) {
1611             mBackdrop.setVisibility(View.INVISIBLE);
1612             Trace.endSection();
1613             return;
1614         }
1615 
1616         MediaMetadata mediaMetadata = mMediaManager.getMediaMetadata();
1617 
1618         if (DEBUG_MEDIA) {
1619             Log.v(TAG, "DEBUG_MEDIA: updating album art for notification "
1620                     + mMediaManager.getMediaNotificationKey()
1621                     + " metadata=" + mediaMetadata
1622                     + " metaDataChanged=" + metaDataChanged
1623                     + " state=" + mState);
1624         }
1625 
1626         Drawable artworkDrawable = null;
1627         if (mediaMetadata != null) {
1628             Bitmap artworkBitmap = mediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ART);
1629             if (artworkBitmap == null) {
1630                 artworkBitmap = mediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
1631                 // might still be null
1632             }
1633             if (artworkBitmap != null) {
1634                 artworkDrawable = new BitmapDrawable(mBackdropBack.getResources(), artworkBitmap);
1635             }
1636         }
1637         boolean allowWhenShade = false;
1638         if (ENABLE_LOCKSCREEN_WALLPAPER && artworkDrawable == null) {
1639             Bitmap lockWallpaper = mLockscreenWallpaper.getBitmap();
1640             if (lockWallpaper != null) {
1641                 artworkDrawable = new LockscreenWallpaper.WallpaperDrawable(
1642                         mBackdropBack.getResources(), lockWallpaper);
1643                 // We're in the SHADE mode on the SIM screen - yet we still need to show
1644                 // the lockscreen wallpaper in that mode.
1645                 allowWhenShade = mStatusBarKeyguardViewManager != null
1646                         && mStatusBarKeyguardViewManager.isShowing();
1647             }
1648         }
1649 
1650         boolean hideBecauseOccluded = mStatusBarKeyguardViewManager != null
1651                 && mStatusBarKeyguardViewManager.isOccluded();
1652 
1653         final boolean hasArtwork = artworkDrawable != null;
1654 
1655         if ((hasArtwork || DEBUG_MEDIA_FAKE_ARTWORK) && !mDozing
1656                 && (mState != StatusBarState.SHADE || allowWhenShade)
1657                 && mFingerprintUnlockController.getMode()
1658                         != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
1659                 && !hideBecauseOccluded) {
1660             // time to show some art!
1661             if (mBackdrop.getVisibility() != View.VISIBLE) {
1662                 mBackdrop.setVisibility(View.VISIBLE);
1663                 if (allowEnterAnimation) {
1664                     mBackdrop.setAlpha(SRC_MIN_ALPHA);
1665                     mBackdrop.animate().alpha(1f);
1666                 } else {
1667                     mBackdrop.animate().cancel();
1668                     mBackdrop.setAlpha(1f);
1669                 }
1670                 mStatusBarWindowManager.setBackdropShowing(true);
1671                 mColorExtractor.setMediaBackdropVisible(true);
1672                 metaDataChanged = true;
1673                 if (DEBUG_MEDIA) {
1674                     Log.v(TAG, "DEBUG_MEDIA: Fading in album artwork");
1675                 }
1676             }
1677             if (metaDataChanged) {
1678                 if (mBackdropBack.getDrawable() != null) {
1679                     Drawable drawable =
1680                             mBackdropBack.getDrawable().getConstantState()
1681                                     .newDrawable(mBackdropFront.getResources()).mutate();
1682                     mBackdropFront.setImageDrawable(drawable);
1683                     if (mScrimSrcModeEnabled) {
1684                         mBackdropFront.getDrawable().mutate().setXfermode(mSrcOverXferMode);
1685                     }
1686                     mBackdropFront.setAlpha(1f);
1687                     mBackdropFront.setVisibility(View.VISIBLE);
1688                 } else {
1689                     mBackdropFront.setVisibility(View.INVISIBLE);
1690                 }
1691 
1692                 if (DEBUG_MEDIA_FAKE_ARTWORK) {
1693                     final int c = 0xFF000000 | (int)(Math.random() * 0xFFFFFF);
1694                     Log.v(TAG, String.format("DEBUG_MEDIA: setting new color: 0x%08x", c));
1695                     mBackdropBack.setBackgroundColor(0xFFFFFFFF);
1696                     mBackdropBack.setImageDrawable(new ColorDrawable(c));
1697                 } else {
1698                     mBackdropBack.setImageDrawable(artworkDrawable);
1699                 }
1700                 if (mScrimSrcModeEnabled) {
1701                     mBackdropBack.getDrawable().mutate().setXfermode(mSrcXferMode);
1702                 }
1703 
1704                 if (mBackdropFront.getVisibility() == View.VISIBLE) {
1705                     if (DEBUG_MEDIA) {
1706                         Log.v(TAG, "DEBUG_MEDIA: Crossfading album artwork from "
1707                                 + mBackdropFront.getDrawable()
1708                                 + " to "
1709                                 + mBackdropBack.getDrawable());
1710                     }
1711                     mBackdropFront.animate()
1712                             .setDuration(250)
1713                             .alpha(0f).withEndAction(mHideBackdropFront);
1714                 }
1715             }
1716         } else {
1717             // need to hide the album art, either because we are unlocked, on AOD
1718             // or because the metadata isn't there to support it
1719             if (mBackdrop.getVisibility() != View.GONE) {
1720                 if (DEBUG_MEDIA) {
1721                     Log.v(TAG, "DEBUG_MEDIA: Fading out album artwork");
1722                 }
1723                 mColorExtractor.setMediaBackdropVisible(false);
1724                 boolean cannotAnimateDoze = mDozing && !ScrimState.AOD.getAnimateChange();
1725                 if (mFingerprintUnlockController.getMode()
1726                         == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
1727                         || hideBecauseOccluded || cannotAnimateDoze) {
1728 
1729                     // We are unlocking directly - no animation!
1730                     mBackdrop.setVisibility(View.GONE);
1731                     mBackdropBack.setImageDrawable(null);
1732                     mStatusBarWindowManager.setBackdropShowing(false);
1733                 } else {
1734                     mStatusBarWindowManager.setBackdropShowing(false);
1735                     mBackdrop.animate()
1736                             .alpha(SRC_MIN_ALPHA)
1737                             .setInterpolator(Interpolators.ACCELERATE_DECELERATE)
1738                             .setDuration(300)
1739                             .setStartDelay(0)
1740                             .withEndAction(() -> {
1741                                 mBackdrop.setVisibility(View.GONE);
1742                                 mBackdropFront.animate().cancel();
1743                                 mBackdropBack.setImageDrawable(null);
1744                                 mHandler.post(mHideBackdropFront);
1745                             });
1746                     if (mKeyguardFadingAway) {
1747                         mBackdrop.animate()
1748                                 // Make it disappear faster, as the focus should be on the activity
1749                                 // behind.
1750                                 .setDuration(mKeyguardFadingAwayDuration / 2)
1751                                 .setStartDelay(mKeyguardFadingAwayDelay)
1752                                 .setInterpolator(Interpolators.LINEAR)
1753                                 .start();
1754                     }
1755                 }
1756             }
1757         }
1758         Trace.endSection();
1759     }
1760 
updateReportRejectedTouchVisibility()1761     private void updateReportRejectedTouchVisibility() {
1762         if (mReportRejectedTouch == null) {
1763             return;
1764         }
1765         mReportRejectedTouch.setVisibility(mState == StatusBarState.KEYGUARD && !mDozing
1766                 && mFalsingManager.isReportingEnabled() ? View.VISIBLE : View.INVISIBLE);
1767     }
1768 
1769     /**
1770      * State is one or more of the DISABLE constants from StatusBarManager.
1771      */
1772     @Override
disable(int state1, int state2, boolean animate)1773     public void disable(int state1, int state2, boolean animate) {
1774         state2 = mRemoteInputQuickSettingsDisabler.adjustDisableFlags(state2);
1775 
1776         animate &= mStatusBarWindowState != WINDOW_STATE_HIDDEN;
1777         final int old1 = mDisabled1;
1778         final int diff1 = state1 ^ old1;
1779         mDisabled1 = state1;
1780 
1781         final int old2 = mDisabled2;
1782         final int diff2 = state2 ^ old2;
1783         mDisabled2 = state2;
1784 
1785         if (DEBUG) {
1786             Log.d(TAG, String.format("disable1: 0x%08x -> 0x%08x (diff1: 0x%08x)",
1787                 old1, state1, diff1));
1788             Log.d(TAG, String.format("disable2: 0x%08x -> 0x%08x (diff2: 0x%08x)",
1789                 old2, state2, diff2));
1790         }
1791 
1792         StringBuilder flagdbg = new StringBuilder();
1793         flagdbg.append("disable<");
1794         flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_EXPAND))                ? 'E' : 'e');
1795         flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_EXPAND))                ? '!' : ' ');
1796         flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS))    ? 'I' : 'i');
1797         flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_NOTIFICATION_ICONS))    ? '!' : ' ');
1798         flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS))   ? 'A' : 'a');
1799         flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_NOTIFICATION_ALERTS))   ? '!' : ' ');
1800         flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_SYSTEM_INFO))           ? 'S' : 's');
1801         flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_SYSTEM_INFO))           ? '!' : ' ');
1802         flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_BACK))                  ? 'B' : 'b');
1803         flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_BACK))                  ? '!' : ' ');
1804         flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_HOME))                  ? 'H' : 'h');
1805         flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_HOME))                  ? '!' : ' ');
1806         flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_RECENT))                ? 'R' : 'r');
1807         flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_RECENT))                ? '!' : ' ');
1808         flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_CLOCK))                 ? 'C' : 'c');
1809         flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_CLOCK))                 ? '!' : ' ');
1810         flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_SEARCH))                ? 'S' : 's');
1811         flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_SEARCH))                ? '!' : ' ');
1812         flagdbg.append("> disable2<");
1813         flagdbg.append(0 != ((state2 & StatusBarManager.DISABLE2_QUICK_SETTINGS))       ? 'Q' : 'q');
1814         flagdbg.append(0 != ((diff2  & StatusBarManager.DISABLE2_QUICK_SETTINGS))       ? '!' : ' ');
1815         flagdbg.append(0 != ((state2 & StatusBarManager.DISABLE2_SYSTEM_ICONS))         ? 'I' : 'i');
1816         flagdbg.append(0 != ((diff2  & StatusBarManager.DISABLE2_SYSTEM_ICONS))         ? '!' : ' ');
1817         flagdbg.append(0 != ((state2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE))   ? 'N' : 'n');
1818         flagdbg.append(0 != ((diff2  & StatusBarManager.DISABLE2_NOTIFICATION_SHADE))   ? '!' : ' ');
1819         flagdbg.append('>');
1820         Log.d(TAG, flagdbg.toString());
1821 
1822         if ((diff1 & StatusBarManager.DISABLE_EXPAND) != 0) {
1823             if ((state1 & StatusBarManager.DISABLE_EXPAND) != 0) {
1824                 animateCollapsePanels();
1825             }
1826         }
1827 
1828         if ((diff1 & StatusBarManager.DISABLE_RECENT) != 0) {
1829             if ((state1 & StatusBarManager.DISABLE_RECENT) != 0) {
1830                 // close recents if it's visible
1831                 mHandler.removeMessages(MSG_HIDE_RECENT_APPS);
1832                 mHandler.sendEmptyMessage(MSG_HIDE_RECENT_APPS);
1833             }
1834         }
1835 
1836         if ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) {
1837             mEntryManager.setDisableNotificationAlerts(
1838                     (state1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0);
1839         }
1840 
1841         if ((diff2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) {
1842             updateQsExpansionEnabled();
1843         }
1844 
1845         if ((diff2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0) {
1846             updateQsExpansionEnabled();
1847             if ((state1 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0) {
1848                 animateCollapsePanels();
1849             }
1850         }
1851     }
1852 
1853     /**
1854      * Reapplies the disable flags as last requested by StatusBarManager.
1855      *
1856      * This needs to be called if state used by {@link #adjustDisableFlags} changes.
1857      */
recomputeDisableFlags(boolean animate)1858     public void recomputeDisableFlags(boolean animate) {
1859         mCommandQueue.recomputeDisableFlags(animate);
1860     }
1861 
createHandler()1862     protected H createHandler() {
1863         return new StatusBar.H();
1864     }
1865 
startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade, int flags)1866     private void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade,
1867             int flags) {
1868         startActivityDismissingKeyguard(intent, onlyProvisioned, dismissShade, flags);
1869     }
1870 
1871     @Override
startActivity(Intent intent, boolean dismissShade)1872     public void startActivity(Intent intent, boolean dismissShade) {
1873         startActivityDismissingKeyguard(intent, false, dismissShade);
1874     }
1875 
1876     @Override
startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade)1877     public void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade) {
1878         startActivityDismissingKeyguard(intent, onlyProvisioned, dismissShade);
1879     }
1880 
1881     @Override
startActivity(Intent intent, boolean dismissShade, Callback callback)1882     public void startActivity(Intent intent, boolean dismissShade, Callback callback) {
1883         startActivityDismissingKeyguard(intent, false, dismissShade,
1884                 false /* disallowEnterPictureInPictureWhileLaunching */, callback, 0);
1885     }
1886 
setQsExpanded(boolean expanded)1887     public void setQsExpanded(boolean expanded) {
1888         mStatusBarWindowManager.setQsExpanded(expanded);
1889         mNotificationPanel.setStatusAccessibilityImportance(expanded
1890                 ? View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
1891                 : View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
1892     }
1893 
isGoingToNotificationShade()1894     public boolean isGoingToNotificationShade() {
1895         return mLeaveOpenOnKeyguardHide;
1896     }
1897 
isWakeUpComingFromTouch()1898     public boolean isWakeUpComingFromTouch() {
1899         return mWakeUpComingFromTouch;
1900     }
1901 
isFalsingThresholdNeeded()1902     public boolean isFalsingThresholdNeeded() {
1903         return getBarState() == StatusBarState.KEYGUARD;
1904     }
1905 
1906     @Override
isDozing()1907     public boolean isDozing() {
1908         return mDozing && mStackScroller.isFullyDark();
1909     }
1910 
1911     @Override
shouldPeek(Entry entry, StatusBarNotification sbn)1912     public boolean shouldPeek(Entry entry, StatusBarNotification sbn) {
1913         if (mIsOccluded && !isDozing()) {
1914             boolean devicePublic = mLockscreenUserManager.
1915                     isLockscreenPublicMode(mLockscreenUserManager.getCurrentUserId());
1916             boolean userPublic = devicePublic
1917                     || mLockscreenUserManager.isLockscreenPublicMode(sbn.getUserId());
1918             boolean needsRedaction = mLockscreenUserManager.needsRedaction(entry);
1919             if (userPublic && needsRedaction) {
1920                 return false;
1921             }
1922         }
1923 
1924         if (!panelsEnabled()) {
1925             if (DEBUG) {
1926                 Log.d(TAG, "No peeking: disabled panel : " + sbn.getKey());
1927             }
1928             return false;
1929         }
1930 
1931         if (sbn.getNotification().fullScreenIntent != null) {
1932             if (mAccessibilityManager.isTouchExplorationEnabled()) {
1933                 if (DEBUG) Log.d(TAG, "No peeking: accessible fullscreen: " + sbn.getKey());
1934                 return false;
1935             } else if (isDozing()) {
1936                 // We never want heads up when we are dozing.
1937                 return false;
1938             } else {
1939                 // we only allow head-up on the lockscreen if it doesn't have a fullscreen intent
1940                 return !mStatusBarKeyguardViewManager.isShowing()
1941                         || mStatusBarKeyguardViewManager.isOccluded();
1942             }
1943         }
1944         return true;
1945     }
1946 
1947     @Override  // NotificationData.Environment
getCurrentMediaNotificationKey()1948     public String getCurrentMediaNotificationKey() {
1949         return mMediaManager.getMediaNotificationKey();
1950     }
1951 
isScrimSrcModeEnabled()1952     public boolean isScrimSrcModeEnabled() {
1953         return mScrimSrcModeEnabled;
1954     }
1955 
1956     /**
1957      * To be called when there's a state change in StatusBarKeyguardViewManager.
1958      */
onKeyguardViewManagerStatesUpdated()1959     public void onKeyguardViewManagerStatesUpdated() {
1960         logStateToEventlog();
1961     }
1962 
1963     @Override  // UnlockMethodCache.OnUnlockMethodChangedListener
onUnlockMethodStateChanged()1964     public void onUnlockMethodStateChanged() {
1965         logStateToEventlog();
1966     }
1967 
1968     @Override
onHeadsUpPinnedModeChanged(boolean inPinnedMode)1969     public void onHeadsUpPinnedModeChanged(boolean inPinnedMode) {
1970         if (inPinnedMode) {
1971             mStatusBarWindowManager.setHeadsUpShowing(true);
1972             mStatusBarWindowManager.setForceStatusBarVisible(true);
1973             if (mNotificationPanel.isFullyCollapsed()) {
1974                 // We need to ensure that the touchable region is updated before the window will be
1975                 // resized, in order to not catch any touches. A layout will ensure that
1976                 // onComputeInternalInsets will be called and after that we can resize the layout. Let's
1977                 // make sure that the window stays small for one frame until the touchableRegion is set.
1978                 mNotificationPanel.requestLayout();
1979                 mStatusBarWindowManager.setForceWindowCollapsed(true);
1980                 mNotificationPanel.post(() -> {
1981                     mStatusBarWindowManager.setForceWindowCollapsed(false);
1982                 });
1983             }
1984         } else {
1985             if (!mNotificationPanel.isFullyCollapsed() || mNotificationPanel.isTracking()) {
1986                 // We are currently tracking or is open and the shade doesn't need to be kept
1987                 // open artificially.
1988                 mStatusBarWindowManager.setHeadsUpShowing(false);
1989             } else {
1990                 // we need to keep the panel open artificially, let's wait until the animation
1991                 // is finished.
1992                 mHeadsUpManager.setHeadsUpGoingAway(true);
1993                 mStackScroller.runAfterAnimationFinished(() -> {
1994                     if (!mHeadsUpManager.hasPinnedHeadsUp()) {
1995                         mStatusBarWindowManager.setHeadsUpShowing(false);
1996                         mHeadsUpManager.setHeadsUpGoingAway(false);
1997                     }
1998                     mRemoteInputManager.removeRemoteInputEntriesKeptUntilCollapsed();
1999                 });
2000             }
2001         }
2002     }
2003 
2004     @Override
onHeadsUpPinned(ExpandableNotificationRow headsUp)2005     public void onHeadsUpPinned(ExpandableNotificationRow headsUp) {
2006         dismissVolumeDialog();
2007     }
2008 
2009     @Override
onHeadsUpUnPinned(ExpandableNotificationRow headsUp)2010     public void onHeadsUpUnPinned(ExpandableNotificationRow headsUp) {
2011     }
2012 
2013     @Override
onHeadsUpStateChanged(Entry entry, boolean isHeadsUp)2014     public void onHeadsUpStateChanged(Entry entry, boolean isHeadsUp) {
2015         mEntryManager.onHeadsUpStateChanged(entry, isHeadsUp);
2016 
2017         if (isHeadsUp) {
2018             mDozeServiceHost.fireNotificationHeadsUp();
2019         }
2020     }
2021 
setHeadsUpUser(int newUserId)2022     protected void setHeadsUpUser(int newUserId) {
2023         if (mHeadsUpManager != null) {
2024             mHeadsUpManager.setUser(newUserId);
2025         }
2026     }
2027 
isKeyguardCurrentlySecure()2028     public boolean isKeyguardCurrentlySecure() {
2029         return !mUnlockMethodCache.canSkipBouncer();
2030     }
2031 
setPanelExpanded(boolean isExpanded)2032     public void setPanelExpanded(boolean isExpanded) {
2033         mPanelExpanded = isExpanded;
2034         updateHideIconsForBouncer(false /* animate */);
2035         mStatusBarWindowManager.setPanelExpanded(isExpanded);
2036         mVisualStabilityManager.setPanelExpanded(isExpanded);
2037         if (isExpanded && getBarState() != StatusBarState.KEYGUARD) {
2038             if (DEBUG) {
2039                 Log.v(TAG, "clearing notification effects from setExpandedHeight");
2040             }
2041             clearNotificationEffects();
2042         }
2043 
2044         if (!isExpanded) {
2045             mRemoteInputManager.removeRemoteInputEntriesKeptUntilCollapsed();
2046         }
2047     }
2048 
getNotificationScrollLayout()2049     public NotificationStackScrollLayout getNotificationScrollLayout() {
2050         return mStackScroller;
2051     }
2052 
isPulsing()2053     public boolean isPulsing() {
2054         return mDozeScrimController != null && mDozeScrimController.isPulsing();
2055     }
2056 
isLaunchTransitionFadingAway()2057     public boolean isLaunchTransitionFadingAway() {
2058         return mLaunchTransitionFadingAway;
2059     }
2060 
hideStatusBarIconsWhenExpanded()2061     public boolean hideStatusBarIconsWhenExpanded() {
2062         return mNotificationPanel.hideStatusBarIconsWhenExpanded();
2063     }
2064 
2065     @Override
onColorsChanged(ColorExtractor extractor, int which)2066     public void onColorsChanged(ColorExtractor extractor, int which) {
2067         updateTheme();
2068     }
2069 
isUsingDarkTheme()2070     public boolean isUsingDarkTheme() {
2071         OverlayInfo themeInfo = null;
2072         try {
2073             themeInfo = mOverlayManager.getOverlayInfo("com.android.systemui.theme.dark",
2074                     mLockscreenUserManager.getCurrentUserId());
2075         } catch (RemoteException e) {
2076             e.printStackTrace();
2077         }
2078         return themeInfo != null && themeInfo.isEnabled();
2079     }
2080 
2081     @Nullable
getAmbientIndicationContainer()2082     public View getAmbientIndicationContainer() {
2083         return mAmbientIndicationContainer;
2084     }
2085 
setOccluded(boolean occluded)2086     public void setOccluded(boolean occluded) {
2087         mIsOccluded = occluded;
2088         mScrimController.setKeyguardOccluded(occluded);
2089         updateHideIconsForBouncer(false /* animate */);
2090     }
2091 
hideStatusBarIconsForBouncer()2092     public boolean hideStatusBarIconsForBouncer() {
2093         return mHideIconsForBouncer || mWereIconsJustHidden;
2094     }
2095 
2096     /**
2097      * Decides if the status bar (clock + notifications + signal cluster) should be visible
2098      * or not when showing the bouncer.
2099      *
2100      * We want to hide it when:
2101      * • User swipes up on the keyguard
2102      * • Locked activity that doesn't show a status bar requests the bouncer
2103      *
2104      * @param animate should the change of the icons be animated.
2105      */
updateHideIconsForBouncer(boolean animate)2106     private void updateHideIconsForBouncer(boolean animate) {
2107         boolean hideBecauseApp = mTopHidesStatusBar && mIsOccluded
2108                 && (mStatusBarWindowHidden || mBouncerShowing);
2109         boolean hideBecauseKeyguard = !mPanelExpanded && !mIsOccluded && mBouncerShowing;
2110         boolean shouldHideIconsForBouncer = hideBecauseApp || hideBecauseKeyguard;
2111         if (mHideIconsForBouncer != shouldHideIconsForBouncer) {
2112             mHideIconsForBouncer = shouldHideIconsForBouncer;
2113             if (!shouldHideIconsForBouncer && mBouncerWasShowingWhenHidden) {
2114                 // We're delaying the showing, since most of the time the fullscreen app will
2115                 // hide the icons again and we don't want them to fade in and out immediately again.
2116                 mWereIconsJustHidden = true;
2117                 mHandler.postDelayed(() -> {
2118                     mWereIconsJustHidden = false;
2119                     recomputeDisableFlags(true);
2120                 }, 500);
2121             } else {
2122                 recomputeDisableFlags(animate);
2123             }
2124         }
2125         if (shouldHideIconsForBouncer) {
2126             mBouncerWasShowingWhenHidden = mBouncerShowing;
2127         }
2128     }
2129 
onLaunchAnimationCancelled()2130     public void onLaunchAnimationCancelled() {
2131         if (!isCollapsing()) {
2132             onClosingFinished();
2133         }
2134     }
2135 
2136     /**
2137      * All changes to the status bar and notifications funnel through here and are batched.
2138      */
2139     protected class H extends Handler {
2140         @Override
handleMessage(Message m)2141         public void handleMessage(Message m) {
2142             switch (m.what) {
2143                 case MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU:
2144                     toggleKeyboardShortcuts(m.arg1);
2145                     break;
2146                 case MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU:
2147                     dismissKeyboardShortcuts();
2148                     break;
2149                 // End old BaseStatusBar.H handling.
2150                 case MSG_OPEN_NOTIFICATION_PANEL:
2151                     animateExpandNotificationsPanel();
2152                     break;
2153                 case MSG_OPEN_SETTINGS_PANEL:
2154                     animateExpandSettingsPanel((String) m.obj);
2155                     break;
2156                 case MSG_CLOSE_PANELS:
2157                     animateCollapsePanels();
2158                     break;
2159                 case MSG_LAUNCH_TRANSITION_TIMEOUT:
2160                     onLaunchTransitionTimeout();
2161                     break;
2162             }
2163         }
2164     }
2165 
maybeEscalateHeadsUp()2166     public void maybeEscalateHeadsUp() {
2167         mHeadsUpManager.getAllEntries().forEach(entry -> {
2168             final StatusBarNotification sbn = entry.notification;
2169             final Notification notification = sbn.getNotification();
2170             if (notification.fullScreenIntent != null) {
2171                 if (DEBUG) {
2172                     Log.d(TAG, "converting a heads up to fullScreen");
2173                 }
2174                 try {
2175                     EventLog.writeEvent(EventLogTags.SYSUI_HEADS_UP_ESCALATION,
2176                             sbn.getKey());
2177                     notification.fullScreenIntent.send();
2178                     entry.notifyFullScreenIntentLaunched();
2179                 } catch (PendingIntent.CanceledException e) {
2180                 }
2181             }
2182         });
2183         mHeadsUpManager.releaseAllImmediately();
2184     }
2185 
2186     /**
2187      * Called for system navigation gestures. First action opens the panel, second opens
2188      * settings. Down action closes the entire panel.
2189      */
2190     @Override
handleSystemKey(int key)2191     public void handleSystemKey(int key) {
2192         if (SPEW) Log.d(TAG, "handleNavigationKey: " + key);
2193         if (!panelsEnabled() || !mKeyguardMonitor.isDeviceInteractive()
2194                 || mKeyguardMonitor.isShowing() && !mKeyguardMonitor.isOccluded()) {
2195             return;
2196         }
2197 
2198         // Panels are not available in setup
2199         if (!mUserSetup) return;
2200 
2201         if (KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP == key) {
2202             mMetricsLogger.action(MetricsEvent.ACTION_SYSTEM_NAVIGATION_KEY_UP);
2203             mNotificationPanel.collapse(false /* delayed */, 1.0f /* speedUpFactor */);
2204         } else if (KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN == key) {
2205             mMetricsLogger.action(MetricsEvent.ACTION_SYSTEM_NAVIGATION_KEY_DOWN);
2206             if (mNotificationPanel.isFullyCollapsed()) {
2207                 if (mVibrateOnOpening) {
2208                     mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
2209                 }
2210                 mNotificationPanel.expand(true /* animate */);
2211                 mMetricsLogger.count(NotificationPanelView.COUNTER_PANEL_OPEN, 1);
2212             } else if (!mNotificationPanel.isInSettings() && !mNotificationPanel.isExpanding()){
2213                 mNotificationPanel.flingSettings(0 /* velocity */, true /* expand */);
2214                 mMetricsLogger.count(NotificationPanelView.COUNTER_PANEL_OPEN_QS, 1);
2215             }
2216         }
2217 
2218     }
2219 
2220     @Override
showPinningEnterExitToast(boolean entering)2221     public void showPinningEnterExitToast(boolean entering) {
2222         if (entering) {
2223             mScreenPinningNotify.showPinningStartToast();
2224         } else {
2225             mScreenPinningNotify.showPinningExitToast();
2226         }
2227     }
2228 
2229     @Override
showPinningEscapeToast()2230     public void showPinningEscapeToast() {
2231         mScreenPinningNotify.showEscapeToast(getNavigationBarView() == null
2232                 || getNavigationBarView().isRecentsButtonVisible());
2233     }
2234 
panelsEnabled()2235     boolean panelsEnabled() {
2236         return (mDisabled1 & StatusBarManager.DISABLE_EXPAND) == 0
2237                 && (mDisabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) == 0
2238                 && !ONLY_CORE_APPS;
2239     }
2240 
makeExpandedVisible(boolean force)2241     void makeExpandedVisible(boolean force) {
2242         if (SPEW) Log.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible);
2243         if (!force && (mExpandedVisible || !panelsEnabled())) {
2244             return;
2245         }
2246 
2247         mExpandedVisible = true;
2248 
2249         // Expand the window to encompass the full screen in anticipation of the drag.
2250         // This is only possible to do atomically because the status bar is at the top of the screen!
2251         mStatusBarWindowManager.setPanelVisible(true);
2252 
2253         visibilityChanged(true);
2254         recomputeDisableFlags(!force /* animate */);
2255         setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true);
2256     }
2257 
animateCollapsePanels()2258     public void animateCollapsePanels() {
2259         animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
2260     }
2261 
2262     private final Runnable mAnimateCollapsePanels = this::animateCollapsePanels;
2263 
postAnimateCollapsePanels()2264     public void postAnimateCollapsePanels() {
2265         mHandler.post(mAnimateCollapsePanels);
2266     }
2267 
postAnimateForceCollapsePanels()2268     public void postAnimateForceCollapsePanels() {
2269         mHandler.post(() -> {
2270             animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */);
2271         });
2272     }
2273 
postAnimateOpenPanels()2274     public void postAnimateOpenPanels() {
2275         mHandler.sendEmptyMessage(MSG_OPEN_SETTINGS_PANEL);
2276     }
2277 
2278     @Override
togglePanel()2279     public void togglePanel() {
2280         if (mPanelExpanded) {
2281             animateCollapsePanels();
2282         } else {
2283             animateExpandNotificationsPanel();
2284         }
2285     }
2286 
2287     @Override
animateCollapsePanels(int flags)2288     public void animateCollapsePanels(int flags) {
2289         animateCollapsePanels(flags, false /* force */, false /* delayed */,
2290                 1.0f /* speedUpFactor */);
2291     }
2292 
animateCollapsePanels(int flags, boolean force)2293     public void animateCollapsePanels(int flags, boolean force) {
2294         animateCollapsePanels(flags, force, false /* delayed */, 1.0f /* speedUpFactor */);
2295     }
2296 
animateCollapsePanels(int flags, boolean force, boolean delayed)2297     public void animateCollapsePanels(int flags, boolean force, boolean delayed) {
2298         animateCollapsePanels(flags, force, delayed, 1.0f /* speedUpFactor */);
2299     }
2300 
animateCollapsePanels(int flags, boolean force, boolean delayed, float speedUpFactor)2301     public void animateCollapsePanels(int flags, boolean force, boolean delayed,
2302             float speedUpFactor) {
2303         if (!force && mState != StatusBarState.SHADE) {
2304             runPostCollapseRunnables();
2305             return;
2306         }
2307         if (SPEW) {
2308             Log.d(TAG, "animateCollapse():"
2309                     + " mExpandedVisible=" + mExpandedVisible
2310                     + " flags=" + flags);
2311         }
2312 
2313         if ((flags & CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL) == 0) {
2314             if (!mHandler.hasMessages(MSG_HIDE_RECENT_APPS)) {
2315                 mHandler.removeMessages(MSG_HIDE_RECENT_APPS);
2316                 mHandler.sendEmptyMessage(MSG_HIDE_RECENT_APPS);
2317             }
2318         }
2319 
2320         // TODO(b/62444020): remove when this bug is fixed
2321         Log.v(TAG, "mStatusBarWindow: " + mStatusBarWindow + " canPanelBeCollapsed(): "
2322                 + mNotificationPanel.canPanelBeCollapsed());
2323         if (mStatusBarWindow != null && mNotificationPanel.canPanelBeCollapsed()) {
2324             // release focus immediately to kick off focus change transition
2325             mStatusBarWindowManager.setStatusBarFocusable(false);
2326 
2327             mStatusBarWindow.cancelExpandHelper();
2328             mStatusBarView.collapsePanel(true /* animate */, delayed, speedUpFactor);
2329         }
2330     }
2331 
runPostCollapseRunnables()2332     private void runPostCollapseRunnables() {
2333         ArrayList<Runnable> clonedList = new ArrayList<>(mPostCollapseRunnables);
2334         mPostCollapseRunnables.clear();
2335         int size = clonedList.size();
2336         for (int i = 0; i < size; i++) {
2337             clonedList.get(i).run();
2338         }
2339         mStatusBarKeyguardViewManager.readyForKeyguardDone();
2340     }
2341 
2342     @Override
animateExpandNotificationsPanel()2343     public void animateExpandNotificationsPanel() {
2344         if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible);
2345         if (!panelsEnabled()) {
2346             return ;
2347         }
2348 
2349         mNotificationPanel.expandWithoutQs();
2350 
2351         if (false) postStartTracing();
2352     }
2353 
2354     @Override
animateExpandSettingsPanel(String subPanel)2355     public void animateExpandSettingsPanel(String subPanel) {
2356         if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible);
2357         if (!panelsEnabled()) {
2358             return;
2359         }
2360 
2361         // Settings are not available in setup
2362         if (!mUserSetup) return;
2363 
2364 
2365         if (subPanel != null) {
2366             mQSPanel.openDetails(subPanel);
2367         }
2368         mNotificationPanel.expandWithQs();
2369 
2370         if (false) postStartTracing();
2371     }
2372 
animateCollapseQuickSettings()2373     public void animateCollapseQuickSettings() {
2374         if (mState == StatusBarState.SHADE) {
2375             mStatusBarView.collapsePanel(true, false /* delayed */, 1.0f /* speedUpFactor */);
2376         }
2377     }
2378 
makeExpandedInvisible()2379     void makeExpandedInvisible() {
2380         if (SPEW) Log.d(TAG, "makeExpandedInvisible: mExpandedVisible=" + mExpandedVisible
2381                 + " mExpandedVisible=" + mExpandedVisible);
2382 
2383         if (!mExpandedVisible || mStatusBarWindow == null) {
2384             return;
2385         }
2386 
2387         // Ensure the panel is fully collapsed (just in case; bug 6765842, 7260868)
2388         mStatusBarView.collapsePanel(/*animate=*/ false, false /* delayed*/,
2389                 1.0f /* speedUpFactor */);
2390 
2391         mNotificationPanel.closeQs();
2392 
2393         mExpandedVisible = false;
2394         visibilityChanged(false);
2395 
2396         // Shrink the window to the size of the status bar only
2397         mStatusBarWindowManager.setPanelVisible(false);
2398         mStatusBarWindowManager.setForceStatusBarVisible(false);
2399 
2400         // Close any guts that might be visible
2401         mGutsManager.closeAndSaveGuts(true /* removeLeavebehind */, true /* force */,
2402                 true /* removeControls */, -1 /* x */, -1 /* y */, true /* resetMenu */);
2403 
2404         runPostCollapseRunnables();
2405         setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
2406         showBouncerIfKeyguard();
2407         recomputeDisableFlags(mNotificationPanel.hideStatusBarIconsWhenExpanded() /* animate */);
2408 
2409         // Trimming will happen later if Keyguard is showing - doing it here might cause a jank in
2410         // the bouncer appear animation.
2411         if (!mStatusBarKeyguardViewManager.isShowing()) {
2412             WindowManagerGlobal.getInstance().trimMemory(ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
2413         }
2414     }
2415 
interceptTouchEvent(MotionEvent event)2416     public boolean interceptTouchEvent(MotionEvent event) {
2417         if (DEBUG_GESTURES) {
2418             if (event.getActionMasked() != MotionEvent.ACTION_MOVE) {
2419                 EventLog.writeEvent(EventLogTags.SYSUI_STATUSBAR_TOUCH,
2420                         event.getActionMasked(), (int) event.getX(), (int) event.getY(),
2421                         mDisabled1, mDisabled2);
2422             }
2423 
2424         }
2425 
2426         if (SPEW) {
2427             Log.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled1="
2428                     + mDisabled1 + " mDisabled2=" + mDisabled2);
2429         } else if (CHATTY) {
2430             if (event.getAction() != MotionEvent.ACTION_MOVE) {
2431                 Log.d(TAG, String.format(
2432                             "panel: %s at (%f, %f) mDisabled1=0x%08x mDisabled2=0x%08x",
2433                             MotionEvent.actionToString(event.getAction()),
2434                             event.getRawX(), event.getRawY(), mDisabled1, mDisabled2));
2435             }
2436         }
2437 
2438         if (DEBUG_GESTURES) {
2439             mGestureRec.add(event);
2440         }
2441 
2442         if (mStatusBarWindowState == WINDOW_STATE_SHOWING) {
2443             final boolean upOrCancel =
2444                     event.getAction() == MotionEvent.ACTION_UP ||
2445                     event.getAction() == MotionEvent.ACTION_CANCEL;
2446             if (upOrCancel && !mExpandedVisible) {
2447                 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
2448             } else {
2449                 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true);
2450             }
2451         }
2452         return false;
2453     }
2454 
getGestureRecorder()2455     public GestureRecorder getGestureRecorder() {
2456         return mGestureRec;
2457     }
2458 
getFingerprintUnlockController()2459     public FingerprintUnlockController getFingerprintUnlockController() {
2460         return mFingerprintUnlockController;
2461     }
2462 
2463     @Override // CommandQueue
setWindowState(int window, int state)2464     public void setWindowState(int window, int state) {
2465         boolean showing = state == WINDOW_STATE_SHOWING;
2466         if (mStatusBarWindow != null
2467                 && window == StatusBarManager.WINDOW_STATUS_BAR
2468                 && mStatusBarWindowState != state) {
2469             mStatusBarWindowState = state;
2470             if (DEBUG_WINDOW_STATE) Log.d(TAG, "Status bar " + windowStateToString(state));
2471             if (!showing && mState == StatusBarState.SHADE) {
2472                 mStatusBarView.collapsePanel(false /* animate */, false /* delayed */,
2473                         1.0f /* speedUpFactor */);
2474             }
2475             if (mStatusBarView != null) {
2476                 mStatusBarWindowHidden = state == WINDOW_STATE_HIDDEN;
2477                 updateHideIconsForBouncer(false /* animate */);
2478             }
2479         }
2480     }
2481 
2482     @Override // CommandQueue
setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds)2483     public void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis,
2484             int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
2485         final int oldVal = mSystemUiVisibility;
2486         final int newVal = (oldVal&~mask) | (vis&mask);
2487         final int diff = newVal ^ oldVal;
2488         if (DEBUG) Log.d(TAG, String.format(
2489                 "setSystemUiVisibility vis=%s mask=%s oldVal=%s newVal=%s diff=%s",
2490                 Integer.toHexString(vis), Integer.toHexString(mask),
2491                 Integer.toHexString(oldVal), Integer.toHexString(newVal),
2492                 Integer.toHexString(diff)));
2493         boolean sbModeChanged = false;
2494         if (diff != 0) {
2495             mSystemUiVisibility = newVal;
2496 
2497             // update low profile
2498             if ((diff & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0) {
2499                 setAreThereNotifications();
2500             }
2501 
2502             // ready to unhide
2503             if ((vis & View.STATUS_BAR_UNHIDE) != 0) {
2504                 mSystemUiVisibility &= ~View.STATUS_BAR_UNHIDE;
2505                 mNoAnimationOnNextBarModeChange = true;
2506             }
2507 
2508             // update status bar mode
2509             final int sbMode = computeStatusBarMode(oldVal, newVal);
2510 
2511             sbModeChanged = sbMode != -1;
2512             if (sbModeChanged && sbMode != mStatusBarMode) {
2513                 mStatusBarMode = sbMode;
2514                 checkBarModes();
2515                 touchAutoHide();
2516             }
2517 
2518             if ((vis & View.NAVIGATION_BAR_UNHIDE) != 0) {
2519                 mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE;
2520             }
2521 
2522             // send updated sysui visibility to window manager
2523             notifyUiVisibilityChanged(mSystemUiVisibility);
2524         }
2525 
2526         mLightBarController.onSystemUiVisibilityChanged(fullscreenStackVis, dockedStackVis,
2527                 mask, fullscreenStackBounds, dockedStackBounds, sbModeChanged, mStatusBarMode);
2528     }
2529 
2530     @Override
showWirelessChargingAnimation(int batteryLevel)2531     public void showWirelessChargingAnimation(int batteryLevel) {
2532         if (mDozing || mKeyguardManager.isKeyguardLocked()) {
2533             // on ambient or lockscreen, hide notification panel
2534             WirelessChargingAnimation.makeWirelessChargingAnimation(mContext, null,
2535                     batteryLevel, new WirelessChargingAnimation.Callback() {
2536                         @Override
2537                         public void onAnimationStarting() {
2538                             CrossFadeHelper.fadeOut(mNotificationPanel, 1);
2539                         }
2540 
2541                         @Override
2542                         public void onAnimationEnded() {
2543                             CrossFadeHelper.fadeIn(mNotificationPanel);
2544                         }
2545                     }, mDozing).show();
2546         } else {
2547             // workspace
2548             WirelessChargingAnimation.makeWirelessChargingAnimation(mContext, null,
2549                     batteryLevel, null, false).show();
2550         }
2551     }
2552 
touchAutoHide()2553     void touchAutoHide() {
2554         // update transient bar autohide
2555         if (mStatusBarMode == MODE_SEMI_TRANSPARENT || (mNavigationBar != null
2556                 && mNavigationBar.isSemiTransparent())) {
2557             scheduleAutohide();
2558         } else {
2559             cancelAutohide();
2560         }
2561     }
2562 
computeStatusBarMode(int oldVal, int newVal)2563     protected int computeStatusBarMode(int oldVal, int newVal) {
2564         return computeBarMode(oldVal, newVal, View.STATUS_BAR_TRANSIENT,
2565                 View.STATUS_BAR_TRANSLUCENT, View.STATUS_BAR_TRANSPARENT);
2566     }
2567 
getStatusBarTransitions()2568     protected BarTransitions getStatusBarTransitions() {
2569         return mStatusBarView.getBarTransitions();
2570     }
2571 
computeBarMode(int oldVis, int newVis, int transientFlag, int translucentFlag, int transparentFlag)2572     protected int computeBarMode(int oldVis, int newVis,
2573             int transientFlag, int translucentFlag, int transparentFlag) {
2574         final int oldMode = barMode(oldVis, transientFlag, translucentFlag, transparentFlag);
2575         final int newMode = barMode(newVis, transientFlag, translucentFlag, transparentFlag);
2576         if (oldMode == newMode) {
2577             return -1; // no mode change
2578         }
2579         return newMode;
2580     }
2581 
barMode(int vis, int transientFlag, int translucentFlag, int transparentFlag)2582     private int barMode(int vis, int transientFlag, int translucentFlag, int transparentFlag) {
2583         int lightsOutTransparent = View.SYSTEM_UI_FLAG_LOW_PROFILE | transparentFlag;
2584         return (vis & transientFlag) != 0 ? MODE_SEMI_TRANSPARENT
2585                 : (vis & translucentFlag) != 0 ? MODE_TRANSLUCENT
2586                 : (vis & lightsOutTransparent) == lightsOutTransparent ? MODE_LIGHTS_OUT_TRANSPARENT
2587                 : (vis & transparentFlag) != 0 ? MODE_TRANSPARENT
2588                 : (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0 ? MODE_LIGHTS_OUT
2589                 : MODE_OPAQUE;
2590     }
2591 
checkBarModes()2592     void checkBarModes() {
2593         if (mDemoMode) return;
2594         if (mStatusBarView != null) checkBarMode(mStatusBarMode, mStatusBarWindowState,
2595                 getStatusBarTransitions());
2596         if (mNavigationBar != null) mNavigationBar.checkNavBarModes();
2597         mNoAnimationOnNextBarModeChange = false;
2598     }
2599 
2600     // Called by NavigationBarFragment
setQsScrimEnabled(boolean scrimEnabled)2601     void setQsScrimEnabled(boolean scrimEnabled) {
2602         mNotificationPanel.setQsScrimEnabled(scrimEnabled);
2603     }
2604 
checkBarMode(int mode, int windowState, BarTransitions transitions)2605     void checkBarMode(int mode, int windowState, BarTransitions transitions) {
2606         final boolean anim = !mNoAnimationOnNextBarModeChange && mDeviceInteractive
2607                 && windowState != WINDOW_STATE_HIDDEN;
2608         transitions.transitionTo(mode, anim);
2609     }
2610 
finishBarAnimations()2611     private void finishBarAnimations() {
2612         if (mStatusBarView != null) {
2613             mStatusBarView.getBarTransitions().finishAnimations();
2614         }
2615         if (mNavigationBar != null) {
2616             mNavigationBar.finishBarAnimations();
2617         }
2618     }
2619 
2620     private final Runnable mCheckBarModes = this::checkBarModes;
2621 
setInteracting(int barWindow, boolean interacting)2622     public void setInteracting(int barWindow, boolean interacting) {
2623         final boolean changing = ((mInteractingWindows & barWindow) != 0) != interacting;
2624         mInteractingWindows = interacting
2625                 ? (mInteractingWindows | barWindow)
2626                 : (mInteractingWindows & ~barWindow);
2627         if (mInteractingWindows != 0) {
2628             suspendAutohide();
2629         } else {
2630             resumeSuspendedAutohide();
2631         }
2632         // manually dismiss the volume panel when interacting with the nav bar
2633         if (changing && interacting && barWindow == StatusBarManager.WINDOW_NAVIGATION_BAR) {
2634             touchAutoDim();
2635             dismissVolumeDialog();
2636         }
2637         checkBarModes();
2638     }
2639 
dismissVolumeDialog()2640     private void dismissVolumeDialog() {
2641         if (mVolumeComponent != null) {
2642             mVolumeComponent.dismissNow();
2643         }
2644     }
2645 
resumeSuspendedAutohide()2646     private void resumeSuspendedAutohide() {
2647         if (mAutohideSuspended) {
2648             scheduleAutohide();
2649             mHandler.postDelayed(mCheckBarModes, 500); // longer than home -> launcher
2650         }
2651     }
2652 
suspendAutohide()2653     private void suspendAutohide() {
2654         mHandler.removeCallbacks(mAutohide);
2655         mHandler.removeCallbacks(mCheckBarModes);
2656         mAutohideSuspended = (mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0;
2657     }
2658 
cancelAutohide()2659     private void cancelAutohide() {
2660         mAutohideSuspended = false;
2661         mHandler.removeCallbacks(mAutohide);
2662     }
2663 
scheduleAutohide()2664     private void scheduleAutohide() {
2665         cancelAutohide();
2666         mHandler.postDelayed(mAutohide, AUTOHIDE_TIMEOUT_MS);
2667     }
2668 
touchAutoDim()2669     public void touchAutoDim() {
2670         if (mNavigationBar != null) {
2671             mNavigationBar.getBarTransitions().setAutoDim(false);
2672         }
2673         mHandler.removeCallbacks(mAutoDim);
2674         if (mState != StatusBarState.KEYGUARD && mState != StatusBarState.SHADE_LOCKED) {
2675             mHandler.postDelayed(mAutoDim, AUTOHIDE_TIMEOUT_MS);
2676         }
2677     }
2678 
checkUserAutohide(MotionEvent event)2679     void checkUserAutohide(MotionEvent event) {
2680         if ((mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0  // a transient bar is revealed
2681                 && event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar
2682                 && event.getX() == 0 && event.getY() == 0  // a touch outside both bars
2683                 && !mRemoteInputManager.getController()
2684                         .isRemoteInputActive()) { // not due to typing in IME
2685             userAutohide();
2686         }
2687     }
2688 
userAutohide()2689     private void userAutohide() {
2690         cancelAutohide();
2691         mHandler.postDelayed(mAutohide, 350); // longer than app gesture -> flag clear
2692     }
2693 
areLightsOn()2694     private boolean areLightsOn() {
2695         return 0 == (mSystemUiVisibility & View.SYSTEM_UI_FLAG_LOW_PROFILE);
2696     }
2697 
setLightsOn(boolean on)2698     public void setLightsOn(boolean on) {
2699         Log.v(TAG, "setLightsOn(" + on + ")");
2700         if (on) {
2701             setSystemUiVisibility(0, 0, 0, View.SYSTEM_UI_FLAG_LOW_PROFILE,
2702                     mLastFullscreenStackBounds, mLastDockedStackBounds);
2703         } else {
2704             setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE, 0, 0,
2705                     View.SYSTEM_UI_FLAG_LOW_PROFILE, mLastFullscreenStackBounds,
2706                     mLastDockedStackBounds);
2707         }
2708     }
2709 
notifyUiVisibilityChanged(int vis)2710     private void notifyUiVisibilityChanged(int vis) {
2711         try {
2712             if (mLastDispatchedSystemUiVisibility != vis) {
2713                 mWindowManagerService.statusBarVisibilityChanged(vis);
2714                 mLastDispatchedSystemUiVisibility = vis;
2715             }
2716         } catch (RemoteException ex) {
2717         }
2718     }
2719 
2720     @Override
topAppWindowChanged(boolean showMenu)2721     public void topAppWindowChanged(boolean showMenu) {
2722         if (SPEW) {
2723             Log.d(TAG, (showMenu?"showing":"hiding") + " the MENU button");
2724         }
2725 
2726         // See above re: lights-out policy for legacy apps.
2727         if (showMenu) setLightsOn(true);
2728     }
2729 
viewInfo(View v)2730     public static String viewInfo(View v) {
2731         return "[(" + v.getLeft() + "," + v.getTop() + ")(" + v.getRight() + "," + v.getBottom()
2732                 + ") " + v.getWidth() + "x" + v.getHeight() + "]";
2733     }
2734 
2735     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)2736     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2737         synchronized (mQueueLock) {
2738             pw.println("Current Status Bar state:");
2739             pw.println("  mExpandedVisible=" + mExpandedVisible);
2740             pw.println("  mDisplayMetrics=" + mDisplayMetrics);
2741             pw.println("  mStackScroller: " + viewInfo(mStackScroller));
2742             pw.println("  mStackScroller: " + viewInfo(mStackScroller)
2743                     + " scroll " + mStackScroller.getScrollX()
2744                     + "," + mStackScroller.getScrollY());
2745         }
2746 
2747         pw.print("  mInteractingWindows="); pw.println(mInteractingWindows);
2748         pw.print("  mStatusBarWindowState=");
2749         pw.println(windowStateToString(mStatusBarWindowState));
2750         pw.print("  mStatusBarMode=");
2751         pw.println(BarTransitions.modeToString(mStatusBarMode));
2752         pw.print("  mDozing="); pw.println(mDozing);
2753         pw.print("  mZenMode=");
2754         pw.println(Settings.Global.zenModeToString(Settings.Global.getInt(
2755                 mContext.getContentResolver(), Settings.Global.ZEN_MODE,
2756                 Settings.Global.ZEN_MODE_OFF)));
2757 
2758         if (mStatusBarView != null) {
2759             dumpBarTransitions(pw, "mStatusBarView", mStatusBarView.getBarTransitions());
2760         }
2761         pw.println("  StatusBarWindowView: ");
2762         if (mStatusBarWindow != null) {
2763             mStatusBarWindow.dump(fd, pw, args);
2764         }
2765 
2766         pw.println("  mMediaManager: ");
2767         if (mMediaManager != null) {
2768             mMediaManager.dump(fd, pw, args);
2769         }
2770 
2771         pw.println("  Panels: ");
2772         if (mNotificationPanel != null) {
2773             pw.println("    mNotificationPanel=" +
2774                 mNotificationPanel + " params=" + mNotificationPanel.getLayoutParams().debug(""));
2775             pw.print  ("      ");
2776             mNotificationPanel.dump(fd, pw, args);
2777         }
2778         pw.println("  mStackScroller: ");
2779         if (mStackScroller != null) {
2780             pw.print  ("      ");
2781             mStackScroller.dump(fd, pw, args);
2782         }
2783         pw.println("  Theme:");
2784         if (mOverlayManager == null) {
2785             pw.println("    overlay manager not initialized!");
2786         } else {
2787             pw.println("    dark overlay on: " + isUsingDarkTheme());
2788         }
2789         final boolean lightWpTheme = mContext.getThemeResId() == R.style.Theme_SystemUI_Light;
2790         pw.println("    light wallpaper theme: " + lightWpTheme);
2791 
2792         DozeLog.dump(pw);
2793 
2794         if (mFingerprintUnlockController != null) {
2795             mFingerprintUnlockController.dump(pw);
2796         }
2797 
2798         if (mKeyguardIndicationController != null) {
2799             mKeyguardIndicationController.dump(fd, pw, args);
2800         }
2801 
2802         if (mScrimController != null) {
2803             mScrimController.dump(fd, pw, args);
2804         }
2805 
2806         if (mStatusBarKeyguardViewManager != null) {
2807             mStatusBarKeyguardViewManager.dump(pw);
2808         }
2809 
2810         if (DUMPTRUCK) {
2811             synchronized (mEntryManager.getNotificationData()) {
2812                 mEntryManager.getNotificationData().dump(pw, "  ");
2813             }
2814 
2815             if (false) {
2816                 pw.println("see the logcat for a dump of the views we have created.");
2817                 // must happen on ui thread
2818                 mHandler.post(() -> {
2819                     mStatusBarView.getLocationOnScreen(mAbsPos);
2820                     Log.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1] +
2821                             ") " + mStatusBarView.getWidth() + "x" + getStatusBarHeight());
2822                     mStatusBarView.debug();
2823                 });
2824             }
2825         }
2826 
2827         if (DEBUG_GESTURES) {
2828             pw.print("  status bar gestures: ");
2829             mGestureRec.dump(fd, pw, args);
2830         }
2831 
2832         if (mHeadsUpManager != null) {
2833             mHeadsUpManager.dump(fd, pw, args);
2834         } else {
2835             pw.println("  mHeadsUpManager: null");
2836         }
2837         if (mGroupManager != null) {
2838             mGroupManager.dump(fd, pw, args);
2839         } else {
2840             pw.println("  mGroupManager: null");
2841         }
2842 
2843         if (mLightBarController != null) {
2844             mLightBarController.dump(fd, pw, args);
2845         }
2846 
2847         if (KeyguardUpdateMonitor.getInstance(mContext) != null) {
2848             KeyguardUpdateMonitor.getInstance(mContext).dump(fd, pw, args);
2849         }
2850 
2851         FalsingManager.getInstance(mContext).dump(pw);
2852         FalsingLog.dump(pw);
2853 
2854         pw.println("SharedPreferences:");
2855         for (Map.Entry<String, ?> entry : Prefs.getAll(mContext).entrySet()) {
2856             pw.print("  "); pw.print(entry.getKey()); pw.print("="); pw.println(entry.getValue());
2857         }
2858     }
2859 
dumpBarTransitions(PrintWriter pw, String var, BarTransitions transitions)2860     static void dumpBarTransitions(PrintWriter pw, String var, BarTransitions transitions) {
2861         pw.print("  "); pw.print(var); pw.print(".BarTransitions.mMode=");
2862         pw.println(BarTransitions.modeToString(transitions.getMode()));
2863     }
2864 
createAndAddWindows()2865     public void createAndAddWindows() {
2866         addStatusBarWindow();
2867     }
2868 
addStatusBarWindow()2869     private void addStatusBarWindow() {
2870         makeStatusBarView();
2871         mStatusBarWindowManager = Dependency.get(StatusBarWindowManager.class);
2872         mRemoteInputManager.setUpWithPresenter(this, mEntryManager, this,
2873                 new RemoteInputController.Delegate() {
2874                     public void setRemoteInputActive(NotificationData.Entry entry,
2875                             boolean remoteInputActive) {
2876                         mHeadsUpManager.setRemoteInputActive(entry, remoteInputActive);
2877                         entry.row.notifyHeightChanged(true /* needsAnimation */);
2878                         updateFooter();
2879                     }
2880                     public void lockScrollTo(NotificationData.Entry entry) {
2881                         mStackScroller.lockScrollTo(entry.row);
2882                     }
2883                     public void requestDisallowLongPressAndDismiss() {
2884                         mStackScroller.requestDisallowLongPress();
2885                         mStackScroller.requestDisallowDismiss();
2886                     }
2887                 });
2888         mRemoteInputManager.getController().addCallback(mStatusBarWindowManager);
2889         mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());
2890     }
2891 
2892     // called by makeStatusbar and also by PhoneStatusBarView
updateDisplaySize()2893     void updateDisplaySize() {
2894         mDisplay.getMetrics(mDisplayMetrics);
2895         mDisplay.getSize(mCurrentDisplaySize);
2896         if (DEBUG_GESTURES) {
2897             mGestureRec.tag("display",
2898                     String.format("%dx%d", mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels));
2899         }
2900     }
2901 
getDisplayDensity()2902     float getDisplayDensity() {
2903         return mDisplayMetrics.density;
2904     }
2905 
getDisplayWidth()2906     float getDisplayWidth() {
2907         return mDisplayMetrics.widthPixels;
2908     }
2909 
getDisplayHeight()2910     float getDisplayHeight() {
2911         return mDisplayMetrics.heightPixels;
2912     }
2913 
getRotation()2914     int getRotation() {
2915         return mDisplay.getRotation();
2916     }
2917 
startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned, boolean dismissShade, int flags)2918     public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned,
2919             boolean dismissShade, int flags) {
2920         startActivityDismissingKeyguard(intent, onlyProvisioned, dismissShade,
2921                 false /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */,
2922                 flags);
2923     }
2924 
startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned, boolean dismissShade)2925     public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned,
2926             boolean dismissShade) {
2927         startActivityDismissingKeyguard(intent, onlyProvisioned, dismissShade, 0);
2928     }
2929 
startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned, final boolean dismissShade, final boolean disallowEnterPictureInPictureWhileLaunching, final Callback callback, int flags)2930     public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned,
2931             final boolean dismissShade, final boolean disallowEnterPictureInPictureWhileLaunching,
2932             final Callback callback, int flags) {
2933         if (onlyProvisioned && !isDeviceProvisioned()) return;
2934 
2935         final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity(
2936                 mContext, intent, mLockscreenUserManager.getCurrentUserId());
2937         Runnable runnable = () -> {
2938             mAssistManager.hideAssist();
2939             intent.setFlags(
2940                     Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
2941             intent.addFlags(flags);
2942             int result = ActivityManager.START_CANCELED;
2943             ActivityOptions options = new ActivityOptions(getActivityOptions(
2944                     null /* remoteAnimation */));
2945             options.setDisallowEnterPictureInPictureWhileLaunching(
2946                     disallowEnterPictureInPictureWhileLaunching);
2947             if (intent == KeyguardBottomAreaView.INSECURE_CAMERA_INTENT) {
2948                 // Normally an activity will set it's requested rotation
2949                 // animation on its window. However when launching an activity
2950                 // causes the orientation to change this is too late. In these cases
2951                 // the default animation is used. This doesn't look good for
2952                 // the camera (as it rotates the camera contents out of sync
2953                 // with physical reality). So, we ask the WindowManager to
2954                 // force the crossfade animation if an orientation change
2955                 // happens to occur during the launch.
2956                 options.setRotationAnimationHint(
2957                         WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS);
2958             }
2959             try {
2960                 result = ActivityManager.getService().startActivityAsUser(
2961                         null, mContext.getBasePackageName(),
2962                         intent,
2963                         intent.resolveTypeIfNeeded(mContext.getContentResolver()),
2964                         null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null,
2965                         options.toBundle(), UserHandle.CURRENT.getIdentifier());
2966             } catch (RemoteException e) {
2967                 Log.w(TAG, "Unable to start activity", e);
2968             }
2969             if (callback != null) {
2970                 callback.onActivityStarted(result);
2971             }
2972         };
2973         Runnable cancelRunnable = () -> {
2974             if (callback != null) {
2975                 callback.onActivityStarted(ActivityManager.START_CANCELED);
2976             }
2977         };
2978         executeRunnableDismissingKeyguard(runnable, cancelRunnable, dismissShade,
2979                 afterKeyguardGone, true /* deferred */);
2980     }
2981 
readyForKeyguardDone()2982     public void readyForKeyguardDone() {
2983         mStatusBarKeyguardViewManager.readyForKeyguardDone();
2984     }
2985 
executeRunnableDismissingKeyguard(final Runnable runnable, final Runnable cancelAction, final boolean dismissShade, final boolean afterKeyguardGone, final boolean deferred)2986     public void executeRunnableDismissingKeyguard(final Runnable runnable,
2987             final Runnable cancelAction,
2988             final boolean dismissShade,
2989             final boolean afterKeyguardGone,
2990             final boolean deferred) {
2991         dismissKeyguardThenExecute(() -> {
2992             if (runnable != null) {
2993                 if (mStatusBarKeyguardViewManager.isShowing()
2994                         && mStatusBarKeyguardViewManager.isOccluded()) {
2995                     mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(runnable);
2996                 } else {
2997                     AsyncTask.execute(runnable);
2998                 }
2999             }
3000             if (dismissShade) {
3001                 if (mExpandedVisible) {
3002                     animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */,
3003                             true /* delayed*/);
3004                 } else {
3005 
3006                     // Do it after DismissAction has been processed to conserve the needed ordering.
3007                     mHandler.post(this::runPostCollapseRunnables);
3008                 }
3009             } else if (isInLaunchTransition() && mNotificationPanel.isLaunchTransitionFinished()) {
3010 
3011                 // We are not dismissing the shade, but the launch transition is already finished,
3012                 // so nobody will call readyForKeyguardDone anymore. Post it such that
3013                 // keyguardDonePending gets called first.
3014                 mHandler.post(mStatusBarKeyguardViewManager::readyForKeyguardDone);
3015             }
3016             return deferred;
3017         }, cancelAction, afterKeyguardGone);
3018     }
3019 
3020     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
3021         @Override
3022         public void onReceive(Context context, Intent intent) {
3023             if (DEBUG) Log.v(TAG, "onReceive: " + intent);
3024             String action = intent.getAction();
3025             if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
3026                 KeyboardShortcuts.dismiss();
3027                 if (mRemoteInputManager.getController() != null) {
3028                     mRemoteInputManager.getController().closeRemoteInputs();
3029                 }
3030                 if (mLockscreenUserManager.isCurrentProfile(getSendingUserId())) {
3031                     int flags = CommandQueue.FLAG_EXCLUDE_NONE;
3032                     String reason = intent.getStringExtra("reason");
3033                     if (reason != null && reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) {
3034                         flags |= CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL;
3035                     }
3036                     animateCollapsePanels(flags);
3037                 }
3038             }
3039             else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
3040                 finishBarAnimations();
3041                 resetUserExpandedStates();
3042             }
3043             else if (DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG.equals(action)) {
3044                 mQSPanel.showDeviceMonitoringDialog();
3045             }
3046         }
3047     };
3048 
3049     private final BroadcastReceiver mDemoReceiver = new BroadcastReceiver() {
3050         @Override
3051         public void onReceive(Context context, Intent intent) {
3052             if (DEBUG) Log.v(TAG, "onReceive: " + intent);
3053             String action = intent.getAction();
3054             if (ACTION_DEMO.equals(action)) {
3055                 Bundle bundle = intent.getExtras();
3056                 if (bundle != null) {
3057                     String command = bundle.getString("command", "").trim().toLowerCase();
3058                     if (command.length() > 0) {
3059                         try {
3060                             dispatchDemoCommand(command, bundle);
3061                         } catch (Throwable t) {
3062                             Log.w(TAG, "Error running demo command, intent=" + intent, t);
3063                         }
3064                     }
3065                 }
3066             } else if (ACTION_FAKE_ARTWORK.equals(action)) {
3067                 if (DEBUG_MEDIA_FAKE_ARTWORK) {
3068                     updateMediaMetaData(true, true);
3069                 }
3070             }
3071         }
3072     };
3073 
resetUserExpandedStates()3074     public void resetUserExpandedStates() {
3075         ArrayList<Entry> activeNotifications = mEntryManager.getNotificationData()
3076                 .getActiveNotifications();
3077         final int notificationCount = activeNotifications.size();
3078         for (int i = 0; i < notificationCount; i++) {
3079             NotificationData.Entry entry = activeNotifications.get(i);
3080             if (entry.row != null) {
3081                 entry.row.resetUserExpansion();
3082             }
3083         }
3084     }
3085 
executeWhenUnlocked(OnDismissAction action)3086     private void executeWhenUnlocked(OnDismissAction action) {
3087         if (mStatusBarKeyguardViewManager.isShowing()) {
3088             mLeaveOpenOnKeyguardHide = true;
3089         }
3090         dismissKeyguardThenExecute(action, null /* cancelAction */, false /* afterKeyguardGone */);
3091     }
3092 
dismissKeyguardThenExecute(OnDismissAction action, boolean afterKeyguardGone)3093     protected void dismissKeyguardThenExecute(OnDismissAction action, boolean afterKeyguardGone) {
3094         dismissKeyguardThenExecute(action, null /* cancelRunnable */, afterKeyguardGone);
3095     }
3096 
dismissKeyguardThenExecute(OnDismissAction action, Runnable cancelAction, boolean afterKeyguardGone)3097     private void dismissKeyguardThenExecute(OnDismissAction action, Runnable cancelAction,
3098             boolean afterKeyguardGone) {
3099         if (mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_ASLEEP
3100                 && mUnlockMethodCache.canSkipBouncer()
3101                 && !mLeaveOpenOnKeyguardHide
3102                 && isPulsing()) {
3103             // Reuse the fingerprint wake-and-unlock transition if we dismiss keyguard from a pulse.
3104             // TODO: Factor this transition out of FingerprintUnlockController.
3105             mFingerprintUnlockController.startWakeAndUnlock(
3106                     FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING);
3107         }
3108         if (mStatusBarKeyguardViewManager.isShowing()) {
3109             mStatusBarKeyguardViewManager.dismissWithAction(action, cancelAction,
3110                     afterKeyguardGone);
3111         } else {
3112             action.onDismiss();
3113         }
3114     }
3115 
3116     // SystemUIService notifies SystemBars of configuration changes, which then calls down here
3117     @Override
onConfigChanged(Configuration newConfig)3118     public void onConfigChanged(Configuration newConfig) {
3119         updateResources();
3120         updateDisplaySize(); // populates mDisplayMetrics
3121 
3122         if (DEBUG) {
3123             Log.v(TAG, "configuration changed: " + mContext.getResources().getConfiguration());
3124         }
3125 
3126         mViewHierarchyManager.updateRowStates();
3127         mScreenPinningRequest.onConfigurationChanged();
3128     }
3129 
3130     @Override
onUserSwitched(int newUserId)3131     public void onUserSwitched(int newUserId) {
3132         // Begin old BaseStatusBar.userSwitched
3133         setHeadsUpUser(newUserId);
3134         // End old BaseStatusBar.userSwitched
3135         if (MULTIUSER_DEBUG) mNotificationPanelDebugText.setText("USER " + newUserId);
3136         animateCollapsePanels();
3137         updatePublicMode();
3138         mEntryManager.getNotificationData().filterAndSort();
3139         if (mReinflateNotificationsOnUserSwitched) {
3140             mEntryManager.updateNotificationsOnDensityOrFontScaleChanged();
3141             mReinflateNotificationsOnUserSwitched = false;
3142         }
3143         updateNotificationViews();
3144         mMediaManager.clearCurrentMediaNotification();
3145         setLockscreenUser(newUserId);
3146     }
3147 
3148     @Override
getNotificationLockscreenUserManager()3149     public NotificationLockscreenUserManager getNotificationLockscreenUserManager() {
3150         return mLockscreenUserManager;
3151     }
3152 
3153     @Override
onBindRow(Entry entry, PackageManager pmUser, StatusBarNotification sbn, ExpandableNotificationRow row)3154     public void onBindRow(Entry entry, PackageManager pmUser,
3155             StatusBarNotification sbn, ExpandableNotificationRow row) {
3156         row.setAboveShelfChangedListener(mAboveShelfObserver);
3157         row.setSecureStateProvider(this::isKeyguardCurrentlySecure);
3158     }
3159 
setLockscreenUser(int newUserId)3160     protected void setLockscreenUser(int newUserId) {
3161         mLockscreenWallpaper.setCurrentUser(newUserId);
3162         mScrimController.setCurrentUser(newUserId);
3163         updateMediaMetaData(true, false);
3164     }
3165 
3166     /**
3167      * Reload some of our resources when the configuration changes.
3168      *
3169      * We don't reload everything when the configuration changes -- we probably
3170      * should, but getting that smooth is tough.  Someday we'll fix that.  In the
3171      * meantime, just update the things that we know change.
3172      */
updateResources()3173     void updateResources() {
3174         // Update the quick setting tiles
3175         if (mQSPanel != null) {
3176             mQSPanel.updateResources();
3177         }
3178 
3179         loadDimens();
3180 
3181         if (mStatusBarView != null) {
3182             mStatusBarView.updateResources();
3183         }
3184         if (mNotificationPanel != null) {
3185             mNotificationPanel.updateResources();
3186         }
3187         if (mBrightnessMirrorController != null) {
3188             mBrightnessMirrorController.updateResources();
3189         }
3190     }
3191 
loadDimens()3192     protected void loadDimens() {
3193         final Resources res = mContext.getResources();
3194 
3195         int oldBarHeight = mNaturalBarHeight;
3196         mNaturalBarHeight = res.getDimensionPixelSize(
3197                 com.android.internal.R.dimen.status_bar_height);
3198         if (mStatusBarWindowManager != null && mNaturalBarHeight != oldBarHeight) {
3199             mStatusBarWindowManager.setBarHeight(mNaturalBarHeight);
3200         }
3201         mMaxAllowedKeyguardNotifications = res.getInteger(
3202                 R.integer.keyguard_max_notification_count);
3203 
3204         if (DEBUG) Log.v(TAG, "defineSlots");
3205     }
3206 
3207     // Visibility reporting
3208 
handleVisibleToUserChanged(boolean visibleToUser)3209     protected void handleVisibleToUserChanged(boolean visibleToUser) {
3210         if (visibleToUser) {
3211             handleVisibleToUserChangedImpl(visibleToUser);
3212             mNotificationLogger.startNotificationLogging();
3213         } else {
3214             mNotificationLogger.stopNotificationLogging();
3215             handleVisibleToUserChangedImpl(visibleToUser);
3216         }
3217     }
3218 
handlePeekToExpandTransistion()3219     void handlePeekToExpandTransistion() {
3220         try {
3221             // consider the transition from peek to expanded to be a panel open,
3222             // but not one that clears notification effects.
3223             int notificationLoad = mEntryManager.getNotificationData()
3224                     .getActiveNotifications().size();
3225             mBarService.onPanelRevealed(false, notificationLoad);
3226         } catch (RemoteException ex) {
3227             // Won't fail unless the world has ended.
3228         }
3229     }
3230 
3231     /**
3232      * The LEDs are turned off when the notification panel is shown, even just a little bit.
3233      * See also StatusBar.setPanelExpanded for another place where we attempt to do this.
3234      */
handleVisibleToUserChangedImpl(boolean visibleToUser)3235     private void handleVisibleToUserChangedImpl(boolean visibleToUser) {
3236         if (visibleToUser) {
3237             boolean pinnedHeadsUp = mHeadsUpManager.hasPinnedHeadsUp();
3238             boolean clearNotificationEffects =
3239                     !isPresenterFullyCollapsed() &&
3240                             (mState == StatusBarState.SHADE
3241                                     || mState == StatusBarState.SHADE_LOCKED);
3242             int notificationLoad = mEntryManager.getNotificationData().getActiveNotifications()
3243                     .size();
3244             if (pinnedHeadsUp && isPresenterFullyCollapsed()) {
3245                 notificationLoad = 1;
3246             }
3247             final int finalNotificationLoad = notificationLoad;
3248             mUiOffloadThread.submit(() -> {
3249                 try {
3250                     mBarService.onPanelRevealed(clearNotificationEffects,
3251                             finalNotificationLoad);
3252                 } catch (RemoteException ex) {
3253                     // Won't fail unless the world has ended.
3254                 }
3255             });
3256         } else {
3257             mUiOffloadThread.submit(() -> {
3258                 try {
3259                     mBarService.onPanelHidden();
3260                 } catch (RemoteException ex) {
3261                     // Won't fail unless the world has ended.
3262                 }
3263             });
3264         }
3265 
3266     }
3267 
logStateToEventlog()3268     private void logStateToEventlog() {
3269         boolean isShowing = mStatusBarKeyguardViewManager.isShowing();
3270         boolean isOccluded = mStatusBarKeyguardViewManager.isOccluded();
3271         boolean isBouncerShowing = mStatusBarKeyguardViewManager.isBouncerShowing();
3272         boolean isSecure = mUnlockMethodCache.isMethodSecure();
3273         boolean canSkipBouncer = mUnlockMethodCache.canSkipBouncer();
3274         int stateFingerprint = getLoggingFingerprint(mState,
3275                 isShowing,
3276                 isOccluded,
3277                 isBouncerShowing,
3278                 isSecure,
3279                 canSkipBouncer);
3280         if (stateFingerprint != mLastLoggedStateFingerprint) {
3281             if (mStatusBarStateLog == null) {
3282                 mStatusBarStateLog = new LogMaker(MetricsEvent.VIEW_UNKNOWN);
3283             }
3284             mMetricsLogger.write(mStatusBarStateLog
3285                     .setCategory(isBouncerShowing ? MetricsEvent.BOUNCER : MetricsEvent.LOCKSCREEN)
3286                     .setType(isShowing ? MetricsEvent.TYPE_OPEN : MetricsEvent.TYPE_CLOSE)
3287                     .setSubtype(isSecure ? 1 : 0));
3288             EventLogTags.writeSysuiStatusBarState(mState,
3289                     isShowing ? 1 : 0,
3290                     isOccluded ? 1 : 0,
3291                     isBouncerShowing ? 1 : 0,
3292                     isSecure ? 1 : 0,
3293                     canSkipBouncer ? 1 : 0);
3294             mLastLoggedStateFingerprint = stateFingerprint;
3295         }
3296     }
3297 
3298     /**
3299      * Returns a fingerprint of fields logged to eventlog
3300      */
getLoggingFingerprint(int statusBarState, boolean keyguardShowing, boolean keyguardOccluded, boolean bouncerShowing, boolean secure, boolean currentlyInsecure)3301     private static int getLoggingFingerprint(int statusBarState, boolean keyguardShowing,
3302             boolean keyguardOccluded, boolean bouncerShowing, boolean secure,
3303             boolean currentlyInsecure) {
3304         // Reserve 8 bits for statusBarState. We'll never go higher than
3305         // that, right? Riiiight.
3306         return (statusBarState & 0xFF)
3307                 | ((keyguardShowing   ? 1 : 0) <<  8)
3308                 | ((keyguardOccluded  ? 1 : 0) <<  9)
3309                 | ((bouncerShowing    ? 1 : 0) << 10)
3310                 | ((secure            ? 1 : 0) << 11)
3311                 | ((currentlyInsecure ? 1 : 0) << 12);
3312     }
3313 
3314     //
3315     // tracing
3316     //
3317 
postStartTracing()3318     void postStartTracing() {
3319         mHandler.postDelayed(mStartTracing, 3000);
3320     }
3321 
vibrate()3322     void vibrate() {
3323         android.os.Vibrator vib = (android.os.Vibrator)mContext.getSystemService(
3324                 Context.VIBRATOR_SERVICE);
3325         vib.vibrate(250, VIBRATION_ATTRIBUTES);
3326     }
3327 
3328     final Runnable mStartTracing = new Runnable() {
3329         @Override
3330         public void run() {
3331             vibrate();
3332             SystemClock.sleep(250);
3333             Log.d(TAG, "startTracing");
3334             android.os.Debug.startMethodTracing("/data/statusbar-traces/trace");
3335             mHandler.postDelayed(mStopTracing, 10000);
3336         }
3337     };
3338 
3339     final Runnable mStopTracing = () -> {
3340         android.os.Debug.stopMethodTracing();
3341         Log.d(TAG, "stopTracing");
3342         vibrate();
3343     };
3344 
3345     @Override
postQSRunnableDismissingKeyguard(final Runnable runnable)3346     public void postQSRunnableDismissingKeyguard(final Runnable runnable) {
3347         mHandler.post(() -> {
3348             mLeaveOpenOnKeyguardHide = true;
3349             executeRunnableDismissingKeyguard(() -> mHandler.post(runnable), null, false, false,
3350                     false);
3351         });
3352     }
3353 
3354     @Override
postStartActivityDismissingKeyguard(final PendingIntent intent)3355     public void postStartActivityDismissingKeyguard(final PendingIntent intent) {
3356         mHandler.post(() -> startPendingIntentDismissingKeyguard(intent));
3357     }
3358 
3359     @Override
postStartActivityDismissingKeyguard(final Intent intent, int delay)3360     public void postStartActivityDismissingKeyguard(final Intent intent, int delay) {
3361         mHandler.postDelayed(() ->
3362                 handleStartActivityDismissingKeyguard(intent, true /*onlyProvisioned*/), delay);
3363     }
3364 
handleStartActivityDismissingKeyguard(Intent intent, boolean onlyProvisioned)3365     private void handleStartActivityDismissingKeyguard(Intent intent, boolean onlyProvisioned) {
3366         startActivityDismissingKeyguard(intent, onlyProvisioned, true /* dismissShade */);
3367     }
3368 
destroy()3369     public void destroy() {
3370         // Begin old BaseStatusBar.destroy().
3371         mContext.unregisterReceiver(mBannerActionBroadcastReceiver);
3372         mLockscreenUserManager.destroy();
3373         try {
3374             mNotificationListener.unregisterAsSystemService();
3375         } catch (RemoteException e) {
3376             // Ignore.
3377         }
3378         mEntryManager.destroy();
3379         // End old BaseStatusBar.destroy().
3380         if (mStatusBarWindow != null) {
3381             mWindowManager.removeViewImmediate(mStatusBarWindow);
3382             mStatusBarWindow = null;
3383         }
3384         if (mNavigationBarView != null) {
3385             mWindowManager.removeViewImmediate(mNavigationBarView);
3386             mNavigationBarView = null;
3387         }
3388         mContext.unregisterReceiver(mBroadcastReceiver);
3389         mContext.unregisterReceiver(mDemoReceiver);
3390         mAssistManager.destroy();
3391 
3392         if (mQSPanel != null && mQSPanel.getHost() != null) {
3393             mQSPanel.getHost().destroy();
3394         }
3395         Dependency.get(ActivityStarterDelegate.class).setActivityStarterImpl(null);
3396         mDeviceProvisionedController.removeCallback(mUserSetupObserver);
3397         Dependency.get(ConfigurationController.class).removeCallback(this);
3398         mZenController.removeCallback(this);
3399         mAppOpsListener.destroy();
3400     }
3401 
3402     private boolean mDemoModeAllowed;
3403     private boolean mDemoMode;
3404 
3405     @Override
dispatchDemoCommand(String command, Bundle args)3406     public void dispatchDemoCommand(String command, Bundle args) {
3407         if (!mDemoModeAllowed) {
3408             mDemoModeAllowed = Settings.Global.getInt(mContext.getContentResolver(),
3409                     DEMO_MODE_ALLOWED, 0) != 0;
3410         }
3411         if (!mDemoModeAllowed) return;
3412         if (command.equals(COMMAND_ENTER)) {
3413             mDemoMode = true;
3414         } else if (command.equals(COMMAND_EXIT)) {
3415             mDemoMode = false;
3416             checkBarModes();
3417         } else if (!mDemoMode) {
3418             // automatically enter demo mode on first demo command
3419             dispatchDemoCommand(COMMAND_ENTER, new Bundle());
3420         }
3421         boolean modeChange = command.equals(COMMAND_ENTER) || command.equals(COMMAND_EXIT);
3422         if ((modeChange || command.equals(COMMAND_VOLUME)) && mVolumeComponent != null) {
3423             mVolumeComponent.dispatchDemoCommand(command, args);
3424         }
3425         if (modeChange || command.equals(COMMAND_CLOCK)) {
3426             dispatchDemoCommandToView(command, args, R.id.clock);
3427         }
3428         if (modeChange || command.equals(COMMAND_BATTERY)) {
3429             mBatteryController.dispatchDemoCommand(command, args);
3430         }
3431         if (modeChange || command.equals(COMMAND_STATUS)) {
3432             ((StatusBarIconControllerImpl) mIconController).dispatchDemoCommand(command, args);
3433         }
3434         if (mNetworkController != null && (modeChange || command.equals(COMMAND_NETWORK))) {
3435             mNetworkController.dispatchDemoCommand(command, args);
3436         }
3437         if (modeChange || command.equals(COMMAND_NOTIFICATIONS)) {
3438             View notifications = mStatusBarView == null ? null
3439                     : mStatusBarView.findViewById(R.id.notification_icon_area);
3440             if (notifications != null) {
3441                 String visible = args.getString("visible");
3442                 int vis = mDemoMode && "false".equals(visible) ? View.INVISIBLE : View.VISIBLE;
3443                 notifications.setVisibility(vis);
3444             }
3445         }
3446         if (command.equals(COMMAND_BARS)) {
3447             String mode = args.getString("mode");
3448             int barMode = "opaque".equals(mode) ? MODE_OPAQUE :
3449                     "translucent".equals(mode) ? MODE_TRANSLUCENT :
3450                     "semi-transparent".equals(mode) ? MODE_SEMI_TRANSPARENT :
3451                     "transparent".equals(mode) ? MODE_TRANSPARENT :
3452                     "warning".equals(mode) ? MODE_WARNING :
3453                     -1;
3454             if (barMode != -1) {
3455                 boolean animate = true;
3456                 if (mStatusBarView != null) {
3457                     mStatusBarView.getBarTransitions().transitionTo(barMode, animate);
3458                 }
3459                 if (mNavigationBar != null) {
3460                     mNavigationBar.getBarTransitions().transitionTo(barMode, animate);
3461                 }
3462             }
3463         }
3464         if (modeChange || command.equals(COMMAND_OPERATOR)) {
3465             dispatchDemoCommandToView(command, args, R.id.operator_name);
3466         }
3467     }
3468 
dispatchDemoCommandToView(String command, Bundle args, int id)3469     private void dispatchDemoCommandToView(String command, Bundle args, int id) {
3470         if (mStatusBarView == null) return;
3471         View v = mStatusBarView.findViewById(id);
3472         if (v instanceof DemoMode) {
3473             ((DemoMode)v).dispatchDemoCommand(command, args);
3474         }
3475     }
3476 
3477     /**
3478      * @return The {@link StatusBarState} the status bar is in.
3479      */
getBarState()3480     public int getBarState() {
3481         return mState;
3482     }
3483 
3484     @Override
isPresenterFullyCollapsed()3485     public boolean isPresenterFullyCollapsed() {
3486         return mNotificationPanel.isFullyCollapsed();
3487     }
3488 
showKeyguard()3489     public void showKeyguard() {
3490         mKeyguardRequested = true;
3491         mLeaveOpenOnKeyguardHide = false;
3492         mPendingRemoteInputView = null;
3493         updateIsKeyguard();
3494         mAssistManager.onLockscreenShown();
3495     }
3496 
hideKeyguard()3497     public boolean hideKeyguard() {
3498         mKeyguardRequested = false;
3499         return updateIsKeyguard();
3500     }
3501 
3502     /**
3503      * @return True if StatusBar state is FULLSCREEN_USER_SWITCHER.
3504      */
isFullScreenUserSwitcherState()3505     public boolean isFullScreenUserSwitcherState() {
3506         return mState == StatusBarState.FULLSCREEN_USER_SWITCHER;
3507     }
3508 
updateIsKeyguard()3509     private boolean updateIsKeyguard() {
3510         boolean wakeAndUnlocking = mFingerprintUnlockController.getMode()
3511                 == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK;
3512 
3513         // For dozing, keyguard needs to be shown whenever the device is non-interactive. Otherwise
3514         // there's no surface we can show to the user. Note that the device goes fully interactive
3515         // late in the transition, so we also allow the device to start dozing once the screen has
3516         // turned off fully.
3517         boolean keyguardForDozing = mDozingRequested &&
3518                 (!mDeviceInteractive || isGoingToSleep() && (isScreenFullyOff() || mIsKeyguard));
3519         boolean shouldBeKeyguard = (mKeyguardRequested || keyguardForDozing) && !wakeAndUnlocking;
3520         if (keyguardForDozing) {
3521             updatePanelExpansionForKeyguard();
3522         }
3523         if (shouldBeKeyguard) {
3524             if (isGoingToSleep()
3525                     && mScreenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_TURNING_OFF) {
3526                 // Delay showing the keyguard until screen turned off.
3527             } else {
3528                 showKeyguardImpl();
3529             }
3530         } else {
3531             return hideKeyguardImpl();
3532         }
3533         return false;
3534     }
3535 
showKeyguardImpl()3536     public void showKeyguardImpl() {
3537         mIsKeyguard = true;
3538         if (mLaunchTransitionFadingAway) {
3539             mNotificationPanel.animate().cancel();
3540             onLaunchTransitionFadingEnded();
3541         }
3542         mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
3543         if (mUserSwitcherController != null && mUserSwitcherController.useFullscreenUserSwitcher()) {
3544             setBarState(StatusBarState.FULLSCREEN_USER_SWITCHER);
3545         } else {
3546             setBarState(StatusBarState.KEYGUARD);
3547         }
3548         updateKeyguardState(false /* goingToFullShade */, false /* fromShadeLocked */);
3549         updatePanelExpansionForKeyguard();
3550         if (mDraggedDownRow != null) {
3551             mDraggedDownRow.setUserLocked(false);
3552             mDraggedDownRow.notifyHeightChanged(false  /* needsAnimation */);
3553             mDraggedDownRow = null;
3554         }
3555     }
3556 
updatePanelExpansionForKeyguard()3557     private void updatePanelExpansionForKeyguard() {
3558         if (mState == StatusBarState.KEYGUARD && mFingerprintUnlockController.getMode()
3559                 != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK) {
3560             instantExpandNotificationsPanel();
3561         } else if (mState == StatusBarState.FULLSCREEN_USER_SWITCHER) {
3562             instantCollapseNotificationPanel();
3563         }
3564     }
3565 
onLaunchTransitionFadingEnded()3566     private void onLaunchTransitionFadingEnded() {
3567         mNotificationPanel.setAlpha(1.0f);
3568         mNotificationPanel.onAffordanceLaunchEnded();
3569         releaseGestureWakeLock();
3570         runLaunchTransitionEndRunnable();
3571         mLaunchTransitionFadingAway = false;
3572         updateMediaMetaData(true /* metaDataChanged */, true);
3573     }
3574 
isCollapsing()3575     public boolean isCollapsing() {
3576         return mNotificationPanel.isCollapsing() || mActivityLaunchAnimator.isAnimationPending();
3577     }
3578 
addPostCollapseAction(Runnable r)3579     public void addPostCollapseAction(Runnable r) {
3580         mPostCollapseRunnables.add(r);
3581     }
3582 
isInLaunchTransition()3583     public boolean isInLaunchTransition() {
3584         return mNotificationPanel.isLaunchTransitionRunning()
3585                 || mNotificationPanel.isLaunchTransitionFinished();
3586     }
3587 
3588     /**
3589      * Fades the content of the keyguard away after the launch transition is done.
3590      *
3591      * @param beforeFading the runnable to be run when the circle is fully expanded and the fading
3592      *                     starts
3593      * @param endRunnable the runnable to be run when the transition is done
3594      */
fadeKeyguardAfterLaunchTransition(final Runnable beforeFading, Runnable endRunnable)3595     public void fadeKeyguardAfterLaunchTransition(final Runnable beforeFading,
3596             Runnable endRunnable) {
3597         mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
3598         mLaunchTransitionEndRunnable = endRunnable;
3599         Runnable hideRunnable = () -> {
3600             mLaunchTransitionFadingAway = true;
3601             if (beforeFading != null) {
3602                 beforeFading.run();
3603             }
3604             updateScrimController();
3605             updateMediaMetaData(false, true);
3606             mNotificationPanel.setAlpha(1);
3607             mStackScroller.setParentNotFullyVisible(true);
3608             mNotificationPanel.animate()
3609                     .alpha(0)
3610                     .setStartDelay(FADE_KEYGUARD_START_DELAY)
3611                     .setDuration(FADE_KEYGUARD_DURATION)
3612                     .withLayer()
3613                     .withEndAction(this::onLaunchTransitionFadingEnded);
3614             mCommandQueue.appTransitionStarting(SystemClock.uptimeMillis(),
3615                     LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true);
3616         };
3617         if (mNotificationPanel.isLaunchTransitionRunning()) {
3618             mNotificationPanel.setLaunchTransitionEndRunnable(hideRunnable);
3619         } else {
3620             hideRunnable.run();
3621         }
3622     }
3623 
3624     /**
3625      * Fades the content of the Keyguard while we are dozing and makes it invisible when finished
3626      * fading.
3627      */
fadeKeyguardWhilePulsing()3628     public void fadeKeyguardWhilePulsing() {
3629         mNotificationPanel.notifyStartFading();
3630         mNotificationPanel.animate()
3631                 .alpha(0f)
3632                 .setStartDelay(0)
3633                 .setDuration(FADE_KEYGUARD_DURATION_PULSING)
3634                 .setInterpolator(Interpolators.ALPHA_OUT)
3635                 .withEndAction(()-> {
3636                     hideKeyguard();
3637                     mStatusBarKeyguardViewManager.onKeyguardFadedAway();
3638                 }).start();
3639     }
3640 
3641     /**
3642      * Plays the animation when an activity that was occluding Keyguard goes away.
3643      */
animateKeyguardUnoccluding()3644     public void animateKeyguardUnoccluding() {
3645         mNotificationPanel.setExpandedFraction(0f);
3646         animateExpandNotificationsPanel();
3647     }
3648 
3649     /**
3650      * Starts the timeout when we try to start the affordances on Keyguard. We usually rely that
3651      * Keyguard goes away via fadeKeyguardAfterLaunchTransition, however, that might not happen
3652      * because the launched app crashed or something else went wrong.
3653      */
startLaunchTransitionTimeout()3654     public void startLaunchTransitionTimeout() {
3655         mHandler.sendEmptyMessageDelayed(MSG_LAUNCH_TRANSITION_TIMEOUT,
3656                 LAUNCH_TRANSITION_TIMEOUT_MS);
3657     }
3658 
onLaunchTransitionTimeout()3659     private void onLaunchTransitionTimeout() {
3660         Log.w(TAG, "Launch transition: Timeout!");
3661         mNotificationPanel.onAffordanceLaunchEnded();
3662         releaseGestureWakeLock();
3663         mNotificationPanel.resetViews();
3664     }
3665 
runLaunchTransitionEndRunnable()3666     private void runLaunchTransitionEndRunnable() {
3667         if (mLaunchTransitionEndRunnable != null) {
3668             Runnable r = mLaunchTransitionEndRunnable;
3669 
3670             // mLaunchTransitionEndRunnable might call showKeyguard, which would execute it again,
3671             // which would lead to infinite recursion. Protect against it.
3672             mLaunchTransitionEndRunnable = null;
3673             r.run();
3674         }
3675     }
3676 
3677     /**
3678      * @return true if we would like to stay in the shade, false if it should go away entirely
3679      */
hideKeyguardImpl()3680     public boolean hideKeyguardImpl() {
3681         mIsKeyguard = false;
3682         Trace.beginSection("StatusBar#hideKeyguard");
3683         boolean staying = mLeaveOpenOnKeyguardHide;
3684         setBarState(StatusBarState.SHADE);
3685         View viewToClick = null;
3686         if (mLeaveOpenOnKeyguardHide) {
3687             if (!mKeyguardRequested) {
3688                 mLeaveOpenOnKeyguardHide = false;
3689             }
3690             long delay = calculateGoingToFullShadeDelay();
3691             mNotificationPanel.animateToFullShade(delay);
3692             if (mDraggedDownRow != null) {
3693                 mDraggedDownRow.setUserLocked(false);
3694                 mDraggedDownRow = null;
3695             }
3696             if (!mKeyguardRequested) {
3697                 viewToClick = mPendingRemoteInputView;
3698                 mPendingRemoteInputView = null;
3699             }
3700 
3701             // Disable layout transitions in navbar for this transition because the load is just
3702             // too heavy for the CPU and GPU on any device.
3703             if (mNavigationBar != null) {
3704                 mNavigationBar.disableAnimationsDuringHide(delay);
3705             }
3706         } else if (!mNotificationPanel.isCollapsing()) {
3707             instantCollapseNotificationPanel();
3708         }
3709         updateKeyguardState(staying, false /* fromShadeLocked */);
3710 
3711         if (viewToClick != null && viewToClick.isAttachedToWindow()) {
3712             viewToClick.callOnClick();
3713         }
3714 
3715         // Keyguard state has changed, but QS is not listening anymore. Make sure to update the tile
3716         // visibilities so next time we open the panel we know the correct height already.
3717         if (mQSPanel != null) {
3718             mQSPanel.refreshAllTiles();
3719         }
3720         mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
3721         releaseGestureWakeLock();
3722         mNotificationPanel.onAffordanceLaunchEnded();
3723         mNotificationPanel.animate().cancel();
3724         mNotificationPanel.setAlpha(1f);
3725         Trace.endSection();
3726         return staying;
3727     }
3728 
releaseGestureWakeLock()3729     private void releaseGestureWakeLock() {
3730         if (mGestureWakeLock.isHeld()) {
3731             mGestureWakeLock.release();
3732         }
3733     }
3734 
calculateGoingToFullShadeDelay()3735     public long calculateGoingToFullShadeDelay() {
3736         return mKeyguardFadingAwayDelay + mKeyguardFadingAwayDuration;
3737     }
3738 
3739     /**
3740      * Notifies the status bar that Keyguard is going away very soon.
3741      */
keyguardGoingAway()3742     public void keyguardGoingAway() {
3743 
3744         // Treat Keyguard exit animation as an app transition to achieve nice transition for status
3745         // bar.
3746         mKeyguardMonitor.notifyKeyguardGoingAway(true);
3747         mCommandQueue.appTransitionPending(true);
3748     }
3749 
3750     /**
3751      * Notifies the status bar the Keyguard is fading away with the specified timings.
3752      *
3753      * @param startTime the start time of the animations in uptime millis
3754      * @param delay the precalculated animation delay in milliseconds
3755      * @param fadeoutDuration the duration of the exit animation, in milliseconds
3756      */
setKeyguardFadingAway(long startTime, long delay, long fadeoutDuration)3757     public void setKeyguardFadingAway(long startTime, long delay, long fadeoutDuration) {
3758         mKeyguardFadingAway = true;
3759         mKeyguardFadingAwayDelay = delay;
3760         mKeyguardFadingAwayDuration = fadeoutDuration;
3761         mCommandQueue.appTransitionStarting(startTime + fadeoutDuration
3762                         - LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION,
3763                 LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true);
3764         recomputeDisableFlags(fadeoutDuration > 0 /* animate */);
3765         mCommandQueue.appTransitionStarting(
3766                     startTime - LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION,
3767                     LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true);
3768         mKeyguardMonitor.notifyKeyguardFadingAway(delay, fadeoutDuration);
3769     }
3770 
isKeyguardFadingAway()3771     public boolean isKeyguardFadingAway() {
3772         return mKeyguardFadingAway;
3773     }
3774 
3775     /**
3776      * Notifies that the Keyguard fading away animation is done.
3777      */
finishKeyguardFadingAway()3778     public void finishKeyguardFadingAway() {
3779         mKeyguardFadingAway = false;
3780         mKeyguardMonitor.notifyKeyguardDoneFading();
3781         mScrimController.setExpansionAffectsAlpha(true);
3782     }
3783 
3784     // TODO: Move this to NotificationLockscreenUserManager.
updatePublicMode()3785     private void updatePublicMode() {
3786         final boolean showingKeyguard = mStatusBarKeyguardViewManager.isShowing();
3787         final boolean devicePublic = showingKeyguard
3788                 && mStatusBarKeyguardViewManager.isSecure(
3789                         mLockscreenUserManager.getCurrentUserId());
3790 
3791         // Look for public mode users. Users are considered public in either case of:
3792         //   - device keyguard is shown in secure mode;
3793         //   - profile is locked with a work challenge.
3794         SparseArray<UserInfo> currentProfiles = mLockscreenUserManager.getCurrentProfiles();
3795         for (int i = currentProfiles.size() - 1; i >= 0; i--) {
3796             final int userId = currentProfiles.valueAt(i).id;
3797             boolean isProfilePublic = devicePublic;
3798             if (!devicePublic && userId != mLockscreenUserManager.getCurrentUserId()) {
3799                 // We can't rely on KeyguardManager#isDeviceLocked() for unified profile challenge
3800                 // due to a race condition where this code could be called before
3801                 // TrustManagerService updates its internal records, resulting in an incorrect
3802                 // state being cached in mLockscreenPublicMode. (b/35951989)
3803                 if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)
3804                         && mStatusBarKeyguardViewManager.isSecure(userId)) {
3805                     isProfilePublic = mKeyguardManager.isDeviceLocked(userId);
3806                 }
3807             }
3808             mLockscreenUserManager.setLockscreenPublicMode(isProfilePublic, userId);
3809         }
3810     }
3811 
updateKeyguardState(boolean goingToFullShade, boolean fromShadeLocked)3812     protected void updateKeyguardState(boolean goingToFullShade, boolean fromShadeLocked) {
3813         Trace.beginSection("StatusBar#updateKeyguardState");
3814         if (mState == StatusBarState.KEYGUARD) {
3815             mKeyguardIndicationController.setVisible(true);
3816             mNotificationPanel.resetViews();
3817             if (mKeyguardUserSwitcher != null) {
3818                 mKeyguardUserSwitcher.setKeyguard(true, fromShadeLocked);
3819             }
3820             if (mStatusBarView != null) mStatusBarView.removePendingHideExpandedRunnables();
3821             if (mAmbientIndicationContainer != null) {
3822                 mAmbientIndicationContainer.setVisibility(View.VISIBLE);
3823             }
3824         } else {
3825             mKeyguardIndicationController.setVisible(false);
3826             if (mKeyguardUserSwitcher != null) {
3827                 mKeyguardUserSwitcher.setKeyguard(false,
3828                         goingToFullShade ||
3829                         mState == StatusBarState.SHADE_LOCKED ||
3830                         fromShadeLocked);
3831             }
3832             if (mAmbientIndicationContainer != null) {
3833                 mAmbientIndicationContainer.setVisibility(View.INVISIBLE);
3834             }
3835         }
3836         mNotificationPanel.setBarState(mState, mKeyguardFadingAway, goingToFullShade);
3837         updateTheme();
3838         updateDozingState();
3839         updatePublicMode();
3840         updateStackScrollerState(goingToFullShade, fromShadeLocked);
3841         mEntryManager.updateNotifications();
3842         checkBarModes();
3843         updateScrimController();
3844         updateMediaMetaData(false, mState != StatusBarState.KEYGUARD);
3845         mKeyguardMonitor.notifyKeyguardState(mStatusBarKeyguardViewManager.isShowing(),
3846                 mUnlockMethodCache.isMethodSecure(),
3847                 mStatusBarKeyguardViewManager.isOccluded());
3848         Trace.endSection();
3849     }
3850 
3851     /**
3852      * Switches theme from light to dark and vice-versa.
3853      */
updateTheme()3854     protected void updateTheme() {
3855         final boolean inflated = mStackScroller != null;
3856 
3857         // The system wallpaper defines if QS should be light or dark.
3858         WallpaperColors systemColors = mColorExtractor
3859                 .getWallpaperColors(WallpaperManager.FLAG_SYSTEM);
3860         final boolean useDarkTheme = systemColors != null
3861                 && (systemColors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_THEME) != 0;
3862         if (isUsingDarkTheme() != useDarkTheme) {
3863             mUiOffloadThread.submit(() -> {
3864                 try {
3865                     mOverlayManager.setEnabled("com.android.systemui.theme.dark",
3866                             useDarkTheme, mLockscreenUserManager.getCurrentUserId());
3867                 } catch (RemoteException e) {
3868                     Log.w(TAG, "Can't change theme", e);
3869                 }
3870             });
3871         }
3872 
3873         // Lock wallpaper defines the color of the majority of the views, hence we'll use it
3874         // to set our default theme.
3875         final boolean lockDarkText = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK, true
3876                 /* ignoreVisibility */).supportsDarkText();
3877         final int themeResId = lockDarkText ? R.style.Theme_SystemUI_Light : R.style.Theme_SystemUI;
3878         if (mContext.getThemeResId() != themeResId) {
3879             mContext.setTheme(themeResId);
3880             if (inflated) {
3881                 onThemeChanged();
3882             }
3883         }
3884 
3885         if (inflated) {
3886             int which;
3887             if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
3888                 which = WallpaperManager.FLAG_LOCK;
3889             } else {
3890                 which = WallpaperManager.FLAG_SYSTEM;
3891             }
3892             final boolean useDarkText = mColorExtractor.getColors(which,
3893                     true /* ignoreVisibility */).supportsDarkText();
3894             mStackScroller.updateDecorViews(useDarkText);
3895 
3896             // Make sure we have the correct navbar/statusbar colors.
3897             mStatusBarWindowManager.setKeyguardDark(useDarkText);
3898         }
3899     }
3900 
updateDozingState()3901     private void updateDozingState() {
3902         Trace.traceCounter(Trace.TRACE_TAG_APP, "dozing", mDozing ? 1 : 0);
3903         Trace.beginSection("StatusBar#updateDozingState");
3904 
3905         boolean sleepingFromKeyguard =
3906                 mStatusBarKeyguardViewManager.isGoingToSleepVisibleNotOccluded();
3907         boolean animate = (!mDozing && mDozeServiceHost.shouldAnimateWakeup())
3908                 || (mDozing && mDozeServiceHost.shouldAnimateScreenOff() && sleepingFromKeyguard);
3909 
3910         mStackScroller.setDark(mDozing, animate, mWakeUpTouchLocation);
3911         mDozeScrimController.setDozing(mDozing);
3912         mKeyguardIndicationController.setDozing(mDozing);
3913         mNotificationPanel.setDozing(mDozing, animate);
3914         updateQsExpansionEnabled();
3915         Trace.endSection();
3916     }
3917 
updateStackScrollerState(boolean goingToFullShade, boolean fromShadeLocked)3918     public void updateStackScrollerState(boolean goingToFullShade, boolean fromShadeLocked) {
3919         if (mStackScroller == null) return;
3920         boolean onKeyguard = mState == StatusBarState.KEYGUARD;
3921         boolean publicMode = mLockscreenUserManager.isAnyProfilePublicMode();
3922         if (mHeadsUpAppearanceController != null) {
3923             mHeadsUpAppearanceController.setPublicMode(publicMode);
3924         }
3925         mStackScroller.setHideSensitive(publicMode, goingToFullShade);
3926         mStackScroller.setDimmed(onKeyguard, fromShadeLocked /* animate */);
3927         mStackScroller.setExpandingEnabled(!onKeyguard);
3928         ActivatableNotificationView activatedChild = mStackScroller.getActivatedChild();
3929         mStackScroller.setActivatedChild(null);
3930         if (activatedChild != null) {
3931             activatedChild.makeInactive(false /* animate */);
3932         }
3933     }
3934 
userActivity()3935     public void userActivity() {
3936         if (mState == StatusBarState.KEYGUARD) {
3937             mKeyguardViewMediatorCallback.userActivity();
3938         }
3939     }
3940 
interceptMediaKey(KeyEvent event)3941     public boolean interceptMediaKey(KeyEvent event) {
3942         return mState == StatusBarState.KEYGUARD
3943                 && mStatusBarKeyguardViewManager.interceptMediaKey(event);
3944     }
3945 
shouldUnlockOnMenuPressed()3946     protected boolean shouldUnlockOnMenuPressed() {
3947         return mDeviceInteractive && mState != StatusBarState.SHADE
3948             && mStatusBarKeyguardViewManager.shouldDismissOnMenuPressed();
3949     }
3950 
onMenuPressed()3951     public boolean onMenuPressed() {
3952         if (shouldUnlockOnMenuPressed()) {
3953             animateCollapsePanels(
3954                     CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL /* flags */, true /* force */);
3955             return true;
3956         }
3957         return false;
3958     }
3959 
endAffordanceLaunch()3960     public void endAffordanceLaunch() {
3961         releaseGestureWakeLock();
3962         mNotificationPanel.onAffordanceLaunchEnded();
3963     }
3964 
onBackPressed()3965     public boolean onBackPressed() {
3966         boolean isScrimmedBouncer = mScrimController.getState() == ScrimState.BOUNCER_SCRIMMED;
3967         if (mStatusBarKeyguardViewManager.onBackPressed(isScrimmedBouncer /* hideImmediately */)) {
3968             if (!isScrimmedBouncer) {
3969                 mNotificationPanel.expandWithoutQs();
3970             }
3971             return true;
3972         }
3973         if (mNotificationPanel.isQsExpanded()) {
3974             if (mNotificationPanel.isQsDetailShowing()) {
3975                 mNotificationPanel.closeQsDetail();
3976             } else {
3977                 mNotificationPanel.animateCloseQs();
3978             }
3979             return true;
3980         }
3981         if (mState != StatusBarState.KEYGUARD && mState != StatusBarState.SHADE_LOCKED) {
3982             animateCollapsePanels();
3983             return true;
3984         }
3985         if (mKeyguardUserSwitcher != null && mKeyguardUserSwitcher.hideIfNotSimple(true)) {
3986             return true;
3987         }
3988         return false;
3989     }
3990 
onSpacePressed()3991     public boolean onSpacePressed() {
3992         if (mDeviceInteractive && mState != StatusBarState.SHADE) {
3993             animateCollapsePanels(
3994                     CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL /* flags */, true /* force */);
3995             return true;
3996         }
3997         return false;
3998     }
3999 
showBouncerIfKeyguard()4000     private void showBouncerIfKeyguard() {
4001         if ((mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)
4002                 && !mKeyguardViewMediator.isHiding()) {
4003             showBouncer(true /* scrimmed */);
4004         }
4005     }
4006 
showBouncer(boolean scrimmed)4007     protected void showBouncer(boolean scrimmed) {
4008         mStatusBarKeyguardViewManager.showBouncer(scrimmed);
4009     }
4010 
instantExpandNotificationsPanel()4011     private void instantExpandNotificationsPanel() {
4012         // Make our window larger and the panel expanded.
4013         makeExpandedVisible(true);
4014         mNotificationPanel.expand(false /* animate */);
4015         recomputeDisableFlags(false /* animate */);
4016     }
4017 
instantCollapseNotificationPanel()4018     private void instantCollapseNotificationPanel() {
4019         mNotificationPanel.instantCollapse();
4020         runPostCollapseRunnables();
4021     }
4022 
4023     @Override
onActivated(ActivatableNotificationView view)4024     public void onActivated(ActivatableNotificationView view) {
4025         onActivated((View) view);
4026         mStackScroller.setActivatedChild(view);
4027     }
4028 
onActivated(View view)4029     public void onActivated(View view) {
4030         mLockscreenGestureLogger.write(
4031                 MetricsEvent.ACTION_LS_NOTE,
4032                 0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */);
4033         mKeyguardIndicationController.showTransientIndication(R.string.notification_tap_again);
4034         ActivatableNotificationView previousView = mStackScroller.getActivatedChild();
4035         if (previousView != null) {
4036             previousView.makeInactive(true /* animate */);
4037         }
4038     }
4039 
4040     /**
4041      * @param state The {@link StatusBarState} to set.
4042      */
setBarState(int state)4043     public void setBarState(int state) {
4044         // If we're visible and switched to SHADE_LOCKED (the user dragged
4045         // down on the lockscreen), clear notification LED, vibration,
4046         // ringing.
4047         // Other transitions are covered in handleVisibleToUserChanged().
4048         if (state != mState && mVisible && (state == StatusBarState.SHADE_LOCKED
4049                 || (state == StatusBarState.SHADE && isGoingToNotificationShade()))) {
4050             clearNotificationEffects();
4051         }
4052         if (state == StatusBarState.KEYGUARD) {
4053             mRemoteInputManager.removeRemoteInputEntriesKeptUntilCollapsed();
4054             maybeEscalateHeadsUp();
4055         }
4056         mState = state;
4057         mGroupManager.setStatusBarState(state);
4058         mHeadsUpManager.setStatusBarState(state);
4059         mFalsingManager.setStatusBarState(state);
4060         mStatusBarWindowManager.setStatusBarState(state);
4061         mStackScroller.setStatusBarState(state);
4062         updateReportRejectedTouchVisibility();
4063         updateDozing();
4064         updateTheme();
4065         touchAutoDim();
4066         mNotificationShelf.setStatusBarState(state);
4067     }
4068 
4069     @Override
onActivationReset(ActivatableNotificationView view)4070     public void onActivationReset(ActivatableNotificationView view) {
4071         if (view == mStackScroller.getActivatedChild()) {
4072             mStackScroller.setActivatedChild(null);
4073             onActivationReset((View)view);
4074         }
4075     }
4076 
onActivationReset(View view)4077     public void onActivationReset(View view) {
4078         mKeyguardIndicationController.hideTransientIndication();
4079     }
4080 
onTrackingStarted()4081     public void onTrackingStarted() {
4082         runPostCollapseRunnables();
4083     }
4084 
onClosingFinished()4085     public void onClosingFinished() {
4086         runPostCollapseRunnables();
4087         if (!isPresenterFullyCollapsed()) {
4088             // if we set it not to be focusable when collapsing, we have to undo it when we aborted
4089             // the closing
4090             mStatusBarWindowManager.setStatusBarFocusable(true);
4091         }
4092     }
4093 
onUnlockHintStarted()4094     public void onUnlockHintStarted() {
4095         mFalsingManager.onUnlockHintStarted();
4096         mKeyguardIndicationController.showTransientIndication(R.string.keyguard_unlock);
4097     }
4098 
onHintFinished()4099     public void onHintFinished() {
4100         // Delay the reset a bit so the user can read the text.
4101         mKeyguardIndicationController.hideTransientIndicationDelayed(HINT_RESET_DELAY_MS);
4102     }
4103 
onCameraHintStarted()4104     public void onCameraHintStarted() {
4105         mFalsingManager.onCameraHintStarted();
4106         mKeyguardIndicationController.showTransientIndication(R.string.camera_hint);
4107     }
4108 
onVoiceAssistHintStarted()4109     public void onVoiceAssistHintStarted() {
4110         mFalsingManager.onLeftAffordanceHintStarted();
4111         mKeyguardIndicationController.showTransientIndication(R.string.voice_hint);
4112     }
4113 
onPhoneHintStarted()4114     public void onPhoneHintStarted() {
4115         mFalsingManager.onLeftAffordanceHintStarted();
4116         mKeyguardIndicationController.showTransientIndication(R.string.phone_hint);
4117     }
4118 
onTrackingStopped(boolean expand)4119     public void onTrackingStopped(boolean expand) {
4120         if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
4121             if (!expand && !mUnlockMethodCache.canSkipBouncer()) {
4122                 showBouncer(false /* scrimmed */);
4123             }
4124         }
4125     }
4126 
4127     @Override
getMaxNotificationsWhileLocked(boolean recompute)4128     public int getMaxNotificationsWhileLocked(boolean recompute) {
4129         if (recompute) {
4130             mMaxKeyguardNotifications = Math.max(1,
4131                     mNotificationPanel.computeMaxKeyguardNotifications(
4132                             mMaxAllowedKeyguardNotifications));
4133             return mMaxKeyguardNotifications;
4134         }
4135         return mMaxKeyguardNotifications;
4136     }
4137 
getMaxNotificationsWhileLocked()4138     public int getMaxNotificationsWhileLocked() {
4139         return getMaxNotificationsWhileLocked(false /* recompute */);
4140     }
4141 
4142     // TODO: Figure out way to remove these.
getNavigationBarView()4143     public NavigationBarView getNavigationBarView() {
4144         return (mNavigationBar != null ? (NavigationBarView) mNavigationBar.getView() : null);
4145     }
4146 
getNavigationBarWindow()4147     public View getNavigationBarWindow() {
4148         return mNavigationBarView;
4149     }
4150 
4151     /**
4152      * TODO: Remove this method. Views should not be passed forward. Will cause theme issues.
4153      * @return bottom area view
4154      */
getKeyguardBottomAreaView()4155     public KeyguardBottomAreaView getKeyguardBottomAreaView() {
4156         return mNotificationPanel.getKeyguardBottomAreaView();
4157     }
4158 
4159     // ---------------------- DragDownHelper.OnDragDownListener ------------------------------------
4160 
4161 
4162     /* Only ever called as a consequence of a lockscreen expansion gesture. */
4163     @Override
onDraggedDown(View startingChild, int dragLengthY)4164     public boolean onDraggedDown(View startingChild, int dragLengthY) {
4165         if (mState == StatusBarState.KEYGUARD
4166                 && hasActiveNotifications() && (!isDozing() || isPulsing())) {
4167             mLockscreenGestureLogger.write(
4168                     MetricsEvent.ACTION_LS_SHADE,
4169                     (int) (dragLengthY / mDisplayMetrics.density),
4170                     0 /* velocityDp - N/A */);
4171 
4172             // We have notifications, go to locked shade.
4173             goToLockedShade(startingChild);
4174             if (startingChild instanceof ExpandableNotificationRow) {
4175                 ExpandableNotificationRow row = (ExpandableNotificationRow) startingChild;
4176                 row.onExpandedByGesture(true /* drag down is always an open */);
4177             }
4178             return true;
4179         } else {
4180             // abort gesture.
4181             return false;
4182         }
4183     }
4184 
4185     @Override
onDragDownReset()4186     public void onDragDownReset() {
4187         mStackScroller.setDimmed(true /* dimmed */, true /* animated */);
4188         mStackScroller.resetScrollPosition();
4189         mStackScroller.resetCheckSnoozeLeavebehind();
4190     }
4191 
4192     @Override
onCrossedThreshold(boolean above)4193     public void onCrossedThreshold(boolean above) {
4194         mStackScroller.setDimmed(!above /* dimmed */, true /* animate */);
4195     }
4196 
4197     @Override
onTouchSlopExceeded()4198     public void onTouchSlopExceeded() {
4199         mStackScroller.cancelLongPress();
4200         mStackScroller.checkSnoozeLeavebehind();
4201     }
4202 
4203     @Override
setEmptyDragAmount(float amount)4204     public void setEmptyDragAmount(float amount) {
4205         mNotificationPanel.setEmptyDragAmount(amount);
4206     }
4207 
4208     @Override
isFalsingCheckNeeded()4209     public boolean isFalsingCheckNeeded() {
4210         return mState == StatusBarState.KEYGUARD;
4211     }
4212 
4213     /**
4214      * If secure with redaction: Show bouncer, go to unlocked shade.
4215      *
4216      * <p>If secure without redaction or no security: Go to {@link StatusBarState#SHADE_LOCKED}.</p>
4217      *
4218      * @param expandView The view to expand after going to the shade.
4219      */
goToLockedShade(View expandView)4220     public void goToLockedShade(View expandView) {
4221         if ((mDisabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0) {
4222             return;
4223         }
4224 
4225         int userId = mLockscreenUserManager.getCurrentUserId();
4226         ExpandableNotificationRow row = null;
4227         if (expandView instanceof ExpandableNotificationRow) {
4228             row = (ExpandableNotificationRow) expandView;
4229             row.setUserExpanded(true /* userExpanded */, true /* allowChildExpansion */);
4230             // Indicate that the group expansion is changing at this time -- this way the group
4231             // and children backgrounds / divider animations will look correct.
4232             row.setGroupExpansionChanging(true);
4233             if (row.getStatusBarNotification() != null) {
4234                 userId = row.getStatusBarNotification().getUserId();
4235             }
4236         }
4237         boolean fullShadeNeedsBouncer = !mLockscreenUserManager.
4238                 userAllowsPrivateNotificationsInPublic(mLockscreenUserManager.getCurrentUserId())
4239                 || !mLockscreenUserManager.shouldShowLockscreenNotifications()
4240                 || mFalsingManager.shouldEnforceBouncer();
4241         if (mLockscreenUserManager.isLockscreenPublicMode(userId) && fullShadeNeedsBouncer) {
4242             mLeaveOpenOnKeyguardHide = true;
4243             showBouncerIfKeyguard();
4244             mDraggedDownRow = row;
4245             mPendingRemoteInputView = null;
4246         } else {
4247             mNotificationPanel.animateToFullShade(0 /* delay */);
4248             setBarState(StatusBarState.SHADE_LOCKED);
4249             updateKeyguardState(false /* goingToFullShade */, false /* fromShadeLocked */);
4250         }
4251     }
4252 
onLockedNotificationImportanceChange(OnDismissAction dismissAction)4253     public void onLockedNotificationImportanceChange(OnDismissAction dismissAction) {
4254         mLeaveOpenOnKeyguardHide = true;
4255         dismissKeyguardThenExecute(dismissAction, true /* afterKeyguardGone */);
4256     }
4257 
4258     @Override
onLockedRemoteInput(ExpandableNotificationRow row, View clicked)4259     public void onLockedRemoteInput(ExpandableNotificationRow row, View clicked) {
4260         mLeaveOpenOnKeyguardHide = true;
4261         showBouncer(true /* scrimmed */);
4262         mPendingRemoteInputView = clicked;
4263     }
4264 
4265     @Override
onMakeExpandedVisibleForRemoteInput(ExpandableNotificationRow row, View clickedView)4266     public void onMakeExpandedVisibleForRemoteInput(ExpandableNotificationRow row,
4267             View clickedView) {
4268         if (isKeyguardShowing()) {
4269             onLockedRemoteInput(row, clickedView);
4270         } else {
4271             row.setUserExpanded(true);
4272             row.getPrivateLayout().setOnExpandedVisibleListener(clickedView::performClick);
4273         }
4274     }
4275 
4276     @Override
shouldHandleRemoteInput(View view, PendingIntent pendingIntent)4277     public boolean shouldHandleRemoteInput(View view, PendingIntent pendingIntent) {
4278         // Skip remote input as doing so will expand the notification shade.
4279         return (mDisabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0;
4280     }
4281 
4282     @Override
handleRemoteViewClick(View view, PendingIntent pendingIntent, Intent fillInIntent, NotificationRemoteInputManager.ClickHandler defaultHandler)4283     public boolean handleRemoteViewClick(View view, PendingIntent pendingIntent,
4284             Intent fillInIntent, NotificationRemoteInputManager.ClickHandler defaultHandler) {
4285         final boolean isActivity = pendingIntent.isActivity();
4286         if (isActivity) {
4287             final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity(
4288                     mContext, pendingIntent.getIntent(), mLockscreenUserManager.getCurrentUserId());
4289             dismissKeyguardThenExecute(() -> {
4290                 try {
4291                     ActivityManager.getService().resumeAppSwitches();
4292                 } catch (RemoteException e) {
4293                 }
4294 
4295                 boolean handled = defaultHandler.handleClick();
4296 
4297                 // close the shade if it was open
4298                 if (handled && !mNotificationPanel.isFullyCollapsed()) {
4299                     animateCollapsePanels(
4300                             CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */);
4301                     visibilityChanged(false);
4302                     mAssistManager.hideAssist();
4303 
4304                     // Wait for activity start.
4305                     return true;
4306                 } else {
4307                     return false;
4308                 }
4309 
4310             }, afterKeyguardGone);
4311             return true;
4312         } else {
4313             return defaultHandler.handleClick();
4314         }
4315     }
4316 
startWorkChallengeIfNecessary(int userId, IntentSender intendSender, String notificationKey)4317     protected boolean startWorkChallengeIfNecessary(int userId, IntentSender intendSender,
4318             String notificationKey) {
4319         // Clear pending remote view, as we do not want to trigger pending remote input view when
4320         // it's called by other code
4321         mPendingWorkRemoteInputView = null;
4322         // Begin old BaseStatusBar.startWorkChallengeIfNecessary.
4323         final Intent newIntent = mKeyguardManager.createConfirmDeviceCredentialIntent(null,
4324                 null, userId);
4325         if (newIntent == null) {
4326             return false;
4327         }
4328         final Intent callBackIntent = new Intent(NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION);
4329         callBackIntent.putExtra(Intent.EXTRA_INTENT, intendSender);
4330         callBackIntent.putExtra(Intent.EXTRA_INDEX, notificationKey);
4331         callBackIntent.setPackage(mContext.getPackageName());
4332 
4333         PendingIntent callBackPendingIntent = PendingIntent.getBroadcast(
4334                 mContext,
4335                 0,
4336                 callBackIntent,
4337                 PendingIntent.FLAG_CANCEL_CURRENT |
4338                         PendingIntent.FLAG_ONE_SHOT |
4339                         PendingIntent.FLAG_IMMUTABLE);
4340         newIntent.putExtra(
4341                 Intent.EXTRA_INTENT,
4342                 callBackPendingIntent.getIntentSender());
4343         try {
4344             ActivityManager.getService().startConfirmDeviceCredentialIntent(newIntent,
4345                     null /*options*/);
4346         } catch (RemoteException ex) {
4347             // ignore
4348         }
4349         return true;
4350         // End old BaseStatusBar.startWorkChallengeIfNecessary.
4351     }
4352 
4353     @Override
onLockedWorkRemoteInput(int userId, ExpandableNotificationRow row, View clicked)4354     public void onLockedWorkRemoteInput(int userId, ExpandableNotificationRow row,
4355             View clicked) {
4356         // Collapse notification and show work challenge
4357         animateCollapsePanels();
4358         startWorkChallengeIfNecessary(userId, null, null);
4359         // Add pending remote input view after starting work challenge, as starting work challenge
4360         // will clear all previous pending review view
4361         mPendingWorkRemoteInputView = clicked;
4362     }
4363 
4364     @Override
onWorkChallengeChanged()4365     public void onWorkChallengeChanged() {
4366         updatePublicMode();
4367         mEntryManager.updateNotifications();
4368         if (mPendingWorkRemoteInputView != null
4369                 && !mLockscreenUserManager.isAnyProfilePublicMode()) {
4370             // Expand notification panel and the notification row, then click on remote input view
4371             final Runnable clickPendingViewRunnable = () -> {
4372                 final View pendingWorkRemoteInputView = mPendingWorkRemoteInputView;
4373                 if (pendingWorkRemoteInputView == null) {
4374                     return;
4375                 }
4376 
4377                 // Climb up the hierarchy until we get to the container for this row.
4378                 ViewParent p = pendingWorkRemoteInputView.getParent();
4379                 while (!(p instanceof ExpandableNotificationRow)) {
4380                     if (p == null) {
4381                         return;
4382                     }
4383                     p = p.getParent();
4384                 }
4385 
4386                 final ExpandableNotificationRow row = (ExpandableNotificationRow) p;
4387                 ViewParent viewParent = row.getParent();
4388                 if (viewParent instanceof NotificationStackScrollLayout) {
4389                     final NotificationStackScrollLayout scrollLayout =
4390                             (NotificationStackScrollLayout) viewParent;
4391                     row.makeActionsVisibile();
4392                     row.post(() -> {
4393                         final Runnable finishScrollingCallback = () -> {
4394                             mPendingWorkRemoteInputView.callOnClick();
4395                             mPendingWorkRemoteInputView = null;
4396                             scrollLayout.setFinishScrollingCallback(null);
4397                         };
4398                         if (scrollLayout.scrollTo(row)) {
4399                             // It scrolls! So call it when it's finished.
4400                             scrollLayout.setFinishScrollingCallback(finishScrollingCallback);
4401                         } else {
4402                             // It does not scroll, so call it now!
4403                             finishScrollingCallback.run();
4404                         }
4405                     });
4406                 }
4407             };
4408             mNotificationPanel.getViewTreeObserver().addOnGlobalLayoutListener(
4409                     new ViewTreeObserver.OnGlobalLayoutListener() {
4410                         @Override
4411                         public void onGlobalLayout() {
4412                             if (mNotificationPanel.mStatusBar.getStatusBarWindow()
4413                                     .getHeight() != mNotificationPanel.mStatusBar
4414                                             .getStatusBarHeight()) {
4415                                 mNotificationPanel.getViewTreeObserver()
4416                                         .removeOnGlobalLayoutListener(this);
4417                                 mNotificationPanel.post(clickPendingViewRunnable);
4418                             }
4419                         }
4420                     });
4421             instantExpandNotificationsPanel();
4422         }
4423     }
4424 
4425     @Override
onExpandClicked(Entry clickedEntry, boolean nowExpanded)4426     public void onExpandClicked(Entry clickedEntry, boolean nowExpanded) {
4427         mHeadsUpManager.setExpanded(clickedEntry, nowExpanded);
4428         if (mState == StatusBarState.KEYGUARD && nowExpanded) {
4429             goToLockedShade(clickedEntry.row);
4430         }
4431     }
4432 
4433     /**
4434      * Goes back to the keyguard after hanging around in {@link StatusBarState#SHADE_LOCKED}.
4435      */
goToKeyguard()4436     public void goToKeyguard() {
4437         if (mState == StatusBarState.SHADE_LOCKED) {
4438             mStackScroller.onGoToKeyguard();
4439             setBarState(StatusBarState.KEYGUARD);
4440             updateKeyguardState(false /* goingToFullShade */, true /* fromShadeLocked*/);
4441         }
4442     }
4443 
getKeyguardFadingAwayDelay()4444     public long getKeyguardFadingAwayDelay() {
4445         return mKeyguardFadingAwayDelay;
4446     }
4447 
getKeyguardFadingAwayDuration()4448     public long getKeyguardFadingAwayDuration() {
4449         return mKeyguardFadingAwayDuration;
4450     }
4451 
setBouncerShowing(boolean bouncerShowing)4452     public void setBouncerShowing(boolean bouncerShowing) {
4453         mBouncerShowing = bouncerShowing;
4454         if (mStatusBarView != null) mStatusBarView.setBouncerShowing(bouncerShowing);
4455         updateHideIconsForBouncer(true /* animate */);
4456         recomputeDisableFlags(true /* animate */);
4457         updateScrimController();
4458     }
4459 
cancelCurrentTouch()4460     public void cancelCurrentTouch() {
4461         if (mNotificationPanel.isTracking()) {
4462             mStatusBarWindow.cancelCurrentTouch();
4463             if (mState == StatusBarState.SHADE) {
4464                 animateCollapsePanels();
4465             }
4466         }
4467     }
4468 
4469     final WakefulnessLifecycle.Observer mWakefulnessObserver = new WakefulnessLifecycle.Observer() {
4470         @Override
4471         public void onFinishedGoingToSleep() {
4472             mNotificationPanel.onAffordanceLaunchEnded();
4473             releaseGestureWakeLock();
4474             mLaunchCameraOnScreenTurningOn = false;
4475             mDeviceInteractive = false;
4476             mWakeUpComingFromTouch = false;
4477             mWakeUpTouchLocation = null;
4478             mStackScroller.setAnimationsEnabled(false);
4479             mVisualStabilityManager.setScreenOn(false);
4480             updateVisibleToUser();
4481 
4482             // We need to disable touch events because these might
4483             // collapse the panel after we expanded it, and thus we would end up with a blank
4484             // Keyguard.
4485             mNotificationPanel.setTouchDisabled(true);
4486             mStatusBarWindow.cancelCurrentTouch();
4487             if (mLaunchCameraOnFinishedGoingToSleep) {
4488                 mLaunchCameraOnFinishedGoingToSleep = false;
4489 
4490                 // This gets executed before we will show Keyguard, so post it in order that the state
4491                 // is correct.
4492                 mHandler.post(() -> onCameraLaunchGestureDetected(mLastCameraLaunchSource));
4493             }
4494             updateIsKeyguard();
4495         }
4496 
4497         @Override
4498         public void onStartedGoingToSleep() {
4499             notifyHeadsUpGoingToSleep();
4500             dismissVolumeDialog();
4501         }
4502 
4503         @Override
4504         public void onStartedWakingUp() {
4505             mDeviceInteractive = true;
4506             mStackScroller.setAnimationsEnabled(true);
4507             mVisualStabilityManager.setScreenOn(true);
4508             mNotificationPanel.setTouchDisabled(false);
4509             mDozeServiceHost.stopDozing();
4510             updateVisibleToUser();
4511             updateIsKeyguard();
4512             updateScrimController();
4513         }
4514     };
4515 
4516     final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() {
4517         @Override
4518         public void onScreenTurningOn() {
4519             mFalsingManager.onScreenTurningOn();
4520             mNotificationPanel.onScreenTurningOn();
4521 
4522             if (mLaunchCameraOnScreenTurningOn) {
4523                 mNotificationPanel.launchCamera(false, mLastCameraLaunchSource);
4524                 mLaunchCameraOnScreenTurningOn = false;
4525             }
4526 
4527             updateScrimController();
4528         }
4529 
4530         @Override
4531         public void onScreenTurnedOn() {
4532             mScrimController.onScreenTurnedOn();
4533         }
4534 
4535         @Override
4536         public void onScreenTurnedOff() {
4537             mFalsingManager.onScreenOff();
4538             mScrimController.onScreenTurnedOff();
4539             // If we pulse in from AOD, we turn the screen off first. However, updatingIsKeyguard
4540             // in that case destroys the HeadsUpManager state, so don't do it in that case.
4541             if (!isPulsing()) {
4542                 updateIsKeyguard();
4543             }
4544         }
4545     };
4546 
getWakefulnessState()4547     public int getWakefulnessState() {
4548         return mWakefulnessLifecycle.getWakefulness();
4549     }
4550 
vibrateForCameraGesture()4551     private void vibrateForCameraGesture() {
4552         // Make sure to pass -1 for repeat so VibratorService doesn't stop us when going to sleep.
4553         mVibrator.vibrate(mCameraLaunchGestureVibePattern, -1 /* repeat */);
4554     }
4555 
4556     /**
4557      * @return true if the screen is currently fully off, i.e. has finished turning off and has
4558      *         since not started turning on.
4559      */
isScreenFullyOff()4560     public boolean isScreenFullyOff() {
4561         return mScreenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_OFF;
4562     }
4563 
4564     @Override
showScreenPinningRequest(int taskId)4565     public void showScreenPinningRequest(int taskId) {
4566         if (mKeyguardMonitor.isShowing()) {
4567             // Don't allow apps to trigger this from keyguard.
4568             return;
4569         }
4570         // Show screen pinning request, since this comes from an app, show 'no thanks', button.
4571         showScreenPinningRequest(taskId, true);
4572     }
4573 
showScreenPinningRequest(int taskId, boolean allowCancel)4574     public void showScreenPinningRequest(int taskId, boolean allowCancel) {
4575         mScreenPinningRequest.showPrompt(taskId, allowCancel);
4576     }
4577 
hasActiveNotifications()4578     public boolean hasActiveNotifications() {
4579         return !mEntryManager.getNotificationData().getActiveNotifications().isEmpty();
4580     }
4581 
4582     @Override
wakeUpIfDozing(long time, View where)4583     public void wakeUpIfDozing(long time, View where) {
4584         if (mDozing) {
4585             PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
4586             pm.wakeUp(time, "com.android.systemui:NODOZE");
4587             mWakeUpComingFromTouch = true;
4588             where.getLocationInWindow(mTmpInt2);
4589             mWakeUpTouchLocation = new PointF(mTmpInt2[0] + where.getWidth() / 2,
4590                     mTmpInt2[1] + where.getHeight() / 2);
4591             mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested();
4592             mFalsingManager.onScreenOnFromTouch();
4593         }
4594     }
4595 
4596     @Override
isDeviceLocked(int userId)4597     public boolean isDeviceLocked(int userId) {
4598         return mKeyguardManager.isDeviceLocked(userId);
4599     }
4600 
4601     @Override
appTransitionCancelled()4602     public void appTransitionCancelled() {
4603         EventBus.getDefault().send(new AppTransitionFinishedEvent());
4604     }
4605 
4606     @Override
appTransitionFinished()4607     public void appTransitionFinished() {
4608         EventBus.getDefault().send(new AppTransitionFinishedEvent());
4609     }
4610 
4611     @Override
onCameraLaunchGestureDetected(int source)4612     public void onCameraLaunchGestureDetected(int source) {
4613         mLastCameraLaunchSource = source;
4614         if (isGoingToSleep()) {
4615             if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Finish going to sleep before launching camera");
4616             mLaunchCameraOnFinishedGoingToSleep = true;
4617             return;
4618         }
4619         if (!mNotificationPanel.canCameraGestureBeLaunched(
4620                 mStatusBarKeyguardViewManager.isShowing() && mExpandedVisible)) {
4621             if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Can't launch camera right now, mExpandedVisible: " +
4622                     mExpandedVisible);
4623             return;
4624         }
4625         if (!mDeviceInteractive) {
4626             PowerManager pm = mContext.getSystemService(PowerManager.class);
4627             pm.wakeUp(SystemClock.uptimeMillis(), "com.android.systemui:CAMERA_GESTURE");
4628             mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested();
4629         }
4630         vibrateForCameraGesture();
4631         if (!mStatusBarKeyguardViewManager.isShowing()) {
4632             startActivityDismissingKeyguard(KeyguardBottomAreaView.INSECURE_CAMERA_INTENT,
4633                     false /* onlyProvisioned */, true /* dismissShade */,
4634                     true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */, 0);
4635         } else {
4636             if (!mDeviceInteractive) {
4637                 // Avoid flickering of the scrim when we instant launch the camera and the bouncer
4638                 // comes on.
4639                 mGestureWakeLock.acquire(LAUNCH_TRANSITION_TIMEOUT_MS + 1000L);
4640             }
4641             if (isScreenTurningOnOrOn()) {
4642                 if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Launching camera");
4643                 if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
4644                     mStatusBarKeyguardViewManager.reset(true /* hide */);
4645                 }
4646                 mNotificationPanel.launchCamera(mDeviceInteractive /* animate */, source);
4647                 updateScrimController();
4648             } else {
4649                 // We need to defer the camera launch until the screen comes on, since otherwise
4650                 // we will dismiss us too early since we are waiting on an activity to be drawn and
4651                 // incorrectly get notified because of the screen on event (which resumes and pauses
4652                 // some activities)
4653                 if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Deferring until screen turns on");
4654                 mLaunchCameraOnScreenTurningOn = true;
4655             }
4656         }
4657     }
4658 
isCameraAllowedByAdmin()4659     boolean isCameraAllowedByAdmin() {
4660         if (mDevicePolicyManager.getCameraDisabled(null,
4661                 mLockscreenUserManager.getCurrentUserId())) {
4662             return false;
4663         } else if (mStatusBarKeyguardViewManager == null ||
4664                 (isKeyguardShowing() && isKeyguardSecure())) {
4665             // Check if the admin has disabled the camera specifically for the keyguard
4666             return (mDevicePolicyManager.
4667                     getKeyguardDisabledFeatures(null, mLockscreenUserManager.getCurrentUserId())
4668                     & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) == 0;
4669         }
4670 
4671         return true;
4672     }
4673 
isGoingToSleep()4674     private boolean isGoingToSleep() {
4675         return mWakefulnessLifecycle.getWakefulness()
4676                 == WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP;
4677     }
4678 
isScreenTurningOnOrOn()4679     private boolean isScreenTurningOnOrOn() {
4680         return mScreenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_TURNING_ON
4681                 || mScreenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_ON;
4682     }
4683 
notifyFpAuthModeChanged()4684     public void notifyFpAuthModeChanged() {
4685         updateDozing();
4686         updateScrimController();
4687     }
4688 
updateDozing()4689     private void updateDozing() {
4690         Trace.beginSection("StatusBar#updateDozing");
4691         // When in wake-and-unlock while pulsing, keep dozing state until fully unlocked.
4692         boolean dozing = mDozingRequested && mState == StatusBarState.KEYGUARD
4693                 || mFingerprintUnlockController.getMode()
4694                         == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING;
4695         final boolean alwaysOn = DozeParameters.getInstance(mContext).getAlwaysOn();
4696         // When in wake-and-unlock we may not have received a change to mState
4697         // but we still should not be dozing, manually set to false.
4698         if (mFingerprintUnlockController.getMode() ==
4699                 FingerprintUnlockController.MODE_WAKE_AND_UNLOCK) {
4700             dozing = false;
4701         }
4702         if (mDozing != dozing) {
4703             mDozing = dozing;
4704             mKeyguardViewMediator.setAodShowing(mDozing && alwaysOn);
4705             mStatusBarWindowManager.setDozing(mDozing);
4706             mStatusBarKeyguardViewManager.setDozing(mDozing);
4707             if (mAmbientIndicationContainer instanceof DozeReceiver) {
4708                 ((DozeReceiver) mAmbientIndicationContainer).setDozing(mDozing);
4709             }
4710             mEntryManager.updateNotifications();
4711             updateDozingState();
4712             updateReportRejectedTouchVisibility();
4713         }
4714         Trace.endSection();
4715     }
4716 
4717     @VisibleForTesting
updateScrimController()4718     void updateScrimController() {
4719         Trace.beginSection("StatusBar#updateScrimController");
4720 
4721         // We don't want to end up in KEYGUARD state when we're unlocking with
4722         // fingerprint from doze. We should cross fade directly from black.
4723         boolean wakeAndUnlocking = mFingerprintUnlockController.isWakeAndUnlock();
4724 
4725         // Do not animate the scrim expansion when triggered by the fingerprint sensor.
4726         mScrimController.setExpansionAffectsAlpha(
4727                 !mFingerprintUnlockController.isFingerprintUnlock());
4728 
4729         if (mBouncerShowing) {
4730             // Bouncer needs the front scrim when it's on top of an activity,
4731             // tapping on a notification, editing QS or being dismissed by
4732             // FLAG_DISMISS_KEYGUARD_ACTIVITY.
4733             ScrimState state = mIsOccluded || mStatusBarKeyguardViewManager.bouncerNeedsScrimming()
4734                     || mStatusBarKeyguardViewManager.willDismissWithAction()
4735                     || mStatusBarKeyguardViewManager.isFullscreenBouncer() ?
4736                     ScrimState.BOUNCER_SCRIMMED : ScrimState.BOUNCER;
4737             mScrimController.transitionTo(state);
4738         } else if (mLaunchCameraOnScreenTurningOn || isInLaunchTransition()) {
4739             mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback);
4740         } else if (mBrightnessMirrorVisible) {
4741             mScrimController.transitionTo(ScrimState.BRIGHTNESS_MIRROR);
4742         } else if (isPulsing()) {
4743             // Handled in DozeScrimController#setPulsing
4744         } else if (mDozing) {
4745             mScrimController.transitionTo(ScrimState.AOD);
4746         } else if (mIsKeyguard && !wakeAndUnlocking) {
4747             mScrimController.transitionTo(ScrimState.KEYGUARD);
4748         } else {
4749             mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback);
4750         }
4751         Trace.endSection();
4752     }
4753 
isKeyguardShowing()4754     public boolean isKeyguardShowing() {
4755         if (mStatusBarKeyguardViewManager == null) {
4756             Slog.i(TAG, "isKeyguardShowing() called before startKeyguard(), returning true");
4757             return true;
4758         }
4759         return mStatusBarKeyguardViewManager.isShowing();
4760     }
4761 
4762     private final class DozeServiceHost implements DozeHost {
4763         private final ArrayList<Callback> mCallbacks = new ArrayList<>();
4764         private boolean mAnimateWakeup;
4765         private boolean mAnimateScreenOff;
4766         private boolean mIgnoreTouchWhilePulsing;
4767 
4768         @Override
toString()4769         public String toString() {
4770             return "PSB.DozeServiceHost[mCallbacks=" + mCallbacks.size() + "]";
4771         }
4772 
firePowerSaveChanged(boolean active)4773         public void firePowerSaveChanged(boolean active) {
4774             for (Callback callback : mCallbacks) {
4775                 callback.onPowerSaveChanged(active);
4776             }
4777         }
4778 
fireNotificationHeadsUp()4779         public void fireNotificationHeadsUp() {
4780             for (Callback callback : mCallbacks) {
4781                 callback.onNotificationHeadsUp();
4782             }
4783         }
4784 
4785         @Override
addCallback(@onNull Callback callback)4786         public void addCallback(@NonNull Callback callback) {
4787             mCallbacks.add(callback);
4788         }
4789 
4790         @Override
removeCallback(@onNull Callback callback)4791         public void removeCallback(@NonNull Callback callback) {
4792             mCallbacks.remove(callback);
4793         }
4794 
4795         @Override
startDozing()4796         public void startDozing() {
4797             if (!mDozingRequested) {
4798                 mDozingRequested = true;
4799                 DozeLog.traceDozing(mContext, mDozing);
4800                 updateDozing();
4801                 updateIsKeyguard();
4802             }
4803         }
4804 
4805         @Override
pulseWhileDozing(@onNull PulseCallback callback, int reason)4806         public void pulseWhileDozing(@NonNull PulseCallback callback, int reason) {
4807             if (reason == DozeLog.PULSE_REASON_SENSOR_LONG_PRESS) {
4808                 mPowerManager.wakeUp(SystemClock.uptimeMillis(), "com.android.systemui:NODOZE");
4809                 startAssist(new Bundle());
4810                 return;
4811             }
4812 
4813             mDozeScrimController.pulse(new PulseCallback() {
4814                 @Override
4815                 public void onPulseStarted() {
4816                     callback.onPulseStarted();
4817                     if (mHeadsUpManager.hasHeadsUpNotifications()) {
4818                         // Only pulse the stack scroller if there's actually something to show.
4819                         // Otherwise just show the always-on screen.
4820                         setPulsing(true);
4821                     }
4822                 }
4823 
4824                 @Override
4825                 public void onPulseFinished() {
4826                     callback.onPulseFinished();
4827                     setPulsing(false);
4828                 }
4829 
4830                 private void setPulsing(boolean pulsing) {
4831                     mNotificationPanel.setPulsing(pulsing);
4832                     mVisualStabilityManager.setPulsing(pulsing);
4833                     mIgnoreTouchWhilePulsing = false;
4834                 }
4835             }, reason);
4836         }
4837 
4838         @Override
stopDozing()4839         public void stopDozing() {
4840             if (mDozingRequested) {
4841                 mDozingRequested = false;
4842                 DozeLog.traceDozing(mContext, mDozing);
4843                 mWakefulnessLifecycle.dispatchStartedWakingUp();
4844                 updateDozing();
4845             }
4846         }
4847 
4848         @Override
onIgnoreTouchWhilePulsing(boolean ignore)4849         public void onIgnoreTouchWhilePulsing(boolean ignore) {
4850             if (ignore != mIgnoreTouchWhilePulsing) {
4851                 DozeLog.tracePulseTouchDisabledByProx(mContext, ignore);
4852             }
4853             mIgnoreTouchWhilePulsing = ignore;
4854             if (isDozing() && ignore) {
4855                 mStatusBarWindow.cancelCurrentTouch();
4856             }
4857         }
4858 
4859         @Override
dozeTimeTick()4860         public void dozeTimeTick() {
4861             mNotificationPanel.dozeTimeTick();
4862         }
4863 
4864         @Override
isPowerSaveActive()4865         public boolean isPowerSaveActive() {
4866             return mBatteryController.isAodPowerSave();
4867         }
4868 
4869         @Override
isPulsingBlocked()4870         public boolean isPulsingBlocked() {
4871             return mFingerprintUnlockController.getMode()
4872                     == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK;
4873         }
4874 
4875         @Override
isProvisioned()4876         public boolean isProvisioned() {
4877             return mDeviceProvisionedController.isDeviceProvisioned()
4878                     && mDeviceProvisionedController.isCurrentUserSetup();
4879         }
4880 
4881         @Override
isBlockingDoze()4882         public boolean isBlockingDoze() {
4883             if (mFingerprintUnlockController.hasPendingAuthentication()) {
4884                 Log.i(TAG, "Blocking AOD because fingerprint has authenticated");
4885                 return true;
4886             }
4887             return false;
4888         }
4889 
4890         @Override
startPendingIntentDismissingKeyguard(PendingIntent intent)4891         public void startPendingIntentDismissingKeyguard(PendingIntent intent) {
4892             StatusBar.this.startPendingIntentDismissingKeyguard(intent);
4893         }
4894 
4895         @Override
extendPulse()4896         public void extendPulse() {
4897             mDozeScrimController.extendPulse();
4898         }
4899 
4900         @Override
setAnimateWakeup(boolean animateWakeup)4901         public void setAnimateWakeup(boolean animateWakeup) {
4902             if (mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_AWAKE
4903                     || mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_WAKING) {
4904                 // Too late to change the wakeup animation.
4905                 return;
4906             }
4907             mAnimateWakeup = animateWakeup;
4908         }
4909 
4910         @Override
setAnimateScreenOff(boolean animateScreenOff)4911         public void setAnimateScreenOff(boolean animateScreenOff) {
4912             mAnimateScreenOff = animateScreenOff;
4913         }
4914 
4915         @Override
onDoubleTap(float screenX, float screenY)4916         public void onDoubleTap(float screenX, float screenY) {
4917             if (screenX > 0 && screenY > 0 && mAmbientIndicationContainer != null
4918                 && mAmbientIndicationContainer.getVisibility() == View.VISIBLE) {
4919                 mAmbientIndicationContainer.getLocationOnScreen(mTmpInt2);
4920                 float viewX = screenX - mTmpInt2[0];
4921                 float viewY = screenY - mTmpInt2[1];
4922                 if (0 <= viewX && viewX <= mAmbientIndicationContainer.getWidth()
4923                         && 0 <= viewY && viewY <= mAmbientIndicationContainer.getHeight()) {
4924                     dispatchDoubleTap(viewX, viewY);
4925                 }
4926             }
4927         }
4928 
4929         @Override
setDozeScreenBrightness(int value)4930         public void setDozeScreenBrightness(int value) {
4931             mStatusBarWindowManager.setDozeScreenBrightness(value);
4932         }
4933 
4934         @Override
setAodDimmingScrim(float scrimOpacity)4935         public void setAodDimmingScrim(float scrimOpacity) {
4936             mScrimController.setAodFrontScrimAlpha(scrimOpacity);
4937         }
4938 
dispatchDoubleTap(float viewX, float viewY)4939         public void dispatchDoubleTap(float viewX, float viewY) {
4940             dispatchTap(mAmbientIndicationContainer, viewX, viewY);
4941             dispatchTap(mAmbientIndicationContainer, viewX, viewY);
4942         }
4943 
dispatchTap(View view, float x, float y)4944         private void dispatchTap(View view, float x, float y) {
4945             long now = SystemClock.elapsedRealtime();
4946             dispatchTouchEvent(view, x, y, now, MotionEvent.ACTION_DOWN);
4947             dispatchTouchEvent(view, x, y, now, MotionEvent.ACTION_UP);
4948         }
4949 
dispatchTouchEvent(View view, float x, float y, long now, int action)4950         private void dispatchTouchEvent(View view, float x, float y, long now, int action) {
4951             MotionEvent ev = MotionEvent.obtain(now, now, action, x, y, 0 /* meta */);
4952             view.dispatchTouchEvent(ev);
4953             ev.recycle();
4954         }
4955 
shouldAnimateWakeup()4956         private boolean shouldAnimateWakeup() {
4957             return mAnimateWakeup;
4958         }
4959 
shouldAnimateScreenOff()4960         public boolean shouldAnimateScreenOff() {
4961             return mAnimateScreenOff;
4962         }
4963     }
4964 
shouldIgnoreTouch()4965     public boolean shouldIgnoreTouch() {
4966         return isDozing() && mDozeServiceHost.mIgnoreTouchWhilePulsing;
4967     }
4968 
4969     // Begin Extra BaseStatusBar methods.
4970 
4971     protected CommandQueue mCommandQueue;
4972     protected IStatusBarService mBarService;
4973 
4974     // all notifications
4975     protected NotificationStackScrollLayout mStackScroller;
4976 
4977     protected NotificationGroupManager mGroupManager;
4978 
4979 
4980     // for heads up notifications
4981     protected HeadsUpManagerPhone mHeadsUpManager;
4982 
4983     private AboveShelfObserver mAboveShelfObserver;
4984 
4985     // handling reordering
4986     protected VisualStabilityManager mVisualStabilityManager;
4987 
4988     protected AccessibilityManager mAccessibilityManager;
4989 
4990     protected boolean mDeviceInteractive;
4991 
4992     protected boolean mVisible;
4993 
4994     // mScreenOnFromKeyguard && mVisible.
4995     private boolean mVisibleToUser;
4996 
4997     protected DevicePolicyManager mDevicePolicyManager;
4998     protected PowerManager mPowerManager;
4999     protected StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
5000 
5001     protected KeyguardManager mKeyguardManager;
5002     private LockPatternUtils mLockPatternUtils;
5003     private DeviceProvisionedController mDeviceProvisionedController
5004             = Dependency.get(DeviceProvisionedController.class);
5005 
5006     // UI-specific methods
5007 
5008     protected WindowManager mWindowManager;
5009     protected IWindowManager mWindowManagerService;
5010 
5011     protected Display mDisplay;
5012 
5013     protected RecentsComponent mRecents;
5014 
5015     protected NotificationShelf mNotificationShelf;
5016     protected FooterView mFooterView;
5017     protected EmptyShadeView mEmptyShadeView;
5018 
5019     protected AssistManager mAssistManager;
5020 
5021     protected boolean mVrMode;
5022 
isDeviceInteractive()5023     public boolean isDeviceInteractive() {
5024         return mDeviceInteractive;
5025     }
5026 
5027     @Override  // NotificationData.Environment
isDeviceProvisioned()5028     public boolean isDeviceProvisioned() {
5029         return mDeviceProvisionedController.isDeviceProvisioned();
5030     }
5031 
5032     private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
5033         @Override
5034         public void onVrStateChanged(boolean enabled) {
5035             mVrMode = enabled;
5036         }
5037     };
5038 
isDeviceInVrMode()5039     public boolean isDeviceInVrMode() {
5040         return mVrMode;
5041     }
5042 
5043     private final BroadcastReceiver mBannerActionBroadcastReceiver = new BroadcastReceiver() {
5044         @Override
5045         public void onReceive(Context context, Intent intent) {
5046             String action = intent.getAction();
5047             if (BANNER_ACTION_CANCEL.equals(action) || BANNER_ACTION_SETUP.equals(action)) {
5048                 NotificationManager noMan = (NotificationManager)
5049                         mContext.getSystemService(Context.NOTIFICATION_SERVICE);
5050                 noMan.cancel(com.android.internal.messages.nano.SystemMessageProto.SystemMessage.
5051                         NOTE_HIDDEN_NOTIFICATIONS);
5052 
5053                 Settings.Secure.putInt(mContext.getContentResolver(),
5054                         Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0);
5055                 if (BANNER_ACTION_SETUP.equals(action)) {
5056                     animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
5057                             true /* force */);
5058                     mContext.startActivity(new Intent(Settings.ACTION_APP_NOTIFICATION_REDACTION)
5059                             .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
5060 
5061                     );
5062                 }
5063             }
5064         }
5065     };
5066 
5067     @Override
onNotificationClicked(StatusBarNotification sbn, ExpandableNotificationRow row)5068     public void onNotificationClicked(StatusBarNotification sbn, ExpandableNotificationRow row) {
5069         RemoteInputController controller = mRemoteInputManager.getController();
5070         if (controller.isRemoteInputActive(row.getEntry())
5071                 && !TextUtils.isEmpty(row.getActiveRemoteInputText())) {
5072             // We have an active remote input typed and the user clicked on the notification.
5073             // this was probably unintentional, so we're closing the edit text instead.
5074             controller.closeRemoteInputs();
5075             return;
5076         }
5077         Notification notification = sbn.getNotification();
5078         final PendingIntent intent = notification.contentIntent != null
5079                 ? notification.contentIntent
5080                 : notification.fullScreenIntent;
5081         final String notificationKey = sbn.getKey();
5082 
5083         final boolean afterKeyguardGone = intent.isActivity()
5084                 && PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
5085                 mLockscreenUserManager.getCurrentUserId());
5086         final boolean wasOccluded = mIsOccluded;
5087         dismissKeyguardThenExecute(() -> {
5088             // TODO: Some of this code may be able to move to NotificationEntryManager.
5089             if (mHeadsUpManager != null && mHeadsUpManager.isHeadsUp(notificationKey)) {
5090                 // Release the HUN notification to the shade.
5091 
5092                 if (isPresenterFullyCollapsed()) {
5093                     HeadsUpUtil.setIsClickedHeadsUpNotification(row, true);
5094                 }
5095                 //
5096                 // In most cases, when FLAG_AUTO_CANCEL is set, the notification will
5097                 // become canceled shortly by NoMan, but we can't assume that.
5098                 mHeadsUpManager.releaseImmediately(notificationKey);
5099             }
5100             StatusBarNotification parentToCancel = null;
5101             if (shouldAutoCancel(sbn) && mGroupManager.isOnlyChildInGroup(sbn)) {
5102                 StatusBarNotification summarySbn =
5103                         mGroupManager.getLogicalGroupSummary(sbn).getStatusBarNotification();
5104                 if (shouldAutoCancel(summarySbn)) {
5105                     parentToCancel = summarySbn;
5106                 }
5107             }
5108             final StatusBarNotification parentToCancelFinal = parentToCancel;
5109             final Runnable runnable = () -> {
5110                 try {
5111                     // The intent we are sending is for the application, which
5112                     // won't have permission to immediately start an activity after
5113                     // the user switches to home.  We know it is safe to do at this
5114                     // point, so make sure new activity switches are now allowed.
5115                     ActivityManager.getService().resumeAppSwitches();
5116                 } catch (RemoteException e) {
5117                 }
5118                 int launchResult = ActivityManager.START_CANCELED;
5119                 if (intent != null) {
5120                     // If we are launching a work activity and require to launch
5121                     // separate work challenge, we defer the activity action and cancel
5122                     // notification until work challenge is unlocked.
5123                     if (intent.isActivity()) {
5124                         final int userId = intent.getCreatorUserHandle().getIdentifier();
5125                         if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)
5126                                 && mKeyguardManager.isDeviceLocked(userId)) {
5127                             // TODO(b/28935539): should allow certain activities to
5128                             // bypass work challenge
5129                             if (startWorkChallengeIfNecessary(userId, intent.getIntentSender(),
5130                                     notificationKey)) {
5131                                 // Show work challenge, do not run PendingIntent and
5132                                 // remove notification
5133                                 collapseOnMainThread();
5134                                 return;
5135                             }
5136                         }
5137                     }
5138                     Intent fillInIntent = null;
5139                     Entry entry = row.getEntry();
5140                     CharSequence remoteInputText = null;
5141                     if (!TextUtils.isEmpty(entry.remoteInputText)) {
5142                         remoteInputText = entry.remoteInputText;
5143                     }
5144                     if (!TextUtils.isEmpty(remoteInputText)
5145                             && !controller.isSpinning(entry.key)) {
5146                         fillInIntent = new Intent().putExtra(Notification.EXTRA_REMOTE_INPUT_DRAFT,
5147                                 remoteInputText.toString());
5148                     }
5149                     RemoteAnimationAdapter adapter = mActivityLaunchAnimator.getLaunchAnimation(
5150                             row, wasOccluded);
5151                     try {
5152                         if (adapter != null) {
5153                             ActivityManager.getService()
5154                                     .registerRemoteAnimationForNextActivityStart(
5155                                             intent.getCreatorPackage(), adapter);
5156                         }
5157                         launchResult = intent.sendAndReturnResult(mContext, 0, fillInIntent, null,
5158                                 null, null, getActivityOptions(adapter));
5159                         mActivityLaunchAnimator.setLaunchResult(launchResult);
5160                     } catch (RemoteException | PendingIntent.CanceledException e) {
5161                         // the stack trace isn't very helpful here.
5162                         // Just log the exception message.
5163                         Log.w(TAG, "Sending contentIntent failed: " + e);
5164 
5165                         // TODO: Dismiss Keyguard.
5166                     }
5167                     if (intent.isActivity()) {
5168                         mAssistManager.hideAssist();
5169                     }
5170                 }
5171                 if (shouldCollapse()) {
5172                     collapseOnMainThread();
5173                 }
5174 
5175                 final int count =
5176                         mEntryManager.getNotificationData().getActiveNotifications().size();
5177                 final int rank = mEntryManager.getNotificationData().getRank(notificationKey);
5178                 final NotificationVisibility nv = NotificationVisibility.obtain(notificationKey,
5179                         rank, count, true);
5180                 try {
5181                     mBarService.onNotificationClick(notificationKey, nv);
5182                 } catch (RemoteException ex) {
5183                     // system process is dead if we're here.
5184                 }
5185                 if (parentToCancelFinal != null) {
5186                     removeNotification(parentToCancelFinal);
5187                 }
5188                 if (shouldAutoCancel(sbn)
5189                         || mEntryManager.isNotificationKeptForRemoteInput(notificationKey)) {
5190                     // Automatically remove all notifications that we may have kept around longer
5191                     removeNotification(sbn);
5192                 }
5193             };
5194 
5195             if (mStatusBarKeyguardViewManager.isShowing()
5196                     && mStatusBarKeyguardViewManager.isOccluded()) {
5197                 mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(runnable);
5198                 collapsePanel(true /* animate */);
5199             } else {
5200                 new Thread(runnable).start();
5201             }
5202 
5203             return !mNotificationPanel.isFullyCollapsed();
5204         }, afterKeyguardGone);
5205     }
5206 
collapseOnMainThread()5207     private void collapseOnMainThread() {
5208         if (Looper.getMainLooper().isCurrentThread()) {
5209             collapsePanel();
5210         } else {
5211             mStackScroller.post(this::collapsePanel);
5212         }
5213     }
5214 
shouldCollapse()5215     private boolean shouldCollapse() {
5216         return mState != StatusBarState.SHADE || !mActivityLaunchAnimator.isAnimationPending();
5217     }
5218 
collapsePanel(boolean animate)5219     public void collapsePanel(boolean animate) {
5220         if (animate) {
5221             collapsePanel();
5222         } else if (!isPresenterFullyCollapsed()) {
5223             instantCollapseNotificationPanel();
5224             visibilityChanged(false);
5225         } else {
5226             runPostCollapseRunnables();
5227         }
5228     }
5229 
collapsePanel()5230     private boolean collapsePanel() {
5231         if (!mNotificationPanel.isFullyCollapsed()) {
5232             // close the shade if it was open
5233             animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */,
5234                     true /* delayed */);
5235             visibilityChanged(false);
5236 
5237             return true;
5238         } else {
5239             return false;
5240         }
5241     }
5242 
removeNotification(StatusBarNotification notification)5243     private void removeNotification(StatusBarNotification notification) {
5244         // We have to post it to the UI thread for synchronization
5245         mHandler.post(() -> {
5246             Runnable removeRunnable =
5247                     () -> mEntryManager.performRemoveNotification(notification);
5248             if (isCollapsing()) {
5249                 // To avoid lags we're only performing the remove
5250                 // after the shade was collapsed
5251                 addPostCollapseAction(removeRunnable);
5252             } else {
5253                 removeRunnable.run();
5254             }
5255         });
5256     }
5257 
5258     protected NotificationListener mNotificationListener;
5259 
5260     @Override  // NotificationData.Environment
isNotificationForCurrentProfiles(StatusBarNotification n)5261     public boolean isNotificationForCurrentProfiles(StatusBarNotification n) {
5262         final int notificationUserId = n.getUserId();
5263         if (DEBUG && MULTIUSER_DEBUG) {
5264             Log.v(TAG, String.format("%s: current userid: %d, notification userid: %d", n,
5265                     mLockscreenUserManager.getCurrentUserId(), notificationUserId));
5266         }
5267         return mLockscreenUserManager.isCurrentProfile(notificationUserId);
5268     }
5269 
5270     @Override
getGroupManager()5271     public NotificationGroupManager getGroupManager() {
5272         return mGroupManager;
5273     }
5274 
5275     @Override
startNotificationGutsIntent(final Intent intent, final int appUid, ExpandableNotificationRow row)5276     public void startNotificationGutsIntent(final Intent intent, final int appUid,
5277             ExpandableNotificationRow row) {
5278         dismissKeyguardThenExecute(() -> {
5279             AsyncTask.execute(() -> {
5280                 int launchResult = TaskStackBuilder.create(mContext)
5281                         .addNextIntentWithParentStack(intent)
5282                         .startActivities(getActivityOptions(
5283                                 mActivityLaunchAnimator.getLaunchAnimation(row, mIsOccluded)),
5284                                 new UserHandle(UserHandle.getUserId(appUid)));
5285                 mActivityLaunchAnimator.setLaunchResult(launchResult);
5286                 if (shouldCollapse()) {
5287                     // Putting it back on the main thread, since we're touching views
5288                     mStatusBarWindow.post(() -> animateCollapsePanels(
5289                             CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */));
5290                 }
5291             });
5292             return true;
5293         }, false /* afterKeyguardGone */);
5294     }
5295 
setNotificationSnoozed(StatusBarNotification sbn, SnoozeOption snoozeOption)5296     public void setNotificationSnoozed(StatusBarNotification sbn, SnoozeOption snoozeOption) {
5297         if (snoozeOption.getSnoozeCriterion() != null) {
5298             mNotificationListener.snoozeNotification(sbn.getKey(),
5299                     snoozeOption.getSnoozeCriterion().getId());
5300         } else {
5301             mNotificationListener.snoozeNotification(sbn.getKey(),
5302                     snoozeOption.getMinutesToSnoozeFor() * 60 * 1000);
5303         }
5304     }
5305 
5306     @Override
toggleSplitScreen()5307     public void toggleSplitScreen() {
5308         toggleSplitScreenMode(-1 /* metricsDockAction */, -1 /* metricsUndockAction */);
5309     }
5310 
awakenDreams()5311     void awakenDreams() {
5312         SystemServicesProxy.getInstance(mContext).awakenDreamsAsync();
5313     }
5314 
5315     @Override
preloadRecentApps()5316     public void preloadRecentApps() {
5317         int msg = MSG_PRELOAD_RECENT_APPS;
5318         mHandler.removeMessages(msg);
5319         mHandler.sendEmptyMessage(msg);
5320     }
5321 
5322     @Override
cancelPreloadRecentApps()5323     public void cancelPreloadRecentApps() {
5324         int msg = MSG_CANCEL_PRELOAD_RECENT_APPS;
5325         mHandler.removeMessages(msg);
5326         mHandler.sendEmptyMessage(msg);
5327     }
5328 
5329     @Override
dismissKeyboardShortcutsMenu()5330     public void dismissKeyboardShortcutsMenu() {
5331         int msg = MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU;
5332         mHandler.removeMessages(msg);
5333         mHandler.sendEmptyMessage(msg);
5334     }
5335 
5336     @Override
toggleKeyboardShortcutsMenu(int deviceId)5337     public void toggleKeyboardShortcutsMenu(int deviceId) {
5338         int msg = MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU;
5339         mHandler.removeMessages(msg);
5340         mHandler.obtainMessage(msg, deviceId, 0).sendToTarget();
5341     }
5342 
5343     @Override
setTopAppHidesStatusBar(boolean topAppHidesStatusBar)5344     public void setTopAppHidesStatusBar(boolean topAppHidesStatusBar) {
5345         mTopHidesStatusBar = topAppHidesStatusBar;
5346         if (!topAppHidesStatusBar && mWereIconsJustHidden) {
5347             // Immediately update the icon hidden state, since that should only apply if we're
5348             // staying fullscreen.
5349             mWereIconsJustHidden = false;
5350             recomputeDisableFlags(true);
5351         }
5352         updateHideIconsForBouncer(true /* animate */);
5353     }
5354 
toggleKeyboardShortcuts(int deviceId)5355     protected void toggleKeyboardShortcuts(int deviceId) {
5356         KeyboardShortcuts.toggle(mContext, deviceId);
5357     }
5358 
dismissKeyboardShortcuts()5359     protected void dismissKeyboardShortcuts() {
5360         KeyboardShortcuts.dismiss();
5361     }
5362 
5363     @Override  // NotificationData.Environment
shouldHideNotifications(int userId)5364     public boolean shouldHideNotifications(int userId) {
5365         return mLockscreenUserManager.shouldHideNotifications(userId);
5366     }
5367 
5368     @Override // NotificationDate.Environment
shouldHideNotifications(String key)5369     public boolean shouldHideNotifications(String key) {
5370         return mLockscreenUserManager.shouldHideNotifications(key);
5371     }
5372 
5373     /**
5374      * Returns true if we're on a secure lockscreen.
5375      */
5376     @Override  // NotificationData.Environment
isSecurelyLocked(int userId)5377     public boolean isSecurelyLocked(int userId) {
5378         return mLockscreenUserManager.isLockscreenPublicMode(userId);
5379     }
5380 
5381     /**
5382      * Called when the notification panel layouts
5383      */
onPanelLaidOut()5384     public void onPanelLaidOut() {
5385         updateKeyguardMaxNotifications();
5386     }
5387 
updateKeyguardMaxNotifications()5388     public void updateKeyguardMaxNotifications() {
5389         if (mState == StatusBarState.KEYGUARD) {
5390             // Since the number of notifications is determined based on the height of the view, we
5391             // need to update them.
5392             int maxBefore = getMaxNotificationsWhileLocked(false /* recompute */);
5393             int maxNotifications = getMaxNotificationsWhileLocked(true /* recompute */);
5394             if (maxBefore != maxNotifications) {
5395                 mViewHierarchyManager.updateRowStates();
5396             }
5397         }
5398     }
5399 
startPendingIntentDismissingKeyguard(final PendingIntent intent)5400     public void startPendingIntentDismissingKeyguard(final PendingIntent intent) {
5401         if (!isDeviceProvisioned()) return;
5402 
5403         final boolean afterKeyguardGone = intent.isActivity()
5404                 && PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
5405                 mLockscreenUserManager.getCurrentUserId());
5406         dismissKeyguardThenExecute(() -> {
5407             new Thread(() -> {
5408                 try {
5409                     // The intent we are sending is for the application, which
5410                     // won't have permission to immediately start an activity after
5411                     // the user switches to home.  We know it is safe to do at this
5412                     // point, so make sure new activity switches are now allowed.
5413                     ActivityManager.getService().resumeAppSwitches();
5414                 } catch (RemoteException e) {
5415                 }
5416                 try {
5417                     intent.send(null, 0, null, null, null, null, getActivityOptions(
5418                             null /* animationAdapter */));
5419                 } catch (PendingIntent.CanceledException e) {
5420                     // the stack trace isn't very helpful here.
5421                     // Just log the exception message.
5422                     Log.w(TAG, "Sending intent failed: " + e);
5423 
5424                     // TODO: Dismiss Keyguard.
5425                 }
5426                 if (intent.isActivity()) {
5427                     mAssistManager.hideAssist();
5428                 }
5429             }).start();
5430 
5431             return collapsePanel();
5432         }, afterKeyguardGone);
5433     }
5434 
shouldAutoCancel(StatusBarNotification sbn)5435     private boolean shouldAutoCancel(StatusBarNotification sbn) {
5436         int flags = sbn.getNotification().flags;
5437         if ((flags & Notification.FLAG_AUTO_CANCEL) != Notification.FLAG_AUTO_CANCEL) {
5438             return false;
5439         }
5440         if ((flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
5441             return false;
5442         }
5443         return true;
5444     }
5445 
getActivityOptions(@ullable RemoteAnimationAdapter animationAdapter)5446     protected Bundle getActivityOptions(@Nullable RemoteAnimationAdapter animationAdapter) {
5447         ActivityOptions options;
5448         if (animationAdapter != null) {
5449             options = ActivityOptions.makeRemoteAnimation(animationAdapter);
5450         } else {
5451             options = ActivityOptions.makeBasic();
5452         }
5453         // Anything launched from the notification shade should always go into the secondary
5454         // split-screen windowing mode.
5455         options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY);
5456         return options.toBundle();
5457     }
5458 
visibilityChanged(boolean visible)5459     protected void visibilityChanged(boolean visible) {
5460         if (mVisible != visible) {
5461             mVisible = visible;
5462             if (!visible) {
5463                 mGutsManager.closeAndSaveGuts(true /* removeLeavebehind */, true /* force */,
5464                         true /* removeControls */, -1 /* x */, -1 /* y */, true /* resetMenu */);
5465             }
5466         }
5467         updateVisibleToUser();
5468     }
5469 
updateVisibleToUser()5470     protected void updateVisibleToUser() {
5471         boolean oldVisibleToUser = mVisibleToUser;
5472         mVisibleToUser = mVisible && mDeviceInteractive;
5473 
5474         if (oldVisibleToUser != mVisibleToUser) {
5475             handleVisibleToUserChanged(mVisibleToUser);
5476         }
5477     }
5478 
5479     /**
5480      * Clear Buzz/Beep/Blink.
5481      */
clearNotificationEffects()5482     public void clearNotificationEffects() {
5483         try {
5484             mBarService.clearNotificationEffects();
5485         } catch (RemoteException e) {
5486             // Won't fail unless the world has ended.
5487         }
5488     }
5489 
5490     /**
5491      * Updates expanded, dimmed and locked states of notification rows.
5492      */
5493     @Override
onUpdateRowStates()5494     public void onUpdateRowStates() {
5495         // The following views will be moved to the end of mStackScroller. This counter represents
5496         // the offset from the last child. Initialized to 1 for the very last position. It is post-
5497         // incremented in the following "changeViewPosition" calls so that its value is correct for
5498         // subsequent calls.
5499         int offsetFromEnd = 1;
5500         if (mFooterView != null) {
5501             mStackScroller.changeViewPosition(mFooterView,
5502                     mStackScroller.getChildCount() - offsetFromEnd++);
5503         }
5504 
5505         mStackScroller.changeViewPosition(mEmptyShadeView,
5506                 mStackScroller.getChildCount() - offsetFromEnd++);
5507 
5508         // No post-increment for this call because it is the last one. Make sure to add one if
5509         // another "changeViewPosition" call is ever added.
5510         mStackScroller.changeViewPosition(mNotificationShelf,
5511                 mStackScroller.getChildCount() - offsetFromEnd);
5512 
5513         // Scrim opacity varies based on notification count
5514         mScrimController.setNotificationCount(mStackScroller.getNotGoneChildCount());
5515     }
5516 
notifyHeadsUpGoingToSleep()5517     protected void notifyHeadsUpGoingToSleep() {
5518         maybeEscalateHeadsUp();
5519     }
5520 
5521     /**
5522      * @return Whether the security bouncer from Keyguard is showing.
5523      */
isBouncerShowing()5524     public boolean isBouncerShowing() {
5525         return mBouncerShowing;
5526     }
5527 
5528     /**
5529      * @return a PackageManger for userId or if userId is < 0 (USER_ALL etc) then
5530      *         return PackageManager for mContext
5531      */
getPackageManagerForUser(Context context, int userId)5532     public static PackageManager getPackageManagerForUser(Context context, int userId) {
5533         Context contextForUser = context;
5534         // UserHandle defines special userId as negative values, e.g. USER_ALL
5535         if (userId >= 0) {
5536             try {
5537                 // Create a context for the correct user so if a package isn't installed
5538                 // for user 0 we can still load information about the package.
5539                 contextForUser =
5540                         context.createPackageContextAsUser(context.getPackageName(),
5541                         Context.CONTEXT_RESTRICTED,
5542                         new UserHandle(userId));
5543             } catch (NameNotFoundException e) {
5544                 // Shouldn't fail to find the package name for system ui.
5545             }
5546         }
5547         return contextForUser.getPackageManager();
5548     }
5549 
isKeyguardSecure()5550     public boolean isKeyguardSecure() {
5551         if (mStatusBarKeyguardViewManager == null) {
5552             // startKeyguard() hasn't been called yet, so we don't know.
5553             // Make sure anything that needs to know isKeyguardSecure() checks and re-checks this
5554             // value onVisibilityChanged().
5555             Slog.w(TAG, "isKeyguardSecure() called before startKeyguard(), returning false",
5556                     new Throwable());
5557             return false;
5558         }
5559         return mStatusBarKeyguardViewManager.isSecure();
5560     }
5561 
5562     @Override
onZenChanged(int zen)5563     public void onZenChanged(int zen) {
5564         updateEmptyShadeView();
5565     }
5566 
5567     @Override
showAssistDisclosure()5568     public void showAssistDisclosure() {
5569         if (mAssistManager != null) {
5570             mAssistManager.showDisclosure();
5571         }
5572     }
5573 
getPanel()5574     public NotificationPanelView getPanel() {
5575         return mNotificationPanel;
5576     }
5577 
5578     @Override
startAssist(Bundle args)5579     public void startAssist(Bundle args) {
5580         if (mAssistManager != null) {
5581             mAssistManager.startAssist(args);
5582         }
5583     }
5584     // End Extra BaseStatusBarMethods.
5585 
5586     private final Runnable mAutoDim = () -> {
5587         if (mNavigationBar != null) {
5588             mNavigationBar.getBarTransitions().setAutoDim(true);
5589         }
5590     };
5591 
getGutsManager()5592     public NotificationGutsManager getGutsManager() {
5593         return mGutsManager;
5594     }
5595 
5596     @Override
isPresenterLocked()5597     public boolean isPresenterLocked() {
5598         return mState == StatusBarState.KEYGUARD;
5599     }
5600 
5601     @Override
getHandler()5602     public Handler getHandler() {
5603         return mHandler;
5604     }
5605 
5606     private final NotificationInfo.CheckSaveListener mCheckSaveListener =
5607             (Runnable saveImportance, StatusBarNotification sbn) -> {
5608                 // If the user has security enabled, show challenge if the setting is changed.
5609                 if (mLockscreenUserManager.isLockscreenPublicMode(sbn.getUser().getIdentifier())
5610                         && (mState == StatusBarState.KEYGUARD ||
5611                                 mState == StatusBarState.SHADE_LOCKED)) {
5612                     onLockedNotificationImportanceChange(() -> {
5613                         saveImportance.run();
5614                         return true;
5615                     });
5616                 } else {
5617                     saveImportance.run();
5618                 }
5619             };
5620 }
5621