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