OSDN Git Service

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