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 
     23 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP;
     24 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
     25 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_WAKING;
     26 import static com.android.systemui.statusbar.notification.NotificationInflater.InflationCallback;
     27 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
     28 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
     29 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
     30 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
     31 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSLUCENT;
     32 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
     33 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_WARNING;
     34 
     35 import android.animation.Animator;
     36 import android.animation.AnimatorListenerAdapter;
     37 import android.annotation.NonNull;
     38 import android.annotation.Nullable;
     39 import android.app.ActivityManager;
     40 import android.app.ActivityManager.StackId;
     41 import android.app.ActivityOptions;
     42 import android.app.INotificationManager;
     43 import android.app.KeyguardManager;
     44 import android.app.Notification;
     45 import android.app.NotificationChannel;
     46 import android.app.NotificationManager;
     47 import android.app.PendingIntent;
     48 import android.app.RemoteInput;
     49 import android.app.StatusBarManager;
     50 import android.app.TaskStackBuilder;
     51 import android.app.WallpaperColors;
     52 import android.app.WallpaperManager;
     53 import android.app.admin.DevicePolicyManager;
     54 import android.content.BroadcastReceiver;
     55 import android.content.ComponentCallbacks2;
     56 import android.content.ComponentName;
     57 import android.content.Context;
     58 import android.content.Intent;
     59 import android.content.IntentFilter;
     60 import android.content.IntentSender;
     61 import android.content.om.IOverlayManager;
     62 import android.content.om.OverlayInfo;
     63 import android.content.pm.ApplicationInfo;
     64 import android.content.pm.IPackageManager;
     65 import android.content.pm.PackageManager;
     66 import android.content.pm.PackageManager.NameNotFoundException;
     67 import android.content.pm.UserInfo;
     68 import android.content.res.Configuration;
     69 import android.content.res.Resources;
     70 import android.database.ContentObserver;
     71 import android.graphics.Bitmap;
     72 import android.graphics.Canvas;
     73 import android.graphics.ColorFilter;
     74 import android.graphics.PixelFormat;
     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.media.session.MediaController;
     86 import android.media.session.MediaSession;
     87 import android.media.session.MediaSessionManager;
     88 import android.media.session.PlaybackState;
     89 import android.metrics.LogMaker;
     90 import android.net.Uri;
     91 import android.os.AsyncTask;
     92 import android.os.Build;
     93 import android.os.Bundle;
     94 import android.os.Handler;
     95 import android.os.IBinder;
     96 import android.os.Message;
     97 import android.os.PowerManager;
     98 import android.os.RemoteException;
     99 import android.os.ServiceManager;
    100 import android.os.SystemClock;
    101 import android.os.SystemProperties;
    102 import android.os.Trace;
    103 import android.os.UserHandle;
    104 import android.os.UserManager;
    105 import android.os.Vibrator;
    106 import android.provider.Settings;
    107 import android.service.notification.NotificationListenerService.RankingMap;
    108 import android.service.notification.StatusBarNotification;
    109 import android.service.vr.IVrManager;
    110 import android.service.vr.IVrStateCallbacks;
    111 import android.text.TextUtils;
    112 import android.util.ArraySet;
    113 import android.util.DisplayMetrics;
    114 import android.util.EventLog;
    115 import android.util.Log;
    116 import android.util.Slog;
    117 import android.util.SparseArray;
    118 import android.util.SparseBooleanArray;
    119 import android.view.Display;
    120 import android.view.HapticFeedbackConstants;
    121 import android.view.IWindowManager;
    122 import android.view.KeyEvent;
    123 import android.view.LayoutInflater;
    124 import android.view.MotionEvent;
    125 import android.view.ThreadedRenderer;
    126 import android.view.View;
    127 import android.view.ViewAnimationUtils;
    128 import android.view.ViewGroup;
    129 import android.view.ViewParent;
    130 import android.view.ViewStub;
    131 import android.view.ViewTreeObserver;
    132 import android.view.WindowManager;
    133 import android.view.WindowManagerGlobal;
    134 import android.view.accessibility.AccessibilityManager;
    135 import android.view.animation.AccelerateInterpolator;
    136 import android.view.animation.Interpolator;
    137 import android.widget.DateTimeView;
    138 import android.widget.ImageView;
    139 import android.widget.RemoteViews;
    140 import android.widget.TextView;
    141 import android.widget.Toast;
    142 
    143 import com.android.internal.annotations.VisibleForTesting;
    144 import com.android.internal.colorextraction.ColorExtractor;
    145 import com.android.internal.logging.MetricsLogger;
    146 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
    147 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
    148 import com.android.internal.statusbar.IStatusBarService;
    149 import com.android.internal.statusbar.NotificationVisibility;
    150 import com.android.internal.statusbar.StatusBarIcon;
    151 import com.android.internal.util.NotificationMessagingUtil;
    152 import com.android.internal.widget.LockPatternUtils;
    153 import com.android.keyguard.KeyguardHostView.OnDismissAction;
    154 import com.android.keyguard.KeyguardUpdateMonitor;
    155 import com.android.keyguard.KeyguardUpdateMonitorCallback;
    156 import com.android.keyguard.ViewMediatorCallback;
    157 import com.android.systemui.ActivityStarterDelegate;
    158 import com.android.systemui.AutoReinflateContainer;
    159 import com.android.systemui.DejankUtils;
    160 import com.android.systemui.DemoMode;
    161 import com.android.systemui.Dependency;
    162 import com.android.systemui.EventLogTags;
    163 import com.android.systemui.ForegroundServiceController;
    164 import com.android.systemui.Interpolators;
    165 import com.android.systemui.Prefs;
    166 import com.android.systemui.R;
    167 import com.android.systemui.RecentsComponent;
    168 import com.android.systemui.SwipeHelper;
    169 import com.android.systemui.SystemUI;
    170 import com.android.systemui.SystemUIFactory;
    171 import com.android.systemui.UiOffloadThread;
    172 import com.android.systemui.assist.AssistManager;
    173 import com.android.systemui.classifier.FalsingLog;
    174 import com.android.systemui.classifier.FalsingManager;
    175 import com.android.systemui.colorextraction.SysuiColorExtractor;
    176 import com.android.systemui.doze.DozeHost;
    177 import com.android.systemui.doze.DozeLog;
    178 import com.android.systemui.doze.DozeReceiver;
    179 import com.android.systemui.fragments.ExtensionFragmentListener;
    180 import com.android.systemui.fragments.FragmentHostManager;
    181 import com.android.systemui.keyguard.KeyguardViewMediator;
    182 import com.android.systemui.keyguard.ScreenLifecycle;
    183 import com.android.systemui.keyguard.WakefulnessLifecycle;
    184 import com.android.systemui.plugins.ActivityStarter;
    185 import com.android.systemui.plugins.qs.QS;
    186 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
    187 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption;
    188 import com.android.systemui.qs.QSFragment;
    189 import com.android.systemui.qs.QSPanel;
    190 import com.android.systemui.qs.QSTileHost;
    191 import com.android.systemui.qs.car.CarQSFragment;
    192 import com.android.systemui.recents.Recents;
    193 import com.android.systemui.recents.ScreenPinningRequest;
    194 import com.android.systemui.recents.events.EventBus;
    195 import com.android.systemui.recents.events.activity.AppTransitionFinishedEvent;
    196 import com.android.systemui.recents.events.activity.UndockingTaskEvent;
    197 import com.android.systemui.recents.misc.SystemServicesProxy;
    198 import com.android.systemui.stackdivider.Divider;
    199 import com.android.systemui.stackdivider.WindowManagerProxy;
    200 import com.android.systemui.statusbar.ActivatableNotificationView;
    201 import com.android.systemui.statusbar.BackDropView;
    202 import com.android.systemui.statusbar.CommandQueue;
    203 import com.android.systemui.statusbar.DismissView;
    204 import com.android.systemui.statusbar.DragDownHelper;
    205 import com.android.systemui.statusbar.EmptyShadeView;
    206 import com.android.systemui.statusbar.ExpandableNotificationRow;
    207 import com.android.systemui.statusbar.GestureRecorder;
    208 import com.android.systemui.statusbar.KeyboardShortcuts;
    209 import com.android.systemui.statusbar.KeyguardIndicationController;
    210 import com.android.systemui.statusbar.NotificationData;
    211 import com.android.systemui.statusbar.NotificationData.Entry;
    212 import com.android.systemui.statusbar.NotificationGuts;
    213 import com.android.systemui.statusbar.NotificationInfo;
    214 import com.android.systemui.statusbar.NotificationShelf;
    215 import com.android.systemui.statusbar.NotificationSnooze;
    216 import com.android.systemui.statusbar.RemoteInputController;
    217 import com.android.systemui.statusbar.ScrimView;
    218 import com.android.systemui.statusbar.SignalClusterView;
    219 import com.android.systemui.statusbar.StatusBarState;
    220 import com.android.systemui.statusbar.notification.AboveShelfObserver;
    221 import com.android.systemui.statusbar.notification.InflationException;
    222 import com.android.systemui.statusbar.notification.RowInflaterTask;
    223 import com.android.systemui.statusbar.notification.VisualStabilityManager;
    224 import com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChangedListener;
    225 import com.android.systemui.statusbar.policy.BatteryController;
    226 import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
    227 import com.android.systemui.statusbar.policy.BrightnessMirrorController;
    228 import com.android.systemui.statusbar.policy.ConfigurationController;
    229 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
    230 import com.android.systemui.statusbar.policy.DarkIconDispatcher;
    231 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
    232 import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
    233 import com.android.systemui.statusbar.policy.ExtensionController;
    234 import com.android.systemui.statusbar.policy.HeadsUpManager;
    235 import com.android.systemui.statusbar.policy.KeyguardMonitor;
    236 import com.android.systemui.statusbar.policy.KeyguardMonitorImpl;
    237 import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
    238 import com.android.systemui.statusbar.policy.NetworkController;
    239 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
    240 import com.android.systemui.statusbar.policy.PreviewInflater;
    241 import com.android.systemui.statusbar.policy.RemoteInputView;
    242 import com.android.systemui.statusbar.policy.UserInfoController;
    243 import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
    244 import com.android.systemui.statusbar.policy.UserSwitcherController;
    245 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
    246 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout
    247         .OnChildLocationsChangedListener;
    248 import com.android.systemui.statusbar.stack.StackStateAnimator;
    249 import com.android.systemui.util.NotificationChannels;
    250 import com.android.systemui.util.leak.LeakDetector;
    251 import com.android.systemui.volume.VolumeComponent;
    252 
    253 import java.io.FileDescriptor;
    254 import java.io.PrintWriter;
    255 import java.io.StringWriter;
    256 import java.util.ArrayList;
    257 import java.util.Collection;
    258 import java.util.Collections;
    259 import java.util.HashMap;
    260 import java.util.HashSet;
    261 import java.util.List;
    262 import java.util.Locale;
    263 import java.util.Map;
    264 import java.util.Set;
    265 import java.util.Stack;
    266 
    267 public class StatusBar extends SystemUI implements DemoMode,
    268         DragDownHelper.DragDownCallback, ActivityStarter, OnUnlockMethodChangedListener,
    269         OnHeadsUpChangedListener, VisualStabilityManager.Callback, CommandQueue.Callbacks,
    270         ActivatableNotificationView.OnActivatedListener,
    271         ExpandableNotificationRow.ExpansionLogger, NotificationData.Environment,
    272         ExpandableNotificationRow.OnExpandClickListener, InflationCallback,
    273         ColorExtractor.OnColorsChangedListener, ConfigurationListener {
    274     public static final boolean MULTIUSER_DEBUG = false;
    275 
    276     public static final boolean ENABLE_REMOTE_INPUT =
    277             SystemProperties.getBoolean("debug.enable_remote_input", true);
    278     public static final boolean ENABLE_CHILD_NOTIFICATIONS
    279             = SystemProperties.getBoolean("debug.child_notifs", true);
    280     public static final boolean FORCE_REMOTE_INPUT_HISTORY =
    281             SystemProperties.getBoolean("debug.force_remoteinput_history", false);
    282     private static boolean ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT = false;
    283 
    284     protected static final int MSG_SHOW_RECENT_APPS = 1019;
    285     protected static final int MSG_HIDE_RECENT_APPS = 1020;
    286     protected static final int MSG_TOGGLE_RECENTS_APPS = 1021;
    287     protected static final int MSG_PRELOAD_RECENT_APPS = 1022;
    288     protected static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 1023;
    289     protected static final int MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU = 1026;
    290     protected static final int MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU = 1027;
    291 
    292     protected static final boolean ENABLE_HEADS_UP = true;
    293     protected static final String SETTING_HEADS_UP_TICKER = "ticker_gets_heads_up";
    294 
    295     // Must match constant in Settings. Used to highlight preferences when linking to Settings.
    296     private static final String EXTRA_FRAGMENT_ARG_KEY = ":settings:fragment_args_key";
    297 
    298     private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
    299 
    300     // Should match the values in PhoneWindowManager
    301     public static final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
    302     public static final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
    303     static public final String SYSTEM_DIALOG_REASON_SCREENSHOT = "screenshot";
    304 
    305     private static final String BANNER_ACTION_CANCEL =
    306             "com.android.systemui.statusbar.banner_action_cancel";
    307     private static final String BANNER_ACTION_SETUP =
    308             "com.android.systemui.statusbar.banner_action_setup";
    309     private static final String NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION
    310             = "com.android.systemui.statusbar.work_challenge_unlocked_notification_action";
    311     public static final String TAG = "StatusBar";
    312     public static final boolean DEBUG = false;
    313     public static final boolean SPEW = false;
    314     public static final boolean DUMPTRUCK = true; // extra dumpsys info
    315     public static final boolean DEBUG_GESTURES = false;
    316     public static final boolean DEBUG_MEDIA = false;
    317     public static final boolean DEBUG_MEDIA_FAKE_ARTWORK = false;
    318     public static final boolean DEBUG_CAMERA_LIFT = false;
    319 
    320     public static final boolean DEBUG_WINDOW_STATE = false;
    321 
    322     // additional instrumentation for testing purposes; intended to be left on during development
    323     public static final boolean CHATTY = DEBUG;
    324 
    325     public static final boolean SHOW_LOCKSCREEN_MEDIA_ARTWORK = true;
    326 
    327     public static final String ACTION_FAKE_ARTWORK = "fake_artwork";
    328 
    329     private static final int MSG_OPEN_NOTIFICATION_PANEL = 1000;
    330     private static final int MSG_CLOSE_PANELS = 1001;
    331     private static final int MSG_OPEN_SETTINGS_PANEL = 1002;
    332     private static final int MSG_LAUNCH_TRANSITION_TIMEOUT = 1003;
    333     // 1020-1040 reserved for BaseStatusBar
    334 
    335     // Time after we abort the launch transition.
    336     private static final long LAUNCH_TRANSITION_TIMEOUT_MS = 5000;
    337 
    338     private static final boolean CLOSE_PANEL_WHEN_EMPTIED = true;
    339 
    340     private static final int STATUS_OR_NAV_TRANSIENT =
    341             View.STATUS_BAR_TRANSIENT | View.NAVIGATION_BAR_TRANSIENT;
    342     private static final long AUTOHIDE_TIMEOUT_MS = 2250;
    343 
    344     /** The minimum delay in ms between reports of notification visibility. */
    345     private static final int VISIBILITY_REPORT_MIN_DELAY_MS = 500;
    346 
    347     /**
    348      * The delay to reset the hint text when the hint animation is finished running.
    349      */
    350     private static final int HINT_RESET_DELAY_MS = 1200;
    351 
    352     private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
    353             .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
    354             .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
    355             .build();
    356 
    357     public static final int FADE_KEYGUARD_START_DELAY = 100;
    358     public static final int FADE_KEYGUARD_DURATION = 300;
    359     public static final int FADE_KEYGUARD_DURATION_PULSING = 96;
    360 
    361     /** If true, the system is in the half-boot-to-decryption-screen state.
    362      * Prudently disable QS and notifications.  */
    363     private static final boolean ONLY_CORE_APPS;
    364 
    365     /** If true, the lockscreen will show a distinct wallpaper */
    366     private static final boolean ENABLE_LOCKSCREEN_WALLPAPER = true;
    367 
    368     /* If true, the device supports freeform window management.
    369      * This affects the status bar UI. */
    370     private static final boolean FREEFORM_WINDOW_MANAGEMENT;
    371 
    372     /**
    373      * How long to wait before auto-dismissing a notification that was kept for remote input, and
    374      * has now sent a remote input. We auto-dismiss, because the app may not see a reason to cancel
    375      * these given that they technically don't exist anymore. We wait a bit in case the app issues
    376      * an update.
    377      */
    378     private static final int REMOTE_INPUT_KEPT_ENTRY_AUTO_CANCEL_DELAY = 200;
    379 
    380     /**
    381      * Never let the alpha become zero for surfaces that draw with SRC - otherwise the RenderNode
    382      * won't draw anything and uninitialized memory will show through
    383      * if mScrimSrcModeEnabled. Note that 0.001 is rounded down to 0 in
    384      * libhwui.
    385      */
    386     private static final float SRC_MIN_ALPHA = 0.002f;
    387 
    388     static {
    389         boolean onlyCoreApps;
    390         boolean freeformWindowManagement;
    391         try {
    392             IPackageManager packageManager =
    393                     IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
    394             onlyCoreApps = packageManager.isOnlyCoreApps();
    395             freeformWindowManagement = packageManager.hasSystemFeature(
    396                     PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT, 0);
    397         } catch (RemoteException e) {
    398             onlyCoreApps = false;
    399             freeformWindowManagement = false;
    400         }
    401         ONLY_CORE_APPS = onlyCoreApps;
    402         FREEFORM_WINDOW_MANAGEMENT = freeformWindowManagement;
    403     }
    404 
    405     /**
    406      * The {@link StatusBarState} of the status bar.
    407      */
    408     protected int mState;
    409     protected boolean mBouncerShowing;
    410     protected boolean mShowLockscreenNotifications;
    411     protected boolean mAllowLockscreenRemoteInput;
    412 
    413     PhoneStatusBarPolicy mIconPolicy;
    414 
    415     VolumeComponent mVolumeComponent;
    416     BrightnessMirrorController mBrightnessMirrorController;
    417     protected FingerprintUnlockController mFingerprintUnlockController;
    418     LightBarController mLightBarController;
    419     protected LockscreenWallpaper mLockscreenWallpaper;
    420 
    421     int mNaturalBarHeight = -1;
    422 
    423     Point mCurrentDisplaySize = new Point();
    424 
    425     protected StatusBarWindowView mStatusBarWindow;
    426     protected PhoneStatusBarView mStatusBarView;
    427     private int mStatusBarWindowState = WINDOW_STATE_SHOWING;
    428     protected StatusBarWindowManager mStatusBarWindowManager;
    429     protected UnlockMethodCache mUnlockMethodCache;
    430     private DozeServiceHost mDozeServiceHost = new DozeServiceHost();
    431     private boolean mWakeUpComingFromTouch;
    432     private PointF mWakeUpTouchLocation;
    433 
    434     int mPixelFormat;
    435     Object mQueueLock = new Object();
    436 
    437     protected StatusBarIconController mIconController;
    438 
    439     // expanded notifications
    440     protected NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
    441     View mExpandedContents;
    442     TextView mNotificationPanelDebugText;
    443 
    444     /**
    445      * {@code true} if notifications not part of a group should by default be rendered in their
    446      * expanded state. If {@code false}, then only the first notification will be expanded if
    447      * possible.
    448      */
    449     private boolean mAlwaysExpandNonGroupedNotification;
    450 
    451     // settings
    452     private QSPanel mQSPanel;
    453 
    454     // top bar
    455     protected KeyguardStatusBarView mKeyguardStatusBar;
    456     boolean mLeaveOpenOnKeyguardHide;
    457     KeyguardIndicationController mKeyguardIndicationController;
    458 
    459     // Keyguard is going away soon.
    460     private boolean mKeyguardGoingAway;
    461     // Keyguard is actually fading away now.
    462     protected boolean mKeyguardFadingAway;
    463     protected long mKeyguardFadingAwayDelay;
    464     protected long mKeyguardFadingAwayDuration;
    465 
    466     // RemoteInputView to be activated after unlock
    467     private View mPendingRemoteInputView;
    468     private View mPendingWorkRemoteInputView;
    469 
    470     private View mReportRejectedTouch;
    471 
    472     int mMaxAllowedKeyguardNotifications;
    473 
    474     boolean mExpandedVisible;
    475 
    476     // the tracker view
    477     int mTrackingPosition; // the position of the top of the tracking view.
    478 
    479     // Tracking finger for opening/closing.
    480     boolean mTracking;
    481 
    482     int[] mAbsPos = new int[2];
    483     ArrayList<Runnable> mPostCollapseRunnables = new ArrayList<>();
    484 
    485     // for disabling the status bar
    486     int mDisabled1 = 0;
    487     int mDisabled2 = 0;
    488 
    489     // tracking calls to View.setSystemUiVisibility()
    490     int mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE;
    491     private final Rect mLastFullscreenStackBounds = new Rect();
    492     private final Rect mLastDockedStackBounds = new Rect();
    493     private final Rect mTmpRect = new Rect();
    494 
    495     // last value sent to window manager
    496     private int mLastDispatchedSystemUiVisibility = ~View.SYSTEM_UI_FLAG_VISIBLE;
    497 
    498     DisplayMetrics mDisplayMetrics = new DisplayMetrics();
    499 
    500     // XXX: gesture research
    501     private final GestureRecorder mGestureRec = DEBUG_GESTURES
    502         ? new GestureRecorder("/sdcard/statusbar_gestures.dat")
    503         : null;
    504 
    505     private ScreenPinningRequest mScreenPinningRequest;
    506 
    507     private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
    508 
    509     // ensure quick settings is disabled until the current user makes it through the setup wizard
    510     private boolean mUserSetup = false;
    511     private DeviceProvisionedListener mUserSetupObserver = new DeviceProvisionedListener() {
    512         @Override
    513         public void onUserSetupChanged() {
    514             final boolean userSetup = mDeviceProvisionedController.isUserSetup(
    515                     mDeviceProvisionedController.getCurrentUser());
    516             if (MULTIUSER_DEBUG) Log.d(TAG, String.format("User setup changed: " +
    517                     "userSetup=%s mUserSetup=%s", userSetup, mUserSetup));
    518 
    519             if (userSetup != mUserSetup) {
    520                 mUserSetup = userSetup;
    521                 if (!mUserSetup && mStatusBarView != null)
    522                     animateCollapseQuickSettings();
    523                 if (mNotificationPanel != null) {
    524                     mNotificationPanel.setUserSetupComplete(mUserSetup);
    525                 }
    526                 updateQsExpansionEnabled();
    527             }
    528         }
    529     };
    530 
    531     protected H mHandler = createHandler();
    532     final private ContentObserver mHeadsUpObserver = new ContentObserver(mHandler) {
    533         @Override
    534         public void onChange(boolean selfChange) {
    535             boolean wasUsing = mUseHeadsUp;
    536             mUseHeadsUp = ENABLE_HEADS_UP && !mDisableNotificationAlerts
    537                     && Settings.Global.HEADS_UP_OFF != Settings.Global.getInt(
    538                     mContext.getContentResolver(), Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED,
    539                     Settings.Global.HEADS_UP_OFF);
    540             mHeadsUpTicker = mUseHeadsUp && 0 != Settings.Global.getInt(
    541                     mContext.getContentResolver(), SETTING_HEADS_UP_TICKER, 0);
    542             Log.d(TAG, "heads up is " + (mUseHeadsUp ? "enabled" : "disabled"));
    543             if (wasUsing != mUseHeadsUp) {
    544                 if (!mUseHeadsUp) {
    545                     Log.d(TAG, "dismissing any existing heads up notification on disable event");
    546                     mHeadsUpManager.releaseAllImmediately();
    547                 }
    548             }
    549         }
    550     };
    551 
    552     private int mInteractingWindows;
    553     private boolean mAutohideSuspended;
    554     private int mStatusBarMode;
    555     private int mMaxKeyguardNotifications;
    556 
    557     private ViewMediatorCallback mKeyguardViewMediatorCallback;
    558     protected ScrimController mScrimController;
    559     protected DozeScrimController mDozeScrimController;
    560     private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class);
    561 
    562     private final Runnable mAutohide = () -> {
    563         int requested = mSystemUiVisibility & ~STATUS_OR_NAV_TRANSIENT;
    564         if (mSystemUiVisibility != requested) {
    565             notifyUiVisibilityChanged(requested);
    566         }
    567     };
    568 
    569     private boolean mWaitingForKeyguardExit;
    570     protected boolean mDozing;
    571     private boolean mDozingRequested;
    572     protected boolean mScrimSrcModeEnabled;
    573 
    574     public static final Interpolator ALPHA_IN = Interpolators.ALPHA_IN;
    575     public static final Interpolator ALPHA_OUT = Interpolators.ALPHA_OUT;
    576 
    577     protected BackDropView mBackdrop;
    578     protected ImageView mBackdropFront, mBackdropBack;
    579     protected PorterDuffXfermode mSrcXferMode = new PorterDuffXfermode(PorterDuff.Mode.SRC);
    580     protected PorterDuffXfermode mSrcOverXferMode =
    581             new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER);
    582 
    583     private MediaSessionManager mMediaSessionManager;
    584     private MediaController mMediaController;
    585     private String mMediaNotificationKey;
    586     private MediaMetadata mMediaMetadata;
    587     private MediaController.Callback mMediaListener
    588             = new MediaController.Callback() {
    589         @Override
    590         public void onPlaybackStateChanged(PlaybackState state) {
    591             super.onPlaybackStateChanged(state);
    592             if (DEBUG_MEDIA) Log.v(TAG, "DEBUG_MEDIA: onPlaybackStateChanged: " + state);
    593             if (state != null) {
    594                 if (!isPlaybackActive(state.getState())) {
    595                     clearCurrentMediaNotification();
    596                     updateMediaMetaData(true, true);
    597                 }
    598             }
    599         }
    600 
    601         @Override
    602         public void onMetadataChanged(MediaMetadata metadata) {
    603             super.onMetadataChanged(metadata);
    604             if (DEBUG_MEDIA) Log.v(TAG, "DEBUG_MEDIA: onMetadataChanged: " + metadata);
    605             mMediaMetadata = metadata;
    606             updateMediaMetaData(true, true);
    607         }
    608     };
    609 
    610     private final OnChildLocationsChangedListener mOnChildLocationsChangedListener =
    611             new OnChildLocationsChangedListener() {
    612         @Override
    613         public void onChildLocationsChanged(NotificationStackScrollLayout stackScrollLayout) {
    614             userActivity();
    615         }
    616     };
    617 
    618     private int mDisabledUnmodified1;
    619     private int mDisabledUnmodified2;
    620 
    621     /** Keys of notifications currently visible to the user. */
    622     private final ArraySet<NotificationVisibility> mCurrentlyVisibleNotifications =
    623             new ArraySet<>();
    624     private long mLastVisibilityReportUptimeMs;
    625 
    626     private Runnable mLaunchTransitionEndRunnable;
    627     protected boolean mLaunchTransitionFadingAway;
    628     private ExpandableNotificationRow mDraggedDownRow;
    629     private boolean mLaunchCameraOnScreenTurningOn;
    630     private boolean mLaunchCameraOnFinishedGoingToSleep;
    631     private int mLastCameraLaunchSource;
    632     private PowerManager.WakeLock mGestureWakeLock;
    633     private Vibrator mVibrator;
    634     private long[] mCameraLaunchGestureVibePattern;
    635 
    636     private final int[] mTmpInt2 = new int[2];
    637 
    638     // Fingerprint (as computed by getLoggingFingerprint() of the last logged state.
    639     private int mLastLoggedStateFingerprint;
    640     private boolean mTopHidesStatusBar;
    641     private boolean mStatusBarWindowHidden;
    642     private boolean mHideIconsForBouncer;
    643     private boolean mIsOccluded;
    644     private boolean mWereIconsJustHidden;
    645     private boolean mBouncerWasShowingWhenHidden;
    646 
    647     public boolean isStartedGoingToSleep() {
    648         return mStartedGoingToSleep;
    649     }
    650 
    651     /**
    652      * If set, the device has started going to sleep but isn't fully non-interactive yet.
    653      */
    654     protected boolean mStartedGoingToSleep;
    655 
    656     private final OnChildLocationsChangedListener mNotificationLocationsChangedListener =
    657             new OnChildLocationsChangedListener() {
    658                 @Override
    659                 public void onChildLocationsChanged(
    660                         NotificationStackScrollLayout stackScrollLayout) {
    661                     if (mHandler.hasCallbacks(mVisibilityReporter)) {
    662                         // Visibilities will be reported when the existing
    663                         // callback is executed.
    664                         return;
    665                     }
    666                     // Calculate when we're allowed to run the visibility
    667                     // reporter. Note that this timestamp might already have
    668                     // passed. That's OK, the callback will just be executed
    669                     // ASAP.
    670                     long nextReportUptimeMs =
    671                             mLastVisibilityReportUptimeMs + VISIBILITY_REPORT_MIN_DELAY_MS;
    672                     mHandler.postAtTime(mVisibilityReporter, nextReportUptimeMs);
    673                 }
    674             };
    675 
    676     // Tracks notifications currently visible in mNotificationStackScroller and
    677     // emits visibility events via NoMan on changes.
    678     protected final Runnable mVisibilityReporter = new Runnable() {
    679         private final ArraySet<NotificationVisibility> mTmpNewlyVisibleNotifications =
    680                 new ArraySet<>();
    681         private final ArraySet<NotificationVisibility> mTmpCurrentlyVisibleNotifications =
    682                 new ArraySet<>();
    683         private final ArraySet<NotificationVisibility> mTmpNoLongerVisibleNotifications =
    684                 new ArraySet<>();
    685 
    686         @Override
    687         public void run() {
    688             mLastVisibilityReportUptimeMs = SystemClock.uptimeMillis();
    689             final String mediaKey = getCurrentMediaNotificationKey();
    690 
    691             // 1. Loop over mNotificationData entries:
    692             //   A. Keep list of visible notifications.
    693             //   B. Keep list of previously hidden, now visible notifications.
    694             // 2. Compute no-longer visible notifications by removing currently
    695             //    visible notifications from the set of previously visible
    696             //    notifications.
    697             // 3. Report newly visible and no-longer visible notifications.
    698             // 4. Keep currently visible notifications for next report.
    699             ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
    700             int N = activeNotifications.size();
    701             for (int i = 0; i < N; i++) {
    702                 Entry entry = activeNotifications.get(i);
    703                 String key = entry.notification.getKey();
    704                 boolean isVisible = mStackScroller.isInVisibleLocation(entry.row);
    705                 NotificationVisibility visObj = NotificationVisibility.obtain(key, i, isVisible);
    706                 boolean previouslyVisible = mCurrentlyVisibleNotifications.contains(visObj);
    707                 if (isVisible) {
    708                     // Build new set of visible notifications.
    709                     mTmpCurrentlyVisibleNotifications.add(visObj);
    710                     if (!previouslyVisible) {
    711                         mTmpNewlyVisibleNotifications.add(visObj);
    712                     }
    713                 } else {
    714                     // release object
    715                     visObj.recycle();
    716                 }
    717             }
    718             mTmpNoLongerVisibleNotifications.addAll(mCurrentlyVisibleNotifications);
    719             mTmpNoLongerVisibleNotifications.removeAll(mTmpCurrentlyVisibleNotifications);
    720 
    721             logNotificationVisibilityChanges(
    722                     mTmpNewlyVisibleNotifications, mTmpNoLongerVisibleNotifications);
    723 
    724             recycleAllVisibilityObjects(mCurrentlyVisibleNotifications);
    725             mCurrentlyVisibleNotifications.addAll(mTmpCurrentlyVisibleNotifications);
    726 
    727             recycleAllVisibilityObjects(mTmpNoLongerVisibleNotifications);
    728             mTmpCurrentlyVisibleNotifications.clear();
    729             mTmpNewlyVisibleNotifications.clear();
    730             mTmpNoLongerVisibleNotifications.clear();
    731         }
    732     };
    733 
    734     private NotificationMessagingUtil mMessagingUtil;
    735     private KeyguardUserSwitcher mKeyguardUserSwitcher;
    736     private UserSwitcherController mUserSwitcherController;
    737     private NetworkController mNetworkController;
    738     private KeyguardMonitorImpl mKeyguardMonitor
    739             = (KeyguardMonitorImpl) Dependency.get(KeyguardMonitor.class);
    740     private BatteryController mBatteryController;
    741     protected boolean mPanelExpanded;
    742     private IOverlayManager mOverlayManager;
    743     private boolean mKeyguardRequested;
    744     private boolean mIsKeyguard;
    745     private LogMaker mStatusBarStateLog;
    746     private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
    747     protected NotificationIconAreaController mNotificationIconAreaController;
    748     private boolean mReinflateNotificationsOnUserSwitched;
    749     private HashMap<String, Entry> mPendingNotifications = new HashMap<>();
    750     private boolean mClearAllEnabled;
    751     @Nullable private View mAmbientIndicationContainer;
    752     private String mKeyToRemoveOnGutsClosed;
    753     private SysuiColorExtractor mColorExtractor;
    754     private ForegroundServiceController mForegroundServiceController;
    755     private ScreenLifecycle mScreenLifecycle;
    756     @VisibleForTesting WakefulnessLifecycle mWakefulnessLifecycle;
    757 
    758     private void recycleAllVisibilityObjects(ArraySet<NotificationVisibility> array) {
    759         final int N = array.size();
    760         for (int i = 0 ; i < N; i++) {
    761             array.valueAt(i).recycle();
    762         }
    763         array.clear();
    764     }
    765 
    766     private final View.OnClickListener mGoToLockedShadeListener = v -> {
    767         if (mState == StatusBarState.KEYGUARD) {
    768             wakeUpIfDozing(SystemClock.uptimeMillis(), v);
    769             goToLockedShade(null);
    770         }
    771     };
    772     private HashMap<ExpandableNotificationRow, List<ExpandableNotificationRow>> mTmpChildOrderMap
    773             = new HashMap<>();
    774     private RankingMap mLatestRankingMap;
    775     private boolean mNoAnimationOnNextBarModeChange;
    776     private FalsingManager mFalsingManager;
    777 
    778     private KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() {
    779         @Override
    780         public void onDreamingStateChanged(boolean dreaming) {
    781             if (dreaming) {
    782                 maybeEscalateHeadsUp();
    783             }
    784         }
    785     };
    786 
    787     private NavigationBarFragment mNavigationBar;
    788     private View mNavigationBarView;
    789 
    790     @Override
    791     public void start() {
    792         mNetworkController = Dependency.get(NetworkController.class);
    793         mUserSwitcherController = Dependency.get(UserSwitcherController.class);
    794         mScreenLifecycle = Dependency.get(ScreenLifecycle.class);
    795         mScreenLifecycle.addObserver(mScreenObserver);
    796         mWakefulnessLifecycle = Dependency.get(WakefulnessLifecycle.class);
    797         mWakefulnessLifecycle.addObserver(mWakefulnessObserver);
    798         mBatteryController = Dependency.get(BatteryController.class);
    799         mAssistManager = Dependency.get(AssistManager.class);
    800         mSystemServicesProxy = SystemServicesProxy.getInstance(mContext);
    801         mOverlayManager = IOverlayManager.Stub.asInterface(
    802                 ServiceManager.getService(Context.OVERLAY_SERVICE));
    803 
    804         mColorExtractor = Dependency.get(SysuiColorExtractor.class);
    805         mColorExtractor.addOnColorsChangedListener(this);
    806 
    807         mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
    808 
    809         mForegroundServiceController = Dependency.get(ForegroundServiceController.class);
    810 
    811         mDisplay = mWindowManager.getDefaultDisplay();
    812         updateDisplaySize();
    813 
    814         Resources res = mContext.getResources();
    815         mScrimSrcModeEnabled = res.getBoolean(R.bool.config_status_bar_scrim_behind_use_src);
    816         mClearAllEnabled = res.getBoolean(R.bool.config_enableNotificationsClearAll);
    817         mAlwaysExpandNonGroupedNotification =
    818                 res.getBoolean(R.bool.config_alwaysExpandNonGroupedNotifications);
    819 
    820         DateTimeView.setReceiverHandler(Dependency.get(Dependency.TIME_TICK_HANDLER));
    821         putComponent(StatusBar.class, this);
    822 
    823         // start old BaseStatusBar.start().
    824         mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
    825         mDevicePolicyManager = (DevicePolicyManager) mContext.getSystemService(
    826                 Context.DEVICE_POLICY_SERVICE);
    827 
    828         mNotificationData = new NotificationData(this);
    829         mMessagingUtil = new NotificationMessagingUtil(mContext);
    830 
    831         mAccessibilityManager = (AccessibilityManager)
    832                 mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
    833 
    834         mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
    835 
    836         mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
    837         mDeviceProvisionedController.addCallback(mDeviceProvisionedListener);
    838         mContext.getContentResolver().registerContentObserver(
    839                 Settings.Global.getUriFor(Settings.Global.ZEN_MODE), false,
    840                 mSettingsObserver);
    841         mContext.getContentResolver().registerContentObserver(
    842                 Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS), false,
    843                 mLockscreenSettingsObserver,
    844                 UserHandle.USER_ALL);
    845         if (ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT) {
    846             mContext.getContentResolver().registerContentObserver(
    847                     Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT),
    848                     false,
    849                     mSettingsObserver,
    850                     UserHandle.USER_ALL);
    851         }
    852 
    853         mContext.getContentResolver().registerContentObserver(
    854                 Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
    855                 true,
    856                 mLockscreenSettingsObserver,
    857                 UserHandle.USER_ALL);
    858 
    859         mBarService = IStatusBarService.Stub.asInterface(
    860                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
    861 
    862         mRecents = getComponent(Recents.class);
    863 
    864         final Configuration currentConfig = res.getConfiguration();
    865         mLocale = currentConfig.locale;
    866         mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(mLocale);
    867 
    868         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
    869         mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
    870         mLockPatternUtils = new LockPatternUtils(mContext);
    871 
    872         // Connect in to the status bar manager service
    873         mCommandQueue = getComponent(CommandQueue.class);
    874         mCommandQueue.addCallbacks(this);
    875 
    876         int[] switches = new int[9];
    877         ArrayList<IBinder> binders = new ArrayList<>();
    878         ArrayList<String> iconSlots = new ArrayList<>();
    879         ArrayList<StatusBarIcon> icons = new ArrayList<>();
    880         Rect fullscreenStackBounds = new Rect();
    881         Rect dockedStackBounds = new Rect();
    882         try {
    883             mBarService.registerStatusBar(mCommandQueue, iconSlots, icons, switches, binders,
    884                     fullscreenStackBounds, dockedStackBounds);
    885         } catch (RemoteException ex) {
    886             // If the system process isn't there we're doomed anyway.
    887         }
    888 
    889         createAndAddWindows();
    890 
    891         mSettingsObserver.onChange(false); // set up
    892         mCommandQueue.disable(switches[0], switches[6], false /* animate */);
    893         setSystemUiVisibility(switches[1], switches[7], switches[8], 0xffffffff,
    894                 fullscreenStackBounds, dockedStackBounds);
    895         topAppWindowChanged(switches[2] != 0);
    896         // StatusBarManagerService has a back up of IME token and it's restored here.
    897         setImeWindowStatus(binders.get(0), switches[3], switches[4], switches[5] != 0);
    898 
    899         // Set up the initial icon state
    900         int N = iconSlots.size();
    901         for (int i=0; i < N; i++) {
    902             mCommandQueue.setIcon(iconSlots.get(i), icons.get(i));
    903         }
    904 
    905         // Set up the initial notification state.
    906         try {
    907             mNotificationListener.registerAsSystemService(mContext,
    908                     new ComponentName(mContext.getPackageName(), getClass().getCanonicalName()),
    909                     UserHandle.USER_ALL);
    910         } catch (RemoteException e) {
    911             Log.e(TAG, "Unable to register notification listener", e);
    912         }
    913 
    914 
    915         if (DEBUG) {
    916             Log.d(TAG, String.format(
    917                     "init: icons=%d disabled=0x%08x lights=0x%08x menu=0x%08x imeButton=0x%08x",
    918                    icons.size(),
    919                    switches[0],
    920                    switches[1],
    921                    switches[2],
    922                    switches[3]
    923                    ));
    924         }
    925 
    926         mCurrentUserId = ActivityManager.getCurrentUser();
    927         setHeadsUpUser(mCurrentUserId);
    928 
    929         IntentFilter filter = new IntentFilter();
    930         filter.addAction(Intent.ACTION_USER_SWITCHED);
    931         filter.addAction(Intent.ACTION_USER_ADDED);
    932         filter.addAction(Intent.ACTION_USER_PRESENT);
    933         mContext.registerReceiver(mBaseBroadcastReceiver, filter);
    934 
    935         IntentFilter internalFilter = new IntentFilter();
    936         internalFilter.addAction(NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION);
    937         internalFilter.addAction(BANNER_ACTION_CANCEL);
    938         internalFilter.addAction(BANNER_ACTION_SETUP);
    939         mContext.registerReceiver(mBaseBroadcastReceiver, internalFilter, PERMISSION_SELF, null);
    940 
    941         IntentFilter allUsersFilter = new IntentFilter();
    942         allUsersFilter.addAction(
    943                 DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
    944         allUsersFilter.addAction(Intent.ACTION_DEVICE_LOCKED_CHANGED);
    945         mContext.registerReceiverAsUser(mAllUsersReceiver, UserHandle.ALL, allUsersFilter,
    946                 null, null);
    947         updateCurrentProfilesCache();
    948 
    949         IVrManager vrManager = IVrManager.Stub.asInterface(ServiceManager.getService(
    950                 Context.VR_SERVICE));
    951         try {
    952             vrManager.registerListener(mVrStateCallbacks);
    953         } catch (RemoteException e) {
    954             Slog.e(TAG, "Failed to register VR mode state listener: " + e);
    955         }
    956 
    957         mNonBlockablePkgs = new HashSet<>();
    958         Collections.addAll(mNonBlockablePkgs, res.getStringArray(
    959                 com.android.internal.R.array.config_nonBlockableNotificationPackages));
    960         // end old BaseStatusBar.start().
    961 
    962         mMediaSessionManager
    963                 = (MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE);
    964         // TODO: use MediaSessionManager.SessionListener to hook us up to future updates
    965         // in session state
    966 
    967         // Lastly, call to the icon policy to install/update all the icons.
    968         mIconPolicy = new PhoneStatusBarPolicy(mContext, mIconController);
    969         mSettingsObserver.onChange(false); // set up
    970 
    971         mHeadsUpObserver.onChange(true); // set up
    972         if (ENABLE_HEADS_UP) {
    973             mContext.getContentResolver().registerContentObserver(
    974                     Settings.Global.getUriFor(Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED), true,
    975                     mHeadsUpObserver);
    976             mContext.getContentResolver().registerContentObserver(
    977                     Settings.Global.getUriFor(SETTING_HEADS_UP_TICKER), true,
    978                     mHeadsUpObserver);
    979         }
    980         mUnlockMethodCache = UnlockMethodCache.getInstance(mContext);
    981         mUnlockMethodCache.addListener(this);
    982         startKeyguard();
    983 
    984         KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateCallback);
    985         putComponent(DozeHost.class, mDozeServiceHost);
    986 
    987         notifyUserAboutHiddenNotifications();
    988 
    989         mScreenPinningRequest = new ScreenPinningRequest(mContext);
    990         mFalsingManager = FalsingManager.getInstance(mContext);
    991 
    992         Dependency.get(ActivityStarterDelegate.class).setActivityStarterImpl(this);
    993 
    994         Dependency.get(ConfigurationController.class).addCallback(this);
    995     }
    996 
    997     protected void createIconController() {
    998     }
    999 
   1000     // ================================================================================
   1001     // Constructing the view
   1002     // ================================================================================
   1003     protected void makeStatusBarView() {
   1004         final Context context = mContext;
   1005         updateDisplaySize(); // populates mDisplayMetrics
   1006         updateResources();
   1007         updateTheme();
   1008 
   1009         inflateStatusBarWindow(context);
   1010         mStatusBarWindow.setService(this);
   1011         mStatusBarWindow.setOnTouchListener(getStatusBarWindowTouchListener());
   1012 
   1013         // TODO: Deal with the ugliness that comes from having some of the statusbar broken out
   1014         // into fragments, but the rest here, it leaves some awkward lifecycle and whatnot.
   1015         mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById(
   1016                 R.id.notification_panel);
   1017         mStackScroller = (NotificationStackScrollLayout) mStatusBarWindow.findViewById(
   1018                 R.id.notification_stack_scroller);
   1019         mNotificationPanel.setStatusBar(this);
   1020         mNotificationPanel.setGroupManager(mGroupManager);
   1021         mAboveShelfObserver = new AboveShelfObserver(mStackScroller);
   1022         mAboveShelfObserver.setListener(mStatusBarWindow.findViewById(
   1023                 R.id.notification_container_parent));
   1024         mKeyguardStatusBar = (KeyguardStatusBarView) mStatusBarWindow.findViewById(R.id.keyguard_header);
   1025 
   1026         mNotificationIconAreaController = SystemUIFactory.getInstance()
   1027                 .createNotificationIconAreaController(context, this);
   1028         inflateShelf();
   1029         mNotificationIconAreaController.setupShelf(mNotificationShelf);
   1030         Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mNotificationIconAreaController);
   1031         FragmentHostManager.get(mStatusBarWindow)
   1032                 .addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> {
   1033                     CollapsedStatusBarFragment statusBarFragment =
   1034                             (CollapsedStatusBarFragment) fragment;
   1035                     statusBarFragment.initNotificationIconArea(mNotificationIconAreaController);
   1036                     mStatusBarView = (PhoneStatusBarView) fragment.getView();
   1037                     mStatusBarView.setBar(this);
   1038                     mStatusBarView.setPanel(mNotificationPanel);
   1039                     mStatusBarView.setScrimController(mScrimController);
   1040                     mStatusBarView.setBouncerShowing(mBouncerShowing);
   1041                     setAreThereNotifications();
   1042                     checkBarModes();
   1043                 }).getFragmentManager()
   1044                 .beginTransaction()
   1045                 .replace(R.id.status_bar_container, new CollapsedStatusBarFragment(),
   1046                         CollapsedStatusBarFragment.TAG)
   1047                 .commit();
   1048         mIconController = Dependency.get(StatusBarIconController.class);
   1049 
   1050         mHeadsUpManager = new HeadsUpManager(context, mStatusBarWindow, mGroupManager);
   1051         mHeadsUpManager.setBar(this);
   1052         mHeadsUpManager.addListener(this);
   1053         mHeadsUpManager.addListener(mNotificationPanel);
   1054         mHeadsUpManager.addListener(mGroupManager);
   1055         mHeadsUpManager.addListener(mVisualStabilityManager);
   1056         mNotificationPanel.setHeadsUpManager(mHeadsUpManager);
   1057         mNotificationData.setHeadsUpManager(mHeadsUpManager);
   1058         mGroupManager.setHeadsUpManager(mHeadsUpManager);
   1059         mHeadsUpManager.setVisualStabilityManager(mVisualStabilityManager);
   1060 
   1061         if (MULTIUSER_DEBUG) {
   1062             mNotificationPanelDebugText = (TextView) mNotificationPanel.findViewById(
   1063                     R.id.header_debug_info);
   1064             mNotificationPanelDebugText.setVisibility(View.VISIBLE);
   1065         }
   1066 
   1067         try {
   1068             boolean showNav = mWindowManagerService.hasNavigationBar();
   1069             if (DEBUG) Log.v(TAG, "hasNavigationBar=" + showNav);
   1070             if (showNav) {
   1071                 createNavigationBar();
   1072             }
   1073         } catch (RemoteException ex) {
   1074             // no window manager? good luck with that
   1075         }
   1076 
   1077         // figure out which pixel-format to use for the status bar.
   1078         mPixelFormat = PixelFormat.OPAQUE;
   1079 
   1080         mStackScroller.setLongPressListener(getNotificationLongClicker());
   1081         mStackScroller.setStatusBar(this);
   1082         mStackScroller.setGroupManager(mGroupManager);
   1083         mStackScroller.setHeadsUpManager(mHeadsUpManager);
   1084         mGroupManager.setOnGroupChangeListener(mStackScroller);
   1085         mVisualStabilityManager.setVisibilityLocationProvider(mStackScroller);
   1086 
   1087         inflateEmptyShadeView();
   1088         inflateDismissView();
   1089         mExpandedContents = mStackScroller;
   1090 
   1091         mBackdrop = (BackDropView) mStatusBarWindow.findViewById(R.id.backdrop);
   1092         mBackdropFront = (ImageView) mBackdrop.findViewById(R.id.backdrop_front);
   1093         mBackdropBack = (ImageView) mBackdrop.findViewById(R.id.backdrop_back);
   1094 
   1095         if (ENABLE_LOCKSCREEN_WALLPAPER) {
   1096             mLockscreenWallpaper = new LockscreenWallpaper(mContext, this, mHandler);
   1097         }
   1098 
   1099         mKeyguardIndicationController =
   1100                 SystemUIFactory.getInstance().createKeyguardIndicationController(mContext,
   1101                 (ViewGroup) mStatusBarWindow.findViewById(R.id.keyguard_indication_area),
   1102                 mNotificationPanel.getLockIcon());
   1103         mNotificationPanel.setKeyguardIndicationController(mKeyguardIndicationController);
   1104 
   1105 
   1106         mAmbientIndicationContainer = mStatusBarWindow.findViewById(
   1107                 R.id.ambient_indication_container);
   1108 
   1109         // set the initial view visibility
   1110         setAreThereNotifications();
   1111 
   1112         // TODO: Find better place for this callback.
   1113         mBatteryController.addCallback(new BatteryStateChangeCallback() {
   1114             @Override
   1115             public void onPowerSaveChanged(boolean isPowerSave) {
   1116                 mHandler.post(mCheckBarModes);
   1117                 if (mDozeServiceHost != null) {
   1118                     mDozeServiceHost.firePowerSaveChanged(isPowerSave);
   1119                 }
   1120             }
   1121 
   1122             @Override
   1123             public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
   1124                 // noop
   1125             }
   1126         });
   1127 
   1128         mLightBarController = Dependency.get(LightBarController.class);
   1129         if (mNavigationBar != null) {
   1130             mNavigationBar.setLightBarController(mLightBarController);
   1131         }
   1132 
   1133         ScrimView scrimBehind = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_behind);
   1134         ScrimView scrimInFront = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_in_front);
   1135         View headsUpScrim = mStatusBarWindow.findViewById(R.id.heads_up_scrim);
   1136         mScrimController = SystemUIFactory.getInstance().createScrimController(mLightBarController,
   1137                 scrimBehind, scrimInFront, headsUpScrim, mLockscreenWallpaper,
   1138                 scrimsVisible -> {
   1139                     if (mStatusBarWindowManager != null) {
   1140                         mStatusBarWindowManager.setScrimsVisible(scrimsVisible);
   1141                     }
   1142                 });
   1143         if (mScrimSrcModeEnabled) {
   1144             Runnable runnable = new Runnable() {
   1145                 @Override
   1146                 public void run() {
   1147                     boolean asSrc = mBackdrop.getVisibility() != View.VISIBLE;
   1148                     mScrimController.setDrawBehindAsSrc(asSrc);
   1149                     mStackScroller.setDrawBackgroundAsSrc(asSrc);
   1150                 }
   1151             };
   1152             mBackdrop.setOnVisibilityChangedRunnable(runnable);
   1153             runnable.run();
   1154         }
   1155         mHeadsUpManager.addListener(mScrimController);
   1156         mStackScroller.setScrimController(mScrimController);
   1157         mDozeScrimController = new DozeScrimController(mScrimController, context);
   1158 
   1159         // Other icons
   1160         mVolumeComponent = getComponent(VolumeComponent.class);
   1161 
   1162         mNotificationPanel.setUserSetupComplete(mUserSetup);
   1163         if (UserManager.get(mContext).isUserSwitcherEnabled()) {
   1164             createUserSwitcher();
   1165         }
   1166 
   1167         // Set up the quick settings tile panel
   1168         View container = mStatusBarWindow.findViewById(R.id.qs_frame);
   1169         if (container != null) {
   1170             FragmentHostManager fragmentHostManager = FragmentHostManager.get(container);
   1171             ExtensionFragmentListener.attachExtensonToFragment(container, QS.TAG, R.id.qs_frame,
   1172                     Dependency.get(ExtensionController.class).newExtension(QS.class)
   1173                             .withPlugin(QS.class)
   1174                             .withFeature(
   1175                                     PackageManager.FEATURE_AUTOMOTIVE, () -> new CarQSFragment())
   1176                             .withDefault(() -> new QSFragment())
   1177                             .build());
   1178             final QSTileHost qsh = SystemUIFactory.getInstance().createQSTileHost(mContext, this,
   1179                     mIconController);
   1180             mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow,
   1181                     mScrimController);
   1182             fragmentHostManager.addTagListener(QS.TAG, (tag, f) -> {
   1183                 QS qs = (QS) f;
   1184                 if (qs instanceof QSFragment) {
   1185                     ((QSFragment) qs).setHost(qsh);
   1186                     mQSPanel = ((QSFragment) qs).getQsPanel();
   1187                     mQSPanel.setBrightnessMirror(mBrightnessMirrorController);
   1188                     mKeyguardStatusBar.setQSPanel(mQSPanel);
   1189                 }
   1190             });
   1191         }
   1192 
   1193         mReportRejectedTouch = mStatusBarWindow.findViewById(R.id.report_rejected_touch);
   1194         if (mReportRejectedTouch != null) {
   1195             updateReportRejectedTouchVisibility();
   1196             mReportRejectedTouch.setOnClickListener(v -> {
   1197                 Uri session = mFalsingManager.reportRejectedTouch();
   1198                 if (session == null) { return; }
   1199 
   1200                 StringWriter message = new StringWriter();
   1201                 message.write("Build info: ");
   1202                 message.write(SystemProperties.get("ro.build.description"));
   1203                 message.write("\nSerial number: ");
   1204                 message.write(SystemProperties.get("ro.serialno"));
   1205                 message.write("\n");
   1206 
   1207                 PrintWriter falsingPw = new PrintWriter(message);
   1208                 FalsingLog.dump(falsingPw);
   1209                 falsingPw.flush();
   1210 
   1211                 startActivityDismissingKeyguard(Intent.createChooser(new Intent(Intent.ACTION_SEND)
   1212                                 .setType("*/*")
   1213                                 .putExtra(Intent.EXTRA_SUBJECT, "Rejected touch report")
   1214                                 .putExtra(Intent.EXTRA_STREAM, session)
   1215                                 .putExtra(Intent.EXTRA_TEXT, message.toString()),
   1216                         "Share rejected touch report")
   1217                                 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK),
   1218                         true /* onlyProvisioned */, true /* dismissShade */);
   1219             });
   1220         }
   1221 
   1222         PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
   1223         if (!pm.isScreenOn()) {
   1224             mBroadcastReceiver.onReceive(mContext, new Intent(Intent.ACTION_SCREEN_OFF));
   1225         }
   1226         mGestureWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
   1227                 "GestureWakeLock");
   1228         mVibrator = mContext.getSystemService(Vibrator.class);
   1229         int[] pattern = mContext.getResources().getIntArray(
   1230                 R.array.config_cameraLaunchGestureVibePattern);
   1231         mCameraLaunchGestureVibePattern = new long[pattern.length];
   1232         for (int i = 0; i < pattern.length; i++) {
   1233             mCameraLaunchGestureVibePattern[i] = pattern[i];
   1234         }
   1235 
   1236         // receive broadcasts
   1237         IntentFilter filter = new IntentFilter();
   1238         filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
   1239         filter.addAction(Intent.ACTION_SCREEN_OFF);
   1240         filter.addAction(DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG);
   1241         context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
   1242 
   1243         IntentFilter demoFilter = new IntentFilter();
   1244         if (DEBUG_MEDIA_FAKE_ARTWORK) {
   1245             demoFilter.addAction(ACTION_FAKE_ARTWORK);
   1246         }
   1247         demoFilter.addAction(ACTION_DEMO);
   1248         context.registerReceiverAsUser(mDemoReceiver, UserHandle.ALL, demoFilter,
   1249                 android.Manifest.permission.DUMP, null);
   1250 
   1251         // listen for USER_SETUP_COMPLETE setting (per-user)
   1252         mDeviceProvisionedController.addCallback(mUserSetupObserver);
   1253         mUserSetupObserver.onUserSetupChanged();
   1254 
   1255         // disable profiling bars, since they overlap and clutter the output on app windows
   1256         ThreadedRenderer.overrideProperty("disableProfileBars", "true");
   1257 
   1258         // Private API call to make the shadows look better for Recents
   1259         ThreadedRenderer.overrideProperty("ambientRatio", String.valueOf(1.5f));
   1260     }
   1261 
   1262     protected void createNavigationBar() {
   1263         mNavigationBarView = NavigationBarFragment.create(mContext, (tag, fragment) -> {
   1264             mNavigationBar = (NavigationBarFragment) fragment;
   1265             if (mLightBarController != null) {
   1266                 mNavigationBar.setLightBarController(mLightBarController);
   1267             }
   1268             mNavigationBar.setCurrentSysuiVisibility(mSystemUiVisibility);
   1269         });
   1270     }
   1271 
   1272     /**
   1273      * Returns the {@link android.view.View.OnTouchListener} that will be invoked when the
   1274      * background window of the status bar is clicked.
   1275      */
   1276     protected View.OnTouchListener getStatusBarWindowTouchListener() {
   1277         return (v, event) -> {
   1278             checkUserAutohide(v, event);
   1279             checkRemoteInputOutside(event);
   1280             if (event.getAction() == MotionEvent.ACTION_DOWN) {
   1281                 if (mExpandedVisible) {
   1282                     animateCollapsePanels();
   1283                 }
   1284             }
   1285             return mStatusBarWindow.onTouchEvent(event);
   1286         };
   1287     }
   1288 
   1289     private void inflateShelf() {
   1290         mNotificationShelf =
   1291                 (NotificationShelf) LayoutInflater.from(mContext).inflate(
   1292                         R.layout.status_bar_notification_shelf, mStackScroller, false);
   1293         mNotificationShelf.setOnActivatedListener(this);
   1294         mStackScroller.setShelf(mNotificationShelf);
   1295         mNotificationShelf.setOnClickListener(mGoToLockedShadeListener);
   1296         mNotificationShelf.setStatusBarState(mState);
   1297     }
   1298 
   1299     public void onDensityOrFontScaleChanged() {
   1300         // start old BaseStatusBar.onDensityOrFontScaleChanged().
   1301         if (!KeyguardUpdateMonitor.getInstance(mContext).isSwitchingUser()) {
   1302             updateNotificationsOnDensityOrFontScaleChanged();
   1303         } else {
   1304             mReinflateNotificationsOnUserSwitched = true;
   1305         }
   1306         // end old BaseStatusBar.onDensityOrFontScaleChanged().
   1307         mScrimController.onDensityOrFontScaleChanged();
   1308         // TODO: Remove this.
   1309         if (mStatusBarView != null) mStatusBarView.onDensityOrFontScaleChanged();
   1310         if (mBrightnessMirrorController != null) {
   1311             mBrightnessMirrorController.onDensityOrFontScaleChanged();
   1312         }
   1313         mStatusBarKeyguardViewManager.onDensityOrFontScaleChanged();
   1314         // TODO: Bring these out of StatusBar.
   1315         ((UserInfoControllerImpl) Dependency.get(UserInfoController.class))
   1316                 .onDensityOrFontScaleChanged();
   1317         Dependency.get(UserSwitcherController.class).onDensityOrFontScaleChanged();
   1318         if (mKeyguardUserSwitcher != null) {
   1319             mKeyguardUserSwitcher.onDensityOrFontScaleChanged();
   1320         }
   1321         mNotificationIconAreaController.onDensityOrFontScaleChanged(mContext);
   1322 
   1323         reevaluateStyles();
   1324     }
   1325 
   1326     private void reinflateViews() {
   1327         reevaluateStyles();
   1328 
   1329         // Clock and bottom icons
   1330         mNotificationPanel.onOverlayChanged();
   1331         // The status bar on the keyguard is a special layout.
   1332         if (mKeyguardStatusBar != null) mKeyguardStatusBar.onOverlayChanged();
   1333         // Recreate Indication controller because internal references changed
   1334         mKeyguardIndicationController =
   1335                 SystemUIFactory.getInstance().createKeyguardIndicationController(mContext,
   1336                         mStatusBarWindow.findViewById(R.id.keyguard_indication_area),
   1337                         mNotificationPanel.getLockIcon());
   1338         mNotificationPanel.setKeyguardIndicationController(mKeyguardIndicationController);
   1339         mKeyguardIndicationController
   1340                 .setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
   1341         mKeyguardIndicationController.setVisible(mState == StatusBarState.KEYGUARD);
   1342         mKeyguardIndicationController.setDozing(mDozing);
   1343         if (mBrightnessMirrorController != null) {
   1344             mBrightnessMirrorController.onOverlayChanged();
   1345         }
   1346         if (mStatusBarKeyguardViewManager != null) {
   1347             mStatusBarKeyguardViewManager.onOverlayChanged();
   1348         }
   1349         if (mAmbientIndicationContainer instanceof AutoReinflateContainer) {
   1350             ((AutoReinflateContainer) mAmbientIndicationContainer).inflateLayout();
   1351         }
   1352     }
   1353 
   1354     protected void reevaluateStyles() {
   1355         inflateSignalClusters();
   1356         inflateDismissView();
   1357         updateClearAll();
   1358         inflateEmptyShadeView();
   1359         updateEmptyShadeView();
   1360     }
   1361 
   1362     private void updateNotificationsOnDensityOrFontScaleChanged() {
   1363         ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
   1364         for (int i = 0; i < activeNotifications.size(); i++) {
   1365             Entry entry = activeNotifications.get(i);
   1366             boolean exposedGuts = mNotificationGutsExposed != null
   1367                     && entry.row.getGuts() == mNotificationGutsExposed;
   1368             entry.row.onDensityOrFontScaleChanged();
   1369             if (exposedGuts) {
   1370                 mNotificationGutsExposed = entry.row.getGuts();
   1371                 bindGuts(entry.row, mGutsMenuItem);
   1372             }
   1373         }
   1374     }
   1375 
   1376     private void inflateSignalClusters() {
   1377         if (mKeyguardStatusBar != null) reinflateSignalCluster(mKeyguardStatusBar);
   1378     }
   1379 
   1380     public static SignalClusterView reinflateSignalCluster(View view) {
   1381         Context context = view.getContext();
   1382         SignalClusterView signalCluster =
   1383                 (SignalClusterView) view.findViewById(R.id.signal_cluster);
   1384         if (signalCluster != null) {
   1385             ViewParent parent = signalCluster.getParent();
   1386             if (parent instanceof ViewGroup) {
   1387                 ViewGroup viewParent = (ViewGroup) parent;
   1388                 int index = viewParent.indexOfChild(signalCluster);
   1389                 viewParent.removeView(signalCluster);
   1390                 SignalClusterView newCluster = (SignalClusterView) LayoutInflater.from(context)
   1391                         .inflate(R.layout.signal_cluster_view, viewParent, false);
   1392                 ViewGroup.MarginLayoutParams layoutParams =
   1393                         (ViewGroup.MarginLayoutParams) viewParent.getLayoutParams();
   1394                 layoutParams.setMarginsRelative(
   1395                         context.getResources().getDimensionPixelSize(
   1396                                 R.dimen.signal_cluster_margin_start),
   1397                         0, 0, 0);
   1398                 newCluster.setLayoutParams(layoutParams);
   1399                 viewParent.addView(newCluster, index);
   1400                 return newCluster;
   1401             }
   1402             return signalCluster;
   1403         }
   1404         return null;
   1405     }
   1406 
   1407     private void inflateEmptyShadeView() {
   1408         if (mStackScroller == null) {
   1409             return;
   1410         }
   1411         mEmptyShadeView = (EmptyShadeView) LayoutInflater.from(mContext).inflate(
   1412                 R.layout.status_bar_no_notifications, mStackScroller, false);
   1413         mStackScroller.setEmptyShadeView(mEmptyShadeView);
   1414     }
   1415 
   1416     private void inflateDismissView() {
   1417         if (!mClearAllEnabled || mStackScroller == null) {
   1418             return;
   1419         }
   1420 
   1421         mDismissView = (DismissView) LayoutInflater.from(mContext).inflate(
   1422                 R.layout.status_bar_notification_dismiss_all, mStackScroller, false);
   1423         mDismissView.setOnButtonClickListener(new View.OnClickListener() {
   1424             @Override
   1425             public void onClick(View v) {
   1426                 mMetricsLogger.action(MetricsEvent.ACTION_DISMISS_ALL_NOTES);
   1427                 clearAllNotifications();
   1428             }
   1429         });
   1430         mStackScroller.setDismissView(mDismissView);
   1431     }
   1432 
   1433     protected void createUserSwitcher() {
   1434         mKeyguardUserSwitcher = new KeyguardUserSwitcher(mContext,
   1435                 (ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_user_switcher),
   1436                 mKeyguardStatusBar, mNotificationPanel);
   1437     }
   1438 
   1439     protected void inflateStatusBarWindow(Context context) {
   1440         mStatusBarWindow = (StatusBarWindowView) View.inflate(context,
   1441                 R.layout.super_status_bar, null);
   1442     }
   1443 
   1444     public void clearAllNotifications() {
   1445 
   1446         // animate-swipe all dismissable notifications, then animate the shade closed
   1447         int numChildren = mStackScroller.getChildCount();
   1448 
   1449         final ArrayList<View> viewsToHide = new ArrayList<View>(numChildren);
   1450         final ArrayList<ExpandableNotificationRow> viewsToRemove = new ArrayList<>(numChildren);
   1451         for (int i = 0; i < numChildren; i++) {
   1452             final View child = mStackScroller.getChildAt(i);
   1453             if (child instanceof ExpandableNotificationRow) {
   1454                 ExpandableNotificationRow row = (ExpandableNotificationRow) child;
   1455                 boolean parentVisible = false;
   1456                 boolean hasClipBounds = child.getClipBounds(mTmpRect);
   1457                 if (mStackScroller.canChildBeDismissed(child)) {
   1458                     viewsToRemove.add(row);
   1459                     if (child.getVisibility() == View.VISIBLE
   1460                             && (!hasClipBounds || mTmpRect.height() > 0)) {
   1461                         viewsToHide.add(child);
   1462                         parentVisible = true;
   1463                     }
   1464                 } else if (child.getVisibility() == View.VISIBLE
   1465                         && (!hasClipBounds || mTmpRect.height() > 0)) {
   1466                     parentVisible = true;
   1467                 }
   1468                 List<ExpandableNotificationRow> children = row.getNotificationChildren();
   1469                 if (children != null) {
   1470                     for (ExpandableNotificationRow childRow : children) {
   1471                         viewsToRemove.add(childRow);
   1472                         if (parentVisible && row.areChildrenExpanded()
   1473                                 && mStackScroller.canChildBeDismissed(childRow)) {
   1474                             hasClipBounds = childRow.getClipBounds(mTmpRect);
   1475                             if (childRow.getVisibility() == View.VISIBLE
   1476                                     && (!hasClipBounds || mTmpRect.height() > 0)) {
   1477                                 viewsToHide.add(childRow);
   1478                             }
   1479                         }
   1480                     }
   1481                 }
   1482             }
   1483         }
   1484         if (viewsToRemove.isEmpty()) {
   1485             animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
   1486             return;
   1487         }
   1488 
   1489         addPostCollapseAction(new Runnable() {
   1490             @Override
   1491             public void run() {
   1492                 mStackScroller.setDismissAllInProgress(false);
   1493                 for (ExpandableNotificationRow rowToRemove : viewsToRemove) {
   1494                     if (mStackScroller.canChildBeDismissed(rowToRemove)) {
   1495                         removeNotification(rowToRemove.getEntry().key, null);
   1496                     } else {
   1497                         rowToRemove.resetTranslation();
   1498                     }
   1499                 }
   1500                 try {
   1501                     mBarService.onClearAllNotifications(mCurrentUserId);
   1502                 } catch (Exception ex) { }
   1503             }
   1504         });
   1505 
   1506         performDismissAllAnimations(viewsToHide);
   1507 
   1508     }
   1509 
   1510     private void performDismissAllAnimations(ArrayList<View> hideAnimatedList) {
   1511         Runnable animationFinishAction = new Runnable() {
   1512             @Override
   1513             public void run() {
   1514                 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
   1515             }
   1516         };
   1517 
   1518         // let's disable our normal animations
   1519         mStackScroller.setDismissAllInProgress(true);
   1520 
   1521         // Decrease the delay for every row we animate to give the sense of
   1522         // accelerating the swipes
   1523         int rowDelayDecrement = 10;
   1524         int currentDelay = 140;
   1525         int totalDelay = 180;
   1526         int numItems = hideAnimatedList.size();
   1527         for (int i = numItems - 1; i >= 0; i--) {
   1528             View view = hideAnimatedList.get(i);
   1529             Runnable endRunnable = null;
   1530             if (i == 0) {
   1531                 endRunnable = animationFinishAction;
   1532             }
   1533             mStackScroller.dismissViewAnimated(view, endRunnable, totalDelay, 260);
   1534             currentDelay = Math.max(50, currentDelay - rowDelayDecrement);
   1535             totalDelay += currentDelay;
   1536         }
   1537     }
   1538 
   1539     protected void setZenMode(int mode) {
   1540         // start old BaseStatusBar.setZenMode().
   1541         if (isDeviceProvisioned()) {
   1542             mZenMode = mode;
   1543             updateNotifications();
   1544         }
   1545         // end old BaseStatusBar.setZenMode().
   1546     }
   1547 
   1548     protected void startKeyguard() {
   1549         Trace.beginSection("StatusBar#startKeyguard");
   1550         KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class);
   1551         mFingerprintUnlockController = new FingerprintUnlockController(mContext,
   1552                 mDozeScrimController, keyguardViewMediator,
   1553                 mScrimController, this, UnlockMethodCache.getInstance(mContext));
   1554         mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this,
   1555                 getBouncerContainer(), mScrimController,
   1556                 mFingerprintUnlockController);
   1557         mKeyguardIndicationController
   1558                 .setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
   1559         mFingerprintUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
   1560         mRemoteInputController.addCallback(mStatusBarKeyguardViewManager);
   1561 
   1562         mRemoteInputController.addCallback(new RemoteInputController.Callback() {
   1563             @Override
   1564             public void onRemoteInputSent(Entry entry) {
   1565                 if (FORCE_REMOTE_INPUT_HISTORY && mKeysKeptForRemoteInput.contains(entry.key)) {
   1566                     removeNotification(entry.key, null);
   1567                 } else if (mRemoteInputEntriesToRemoveOnCollapse.contains(entry)) {
   1568                     // We're currently holding onto this notification, but from the apps point of
   1569                     // view it is already canceled, so we'll need to cancel it on the apps behalf
   1570                     // after sending - unless the app posts an update in the mean time, so wait a
   1571                     // bit.
   1572                     mHandler.postDelayed(() -> {
   1573                         if (mRemoteInputEntriesToRemoveOnCollapse.remove(entry)) {
   1574                             removeNotification(entry.key, null);
   1575                         }
   1576                     }, REMOTE_INPUT_KEPT_ENTRY_AUTO_CANCEL_DELAY);
   1577                 }
   1578             }
   1579         });
   1580 
   1581         mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback();
   1582         mLightBarController.setFingerprintUnlockController(mFingerprintUnlockController);
   1583         Trace.endSection();
   1584     }
   1585 
   1586     protected View getStatusBarView() {
   1587         return mStatusBarView;
   1588     }
   1589 
   1590     public StatusBarWindowView getStatusBarWindow() {
   1591         return mStatusBarWindow;
   1592     }
   1593 
   1594     protected ViewGroup getBouncerContainer() {
   1595         return mStatusBarWindow;
   1596     }
   1597 
   1598     public int getStatusBarHeight() {
   1599         if (mNaturalBarHeight < 0) {
   1600             final Resources res = mContext.getResources();
   1601             mNaturalBarHeight =
   1602                     res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
   1603         }
   1604         return mNaturalBarHeight;
   1605     }
   1606 
   1607     protected boolean toggleSplitScreenMode(int metricsDockAction, int metricsUndockAction) {
   1608         if (mRecents == null) {
   1609             return false;
   1610         }
   1611         int dockSide = WindowManagerProxy.getInstance().getDockSide();
   1612         if (dockSide == WindowManager.DOCKED_INVALID) {
   1613             return mRecents.dockTopTask(NavigationBarGestureHelper.DRAG_MODE_NONE,
   1614                     ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, null, metricsDockAction);
   1615         } else {
   1616             Divider divider = getComponent(Divider.class);
   1617             if (divider != null && divider.isMinimized() && !divider.isHomeStackResizable()) {
   1618                 // Undocking from the minimized state is not supported
   1619                 return false;
   1620             } else {
   1621                 EventBus.getDefault().send(new UndockingTaskEvent());
   1622                 if (metricsUndockAction != -1) {
   1623                     mMetricsLogger.action(metricsUndockAction);
   1624                 }
   1625             }
   1626         }
   1627         return true;
   1628     }
   1629 
   1630     void awakenDreams() {
   1631         SystemServicesProxy.getInstance(mContext).awakenDreamsAsync();
   1632     }
   1633 
   1634     public UserHandle getCurrentUserHandle() {
   1635         return new UserHandle(mCurrentUserId);
   1636     }
   1637 
   1638     public void addNotification(StatusBarNotification notification, RankingMap ranking)
   1639             throws InflationException {
   1640         String key = notification.getKey();
   1641         if (DEBUG) Log.d(TAG, "addNotification key=" + key);
   1642 
   1643         mNotificationData.updateRanking(ranking);
   1644         Entry shadeEntry = createNotificationViews(notification);
   1645         boolean isHeadsUped = shouldPeek(shadeEntry);
   1646         if (!isHeadsUped && notification.getNotification().fullScreenIntent != null) {
   1647             if (shouldSuppressFullScreenIntent(key)) {
   1648                 if (DEBUG) {
   1649                     Log.d(TAG, "No Fullscreen intent: suppressed by DND: " + key);
   1650                 }
   1651             } else if (mNotificationData.getImportance(key)
   1652                     < NotificationManager.IMPORTANCE_HIGH) {
   1653                 if (DEBUG) {
   1654                     Log.d(TAG, "No Fullscreen intent: not important enough: "
   1655                             + key);
   1656                 }
   1657             } else {
   1658                 // Stop screensaver if the notification has a full-screen intent.
   1659                 // (like an incoming phone call)
   1660                 awakenDreams();
   1661 
   1662                 // not immersive & a full-screen alert should be shown
   1663                 if (DEBUG)
   1664                     Log.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent");
   1665                 try {
   1666                     EventLog.writeEvent(EventLogTags.SYSUI_FULLSCREEN_NOTIFICATION,
   1667                             key);
   1668                     notification.getNotification().fullScreenIntent.send();
   1669                     shadeEntry.notifyFullScreenIntentLaunched();
   1670                     mMetricsLogger.count("note_fullscreen", 1);
   1671                 } catch (PendingIntent.CanceledException e) {
   1672                 }
   1673             }
   1674         }
   1675         abortExistingInflation(key);
   1676 
   1677         mForegroundServiceController.addNotification(notification,
   1678                 mNotificationData.getImportance(key));
   1679 
   1680         mPendingNotifications.put(key, shadeEntry);
   1681     }
   1682 
   1683     private void abortExistingInflation(String key) {
   1684         if (mPendingNotifications.containsKey(key)) {
   1685             Entry entry = mPendingNotifications.get(key);
   1686             entry.abortTask();
   1687             mPendingNotifications.remove(key);
   1688         }
   1689         Entry addedEntry = mNotificationData.get(key);
   1690         if (addedEntry != null) {
   1691             addedEntry.abortTask();
   1692         }
   1693     }
   1694 
   1695     private void addEntry(Entry shadeEntry) {
   1696         boolean isHeadsUped = shouldPeek(shadeEntry);
   1697         if (isHeadsUped) {
   1698             mHeadsUpManager.showNotification(shadeEntry);
   1699             // Mark as seen immediately
   1700             setNotificationShown(shadeEntry.notification);
   1701         }
   1702         addNotificationViews(shadeEntry);
   1703         // Recalculate the position of the sliding windows and the titles.
   1704         setAreThereNotifications();
   1705     }
   1706 
   1707     @Override
   1708     public void handleInflationException(StatusBarNotification notification, Exception e) {
   1709         handleNotificationError(notification, e.getMessage());
   1710     }
   1711 
   1712     @Override
   1713     public void onAsyncInflationFinished(Entry entry) {
   1714         mPendingNotifications.remove(entry.key);
   1715         // If there was an async task started after the removal, we don't want to add it back to
   1716         // the list, otherwise we might get leaks.
   1717         boolean isNew = mNotificationData.get(entry.key) == null;
   1718         if (isNew && !entry.row.isRemoved()) {
   1719             addEntry(entry);
   1720         } else if (!isNew && entry.row.hasLowPriorityStateUpdated()) {
   1721             mVisualStabilityManager.onLowPriorityUpdated(entry);
   1722             updateNotificationShade();
   1723         }
   1724         entry.row.setLowPriorityStateUpdated(false);
   1725     }
   1726 
   1727     private boolean shouldSuppressFullScreenIntent(String key) {
   1728         if (isDeviceInVrMode()) {
   1729             return true;
   1730         }
   1731 
   1732         if (mPowerManager.isInteractive()) {
   1733             return mNotificationData.shouldSuppressScreenOn(key);
   1734         } else {
   1735             return mNotificationData.shouldSuppressScreenOff(key);
   1736         }
   1737     }
   1738 
   1739     protected void updateNotificationRanking(RankingMap ranking) {
   1740         mNotificationData.updateRanking(ranking);
   1741         updateNotifications();
   1742     }
   1743 
   1744     public void removeNotification(String key, RankingMap ranking) {
   1745         boolean deferRemoval = false;
   1746         abortExistingInflation(key);
   1747         if (mHeadsUpManager.isHeadsUp(key)) {
   1748             // A cancel() in repsonse to a remote input shouldn't be delayed, as it makes the
   1749             // sending look longer than it takes.
   1750             // Also we should not defer the removal if reordering isn't allowed since otherwise
   1751             // some notifications can't disappear before the panel is closed.
   1752             boolean ignoreEarliestRemovalTime = mRemoteInputController.isSpinning(key)
   1753                     && !FORCE_REMOTE_INPUT_HISTORY
   1754                     || !mVisualStabilityManager.isReorderingAllowed();
   1755             deferRemoval = !mHeadsUpManager.removeNotification(key,  ignoreEarliestRemovalTime);
   1756         }
   1757         if (key.equals(mMediaNotificationKey)) {
   1758             clearCurrentMediaNotification();
   1759             updateMediaMetaData(true, true);
   1760         }
   1761         if (FORCE_REMOTE_INPUT_HISTORY && mRemoteInputController.isSpinning(key)) {
   1762             Entry entry = mNotificationData.get(key);
   1763             StatusBarNotification sbn = entry.notification;
   1764 
   1765             Notification.Builder b = Notification.Builder
   1766                     .recoverBuilder(mContext, sbn.getNotification().clone());
   1767             CharSequence[] oldHistory = sbn.getNotification().extras
   1768                     .getCharSequenceArray(Notification.EXTRA_REMOTE_INPUT_HISTORY);
   1769             CharSequence[] newHistory;
   1770             if (oldHistory == null) {
   1771                 newHistory = new CharSequence[1];
   1772             } else {
   1773                 newHistory = new CharSequence[oldHistory.length + 1];
   1774                 for (int i = 0; i < oldHistory.length; i++) {
   1775                     newHistory[i + 1] = oldHistory[i];
   1776                 }
   1777             }
   1778             newHistory[0] = String.valueOf(entry.remoteInputText);
   1779             b.setRemoteInputHistory(newHistory);
   1780 
   1781             Notification newNotification = b.build();
   1782 
   1783             // Undo any compatibility view inflation
   1784             newNotification.contentView = sbn.getNotification().contentView;
   1785             newNotification.bigContentView = sbn.getNotification().bigContentView;
   1786             newNotification.headsUpContentView = sbn.getNotification().headsUpContentView;
   1787 
   1788             StatusBarNotification newSbn = new StatusBarNotification(sbn.getPackageName(),
   1789                     sbn.getOpPkg(),
   1790                     sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
   1791                     newNotification, sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime());
   1792             boolean updated = false;
   1793             try {
   1794                 updateNotification(newSbn, null);
   1795                 updated = true;
   1796             } catch (InflationException e) {
   1797                 deferRemoval = false;
   1798             }
   1799             if (updated) {
   1800                 mKeysKeptForRemoteInput.add(entry.key);
   1801                 return;
   1802             }
   1803         }
   1804         if (deferRemoval) {
   1805             mLatestRankingMap = ranking;
   1806             mHeadsUpEntriesToRemoveOnSwitch.add(mHeadsUpManager.getEntry(key));
   1807             return;
   1808         }
   1809         Entry entry = mNotificationData.get(key);
   1810 
   1811         if (entry != null && mRemoteInputController.isRemoteInputActive(entry)
   1812                 && (entry.row != null && !entry.row.isDismissed())) {
   1813             mLatestRankingMap = ranking;
   1814             mRemoteInputEntriesToRemoveOnCollapse.add(entry);
   1815             return;
   1816         }
   1817         if (entry != null && mNotificationGutsExposed != null
   1818                 && mNotificationGutsExposed == entry.row.getGuts() && entry.row.getGuts() != null
   1819                 && !entry.row.getGuts().isLeavebehind()) {
   1820             Log.w(TAG, "Keeping notification because it's showing guts. " + key);
   1821             mLatestRankingMap = ranking;
   1822             mKeyToRemoveOnGutsClosed = key;
   1823             return;
   1824         }
   1825 
   1826         if (entry != null) {
   1827             mForegroundServiceController.removeNotification(entry.notification);
   1828         }
   1829 
   1830         if (entry != null && entry.row != null) {
   1831             entry.row.setRemoved();
   1832             mStackScroller.cleanUpViewState(entry.row);
   1833         }
   1834         // Let's remove the children if this was a summary
   1835         handleGroupSummaryRemoved(key, ranking);
   1836         StatusBarNotification old = removeNotificationViews(key, ranking);
   1837         if (SPEW) Log.d(TAG, "removeNotification key=" + key + " old=" + old);
   1838 
   1839         if (old != null) {
   1840             if (CLOSE_PANEL_WHEN_EMPTIED && !hasActiveNotifications()
   1841                     && !mNotificationPanel.isTracking() && !mNotificationPanel.isQsExpanded()) {
   1842                 if (mState == StatusBarState.SHADE) {
   1843                     animateCollapsePanels();
   1844                 } else if (mState == StatusBarState.SHADE_LOCKED && !isCollapsing()) {
   1845                     goToKeyguard();
   1846                 }
   1847             }
   1848         }
   1849         setAreThereNotifications();
   1850     }
   1851 
   1852     /**
   1853      * Ensures that the group children are cancelled immediately when the group summary is cancelled
   1854      * instead of waiting for the notification manager to send all cancels. Otherwise this could
   1855      * lead to flickers.
   1856      *
   1857      * This also ensures that the animation looks nice and only consists of a single disappear
   1858      * animation instead of multiple.
   1859      *
   1860      * @param key the key of the notification was removed
   1861      * @param ranking the current ranking
   1862      */
   1863     private void handleGroupSummaryRemoved(String key,
   1864             RankingMap ranking) {
   1865         Entry entry = mNotificationData.get(key);
   1866         if (entry != null && entry.row != null
   1867                 && entry.row.isSummaryWithChildren()) {
   1868             if (entry.notification.getOverrideGroupKey() != null && !entry.row.isDismissed()) {
   1869                 // We don't want to remove children for autobundled notifications as they are not
   1870                 // always cancelled. We only remove them if they were dismissed by the user.
   1871                 return;
   1872             }
   1873             List<ExpandableNotificationRow> notificationChildren =
   1874                     entry.row.getNotificationChildren();
   1875             ArrayList<ExpandableNotificationRow> toRemove = new ArrayList<>();
   1876             for (int i = 0; i < notificationChildren.size(); i++) {
   1877                 ExpandableNotificationRow row = notificationChildren.get(i);
   1878                 if ((row.getStatusBarNotification().getNotification().flags
   1879                         & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
   1880                     // the child is a forground service notification which we can't remove!
   1881                     continue;
   1882                 }
   1883                 toRemove.add(row);
   1884                 row.setKeepInParent(true);
   1885                 // we need to set this state earlier as otherwise we might generate some weird
   1886                 // animations
   1887                 row.setRemoved();
   1888             }
   1889         }
   1890     }
   1891 
   1892     protected void performRemoveNotification(StatusBarNotification n) {
   1893         Entry entry = mNotificationData.get(n.getKey());
   1894         if (mRemoteInputController.isRemoteInputActive(entry)) {
   1895             mRemoteInputController.removeRemoteInput(entry, null);
   1896         }
   1897         // start old BaseStatusBar.performRemoveNotification.
   1898         final String pkg = n.getPackageName();
   1899         final String tag = n.getTag();
   1900         final int id = n.getId();
   1901         final int userId = n.getUserId();
   1902         try {
   1903             mBarService.onNotificationClear(pkg, tag, id, userId);
   1904             if (FORCE_REMOTE_INPUT_HISTORY
   1905                     && mKeysKeptForRemoteInput.contains(n.getKey())) {
   1906                 mKeysKeptForRemoteInput.remove(n.getKey());
   1907             }
   1908             removeNotification(n.getKey(), null);
   1909 
   1910         } catch (RemoteException ex) {
   1911             // system process is dead if we're here.
   1912         }
   1913         if (mStackScroller.hasPulsingNotifications() && mHeadsUpManager.getAllEntries().isEmpty()) {
   1914             // We were showing a pulse for a notification, but no notifications are pulsing anymore.
   1915             // Finish the pulse.
   1916             mDozeScrimController.pulseOutNow();
   1917         }
   1918         // end old BaseStatusBar.performRemoveNotification.
   1919     }
   1920 
   1921     private void updateNotificationShade() {
   1922         if (mStackScroller == null) return;
   1923 
   1924         // Do not modify the notifications during collapse.
   1925         if (isCollapsing()) {
   1926             addPostCollapseAction(new Runnable() {
   1927                 @Override
   1928                 public void run() {
   1929                     updateNotificationShade();
   1930                 }
   1931             });
   1932             return;
   1933         }
   1934 
   1935         ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
   1936         ArrayList<ExpandableNotificationRow> toShow = new ArrayList<>(activeNotifications.size());
   1937         final int N = activeNotifications.size();
   1938         for (int i=0; i<N; i++) {
   1939             Entry ent = activeNotifications.get(i);
   1940             if (ent.row.isDismissed() || ent.row.isRemoved()) {
   1941                 // we don't want to update removed notifications because they could
   1942                 // temporarily become children if they were isolated before.
   1943                 continue;
   1944             }
   1945             int userId = ent.notification.getUserId();
   1946 
   1947             // Display public version of the notification if we need to redact.
   1948             boolean devicePublic = isLockscreenPublicMode(mCurrentUserId);
   1949             boolean userPublic = devicePublic || isLockscreenPublicMode(userId);
   1950             boolean needsRedaction = needsRedaction(ent);
   1951             boolean sensitive = userPublic && needsRedaction;
   1952             boolean deviceSensitive = devicePublic
   1953                     && !userAllowsPrivateNotificationsInPublic(mCurrentUserId);
   1954             ent.row.setSensitive(sensitive, deviceSensitive);
   1955             ent.row.setNeedsRedaction(needsRedaction);
   1956             if (mGroupManager.isChildInGroupWithSummary(ent.row.getStatusBarNotification())) {
   1957                 ExpandableNotificationRow summary = mGroupManager.getGroupSummary(
   1958                         ent.row.getStatusBarNotification());
   1959                 List<ExpandableNotificationRow> orderedChildren =
   1960                         mTmpChildOrderMap.get(summary);
   1961                 if (orderedChildren == null) {
   1962                     orderedChildren = new ArrayList<>();
   1963                     mTmpChildOrderMap.put(summary, orderedChildren);
   1964                 }
   1965                 orderedChildren.add(ent.row);
   1966             } else {
   1967                 toShow.add(ent.row);
   1968             }
   1969 
   1970         }
   1971 
   1972         ArrayList<ExpandableNotificationRow> toRemove = new ArrayList<>();
   1973         for (int i=0; i< mStackScroller.getChildCount(); i++) {
   1974             View child = mStackScroller.getChildAt(i);
   1975             if (!toShow.contains(child) && child instanceof ExpandableNotificationRow) {
   1976                 toRemove.add((ExpandableNotificationRow) child);
   1977             }
   1978         }
   1979 
   1980         for (ExpandableNotificationRow remove : toRemove) {
   1981             if (mGroupManager.isChildInGroupWithSummary(remove.getStatusBarNotification())) {
   1982                 // we are only transfering this notification to its parent, don't generate an animation
   1983                 mStackScroller.setChildTransferInProgress(true);
   1984             }
   1985             if (remove.isSummaryWithChildren()) {
   1986                 remove.removeAllChildren();
   1987             }
   1988             mStackScroller.removeView(remove);
   1989             mStackScroller.setChildTransferInProgress(false);
   1990         }
   1991 
   1992         removeNotificationChildren();
   1993 
   1994         for (int i=0; i<toShow.size(); i++) {
   1995             View v = toShow.get(i);
   1996             if (v.getParent() == null) {
   1997                 mVisualStabilityManager.notifyViewAddition(v);
   1998                 mStackScroller.addView(v);
   1999             }
   2000         }
   2001 
   2002         addNotificationChildrenAndSort();
   2003 
   2004         // So after all this work notifications still aren't sorted correctly.
   2005         // Let's do that now by advancing through toShow and mStackScroller in
   2006         // lock-step, making sure mStackScroller matches what we see in toShow.
   2007         int j = 0;
   2008         for (int i = 0; i < mStackScroller.getChildCount(); i++) {
   2009             View child = mStackScroller.getChildAt(i);
   2010             if (!(child instanceof ExpandableNotificationRow)) {
   2011                 // We don't care about non-notification views.
   2012                 continue;
   2013             }
   2014 
   2015             ExpandableNotificationRow targetChild = toShow.get(j);
   2016             if (child != targetChild) {
   2017                 // Oops, wrong notification at this position. Put the right one
   2018                 // here and advance both lists.
   2019                 if (mVisualStabilityManager.canReorderNotification(targetChild)) {
   2020                     mStackScroller.changeViewPosition(targetChild, i);
   2021                 } else {
   2022                     mVisualStabilityManager.addReorderingAllowedCallback(this);
   2023                 }
   2024             }
   2025             j++;
   2026 
   2027         }
   2028 
   2029         mVisualStabilityManager.onReorderingFinished();
   2030         // clear the map again for the next usage
   2031         mTmpChildOrderMap.clear();
   2032 
   2033         updateRowStates();
   2034         updateSpeedBumpIndex();
   2035         updateClearAll();
   2036         updateEmptyShadeView();
   2037 
   2038         updateQsExpansionEnabled();
   2039 
   2040         // Let's also update the icons
   2041         mNotificationIconAreaController.updateNotificationIcons(mNotificationData);
   2042     }
   2043 
   2044     /** @return true if the entry needs redaction when on the lockscreen. */
   2045     private boolean needsRedaction(Entry ent) {
   2046         int userId = ent.notification.getUserId();
   2047 
   2048         boolean currentUserWantsRedaction = !userAllowsPrivateNotificationsInPublic(mCurrentUserId);
   2049         boolean notiUserWantsRedaction = !userAllowsPrivateNotificationsInPublic(userId);
   2050         boolean redactedLockscreen = currentUserWantsRedaction || notiUserWantsRedaction;
   2051 
   2052         boolean notificationRequestsRedaction =
   2053                 ent.notification.getNotification().visibility == Notification.VISIBILITY_PRIVATE;
   2054         boolean userForcesRedaction = packageHasVisibilityOverride(ent.notification.getKey());
   2055 
   2056         return userForcesRedaction || notificationRequestsRedaction && redactedLockscreen;
   2057     }
   2058 
   2059     /**
   2060      * Disable QS if device not provisioned.
   2061      * If the user switcher is simple then disable QS during setup because
   2062      * the user intends to use the lock screen user switcher, QS in not needed.
   2063      */
   2064     private void updateQsExpansionEnabled() {
   2065         mNotificationPanel.setQsExpansionEnabled(isDeviceProvisioned()
   2066                 && (mUserSetup || mUserSwitcherController == null
   2067                         || !mUserSwitcherController.isSimpleUserSwitcher())
   2068                 && ((mDisabled2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) == 0)
   2069                 && !mDozing
   2070                 && !ONLY_CORE_APPS);
   2071     }
   2072 
   2073     private void addNotificationChildrenAndSort() {
   2074         // Let's now add all notification children which are missing
   2075         boolean orderChanged = false;
   2076         for (int i = 0; i < mStackScroller.getChildCount(); i++) {
   2077             View view = mStackScroller.getChildAt(i);
   2078             if (!(view instanceof ExpandableNotificationRow)) {
   2079                 // We don't care about non-notification views.
   2080                 continue;
   2081             }
   2082 
   2083             ExpandableNotificationRow parent = (ExpandableNotificationRow) view;
   2084             List<ExpandableNotificationRow> children = parent.getNotificationChildren();
   2085             List<ExpandableNotificationRow> orderedChildren = mTmpChildOrderMap.get(parent);
   2086 
   2087             for (int childIndex = 0; orderedChildren != null && childIndex < orderedChildren.size();
   2088                     childIndex++) {
   2089                 ExpandableNotificationRow childView = orderedChildren.get(childIndex);
   2090                 if (children == null || !children.contains(childView)) {
   2091                     if (childView.getParent() != null) {
   2092                         Log.wtf(TAG, "trying to add a notification child that already has " +
   2093                                 "a parent. class:" + childView.getParent().getClass() +
   2094                                 "\n child: " + childView);
   2095                         // This shouldn't happen. We can recover by removing it though.
   2096                         ((ViewGroup) childView.getParent()).removeView(childView);
   2097                     }
   2098                     mVisualStabilityManager.notifyViewAddition(childView);
   2099                     parent.addChildNotification(childView, childIndex);
   2100                     mStackScroller.notifyGroupChildAdded(childView);
   2101                 }
   2102             }
   2103 
   2104             // Finally after removing and adding has been beformed we can apply the order.
   2105             orderChanged |= parent.applyChildOrder(orderedChildren, mVisualStabilityManager, this);
   2106         }
   2107         if (orderChanged) {
   2108             mStackScroller.generateChildOrderChangedEvent();
   2109         }
   2110     }
   2111 
   2112     private void removeNotificationChildren() {
   2113         // First let's remove all children which don't belong in the parents
   2114         ArrayList<ExpandableNotificationRow> toRemove = new ArrayList<>();
   2115         for (int i = 0; i < mStackScroller.getChildCount(); i++) {
   2116             View view = mStackScroller.getChildAt(i);
   2117             if (!(view instanceof ExpandableNotificationRow)) {
   2118                 // We don't care about non-notification views.
   2119                 continue;
   2120             }
   2121 
   2122             ExpandableNotificationRow parent = (ExpandableNotificationRow) view;
   2123             List<ExpandableNotificationRow> children = parent.getNotificationChildren();
   2124             List<ExpandableNotificationRow> orderedChildren = mTmpChildOrderMap.get(parent);
   2125 
   2126             if (children != null) {
   2127                 toRemove.clear();
   2128                 for (ExpandableNotificationRow childRow : children) {
   2129                     if ((orderedChildren == null
   2130                             || !orderedChildren.contains(childRow))
   2131                             && !childRow.keepInParent()) {
   2132                         toRemove.add(childRow);
   2133                     }
   2134                 }
   2135                 for (ExpandableNotificationRow remove : toRemove) {
   2136                     parent.removeChildNotification(remove);
   2137                     if (mNotificationData.get(remove.getStatusBarNotification().getKey()) == null) {
   2138                         // We only want to add an animation if the view is completely removed
   2139                         // otherwise it's just a transfer
   2140                         mStackScroller.notifyGroupChildRemoved(remove,
   2141                                 parent.getChildrenContainer());
   2142                     }
   2143                 }
   2144             }
   2145         }
   2146     }
   2147 
   2148     public void addQsTile(ComponentName tile) {
   2149         mQSPanel.getHost().addTile(tile);
   2150     }
   2151 
   2152     public void remQsTile(ComponentName tile) {
   2153         mQSPanel.getHost().removeTile(tile);
   2154     }
   2155 
   2156     public void clickTile(ComponentName tile) {
   2157         mQSPanel.clickTile(tile);
   2158     }
   2159 
   2160     private boolean packageHasVisibilityOverride(String key) {
   2161         return mNotificationData.getVisibilityOverride(key) == Notification.VISIBILITY_PRIVATE;
   2162     }
   2163 
   2164     private void updateClearAll() {
   2165         if (!mClearAllEnabled) {
   2166             return;
   2167         }
   2168         boolean showDismissView = mState != StatusBarState.KEYGUARD
   2169                 && hasActiveClearableNotifications();
   2170         mStackScroller.updateDismissView(showDismissView);
   2171     }
   2172 
   2173     /**
   2174      * Return whether there are any clearable notifications
   2175      */
   2176     private boolean hasActiveClearableNotifications() {
   2177         int childCount = mStackScroller.getChildCount();
   2178         for (int i = 0; i < childCount; i++) {
   2179             View child = mStackScroller.getChildAt(i);
   2180             if (!(child instanceof ExpandableNotificationRow)) {
   2181                 continue;
   2182             }
   2183             if (((ExpandableNotificationRow) child).canViewBeDismissed()) {
   2184                     return true;
   2185             }
   2186         }
   2187         return false;
   2188     }
   2189 
   2190     private void updateEmptyShadeView() {
   2191         boolean showEmptyShadeView =
   2192                 mState != StatusBarState.KEYGUARD &&
   2193                         mNotificationData.getActiveNotifications().size() == 0;
   2194         mNotificationPanel.showEmptyShadeView(showEmptyShadeView);
   2195     }
   2196 
   2197     private void updateSpeedBumpIndex() {
   2198         int speedBumpIndex = 0;
   2199         int currentIndex = 0;
   2200         final int N = mStackScroller.getChildCount();
   2201         for (int i = 0; i < N; i++) {
   2202             View view = mStackScroller.getChildAt(i);
   2203             if (view.getVisibility() == View.GONE || !(view instanceof ExpandableNotificationRow)) {
   2204                 continue;
   2205             }
   2206             ExpandableNotificationRow row = (ExpandableNotificationRow) view;
   2207             currentIndex++;
   2208             if (!mNotificationData.isAmbient(row.getStatusBarNotification().getKey())) {
   2209                 speedBumpIndex = currentIndex;
   2210             }
   2211         }
   2212         boolean noAmbient = speedBumpIndex == N;
   2213         mStackScroller.updateSpeedBumpIndex(speedBumpIndex, noAmbient);
   2214     }
   2215 
   2216     public static boolean isTopLevelChild(Entry entry) {
   2217         return entry.row.getParent() instanceof NotificationStackScrollLayout;
   2218     }
   2219 
   2220     protected void updateNotifications() {
   2221         mNotificationData.filterAndSort();
   2222 
   2223         updateNotificationShade();
   2224     }
   2225 
   2226     public void requestNotificationUpdate() {
   2227         updateNotifications();
   2228     }
   2229 
   2230     protected void setAreThereNotifications() {
   2231 
   2232         if (SPEW) {
   2233             final boolean clearable = hasActiveNotifications() &&
   2234                     hasActiveClearableNotifications();
   2235             Log.d(TAG, "setAreThereNotifications: N=" +
   2236                     mNotificationData.getActiveNotifications().size() + " any=" +
   2237                     hasActiveNotifications() + " clearable=" + clearable);
   2238         }
   2239 
   2240         if (mStatusBarView != null) {
   2241             final View nlo = mStatusBarView.findViewById(R.id.notification_lights_out);
   2242             final boolean showDot = hasActiveNotifications() && !areLightsOn();
   2243             if (showDot != (nlo.getAlpha() == 1.0f)) {
   2244                 if (showDot) {
   2245                     nlo.setAlpha(0f);
   2246                     nlo.setVisibility(View.VISIBLE);
   2247                 }
   2248                 nlo.animate()
   2249                         .alpha(showDot ? 1 : 0)
   2250                         .setDuration(showDot ? 750 : 250)
   2251                         .setInterpolator(new AccelerateInterpolator(2.0f))
   2252                         .setListener(showDot ? null : new AnimatorListenerAdapter() {
   2253                             @Override
   2254                             public void onAnimationEnd(Animator _a) {
   2255                                 nlo.setVisibility(View.GONE);
   2256                             }
   2257                         })
   2258                         .start();
   2259             }
   2260         }
   2261 
   2262         findAndUpdateMediaNotifications();
   2263     }
   2264 
   2265     public void findAndUpdateMediaNotifications() {
   2266         boolean metaDataChanged = false;
   2267 
   2268         synchronized (mNotificationData) {
   2269             ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
   2270             final int N = activeNotifications.size();
   2271 
   2272             // Promote the media notification with a controller in 'playing' state, if any.
   2273             Entry mediaNotification = null;
   2274             MediaController controller = null;
   2275             for (int i = 0; i < N; i++) {
   2276                 final Entry entry = activeNotifications.get(i);
   2277                 if (isMediaNotification(entry)) {
   2278                     final MediaSession.Token token =
   2279                             entry.notification.getNotification().extras
   2280                             .getParcelable(Notification.EXTRA_MEDIA_SESSION);
   2281                     if (token != null) {
   2282                         MediaController aController = new MediaController(mContext, token);
   2283                         if (PlaybackState.STATE_PLAYING ==
   2284                                 getMediaControllerPlaybackState(aController)) {
   2285                             if (DEBUG_MEDIA) {
   2286                                 Log.v(TAG, "DEBUG_MEDIA: found mediastyle controller matching "
   2287                                         + entry.notification.getKey());
   2288                             }
   2289                             mediaNotification = entry;
   2290                             controller = aController;
   2291                             break;
   2292                         }
   2293                     }
   2294                 }
   2295             }
   2296             if (mediaNotification == null) {
   2297                 // Still nothing? OK, let's just look for live media sessions and see if they match
   2298                 // one of our notifications. This will catch apps that aren't (yet!) using media
   2299                 // notifications.
   2300 
   2301                 if (mMediaSessionManager != null) {
   2302                     final List<MediaController> sessions
   2303                             = mMediaSessionManager.getActiveSessionsForUser(
   2304                                     null,
   2305                                     UserHandle.USER_ALL);
   2306 
   2307                     for (MediaController aController : sessions) {
   2308                         if (PlaybackState.STATE_PLAYING ==
   2309                                 getMediaControllerPlaybackState(aController)) {
   2310                             // now to see if we have one like this
   2311                             final String pkg = aController.getPackageName();
   2312 
   2313                             for (int i = 0; i < N; i++) {
   2314                                 final Entry entry = activeNotifications.get(i);
   2315                                 if (entry.notification.getPackageName().equals(pkg)) {
   2316                                     if (DEBUG_MEDIA) {
   2317                                         Log.v(TAG, "DEBUG_MEDIA: found controller matching "
   2318                                             + entry.notification.getKey());
   2319                                     }
   2320                                     controller = aController;
   2321                                     mediaNotification = entry;
   2322                                     break;
   2323                                 }
   2324                             }
   2325                         }
   2326                     }
   2327                 }
   2328             }
   2329 
   2330             if (controller != null && !sameSessions(mMediaController, controller)) {
   2331                 // We have a new media session
   2332                 clearCurrentMediaNotification();
   2333                 mMediaController = controller;
   2334                 mMediaController.registerCallback(mMediaListener);
   2335                 mMediaMetadata = mMediaController.getMetadata();
   2336                 if (DEBUG_MEDIA) {
   2337                     Log.v(TAG, "DEBUG_MEDIA: insert listener, receive metadata: "
   2338                             + mMediaMetadata);
   2339                 }
   2340 
   2341                 if (mediaNotification != null) {
   2342                     mMediaNotificationKey = mediaNotification.notification.getKey();
   2343                     if (DEBUG_MEDIA) {
   2344                         Log.v(TAG, "DEBUG_MEDIA: Found new media notification: key="
   2345                                 + mMediaNotificationKey + " controller=" + mMediaController);
   2346                     }
   2347                 }
   2348                 metaDataChanged = true;
   2349             }
   2350         }
   2351 
   2352         if (metaDataChanged) {
   2353             updateNotifications();
   2354         }
   2355         updateMediaMetaData(metaDataChanged, true);
   2356     }
   2357 
   2358     private int getMediaControllerPlaybackState(MediaController controller) {
   2359         if (controller != null) {
   2360             final PlaybackState playbackState = controller.getPlaybackState();
   2361             if (playbackState != null) {
   2362                 return playbackState.getState();
   2363             }
   2364         }
   2365         return PlaybackState.STATE_NONE;
   2366     }
   2367 
   2368     private boolean isPlaybackActive(int state) {
   2369         if (state != PlaybackState.STATE_STOPPED
   2370                 && state != PlaybackState.STATE_ERROR
   2371                 && state != PlaybackState.STATE_NONE) {
   2372             return true;
   2373         }
   2374         return false;
   2375     }
   2376 
   2377     private void clearCurrentMediaNotification() {
   2378         mMediaNotificationKey = null;
   2379         mMediaMetadata = null;
   2380         if (mMediaController != null) {
   2381             if (DEBUG_MEDIA) {
   2382                 Log.v(TAG, "DEBUG_MEDIA: Disconnecting from old controller: "
   2383                         + mMediaController.getPackageName());
   2384             }
   2385             mMediaController.unregisterCallback(mMediaListener);
   2386         }
   2387         mMediaController = null;
   2388     }
   2389 
   2390     private boolean sameSessions(MediaController a, MediaController b) {
   2391         if (a == b) return true;
   2392         if (a == null) return false;
   2393         return a.controlsSameSession(b);
   2394     }
   2395 
   2396     /**
   2397      * Hide the album artwork that is fading out and release its bitmap.
   2398      */
   2399     protected Runnable mHideBackdropFront = new Runnable() {
   2400         @Override
   2401         public void run() {
   2402             if (DEBUG_MEDIA) {
   2403                 Log.v(TAG, "DEBUG_MEDIA: removing fade layer");
   2404             }
   2405             mBackdropFront.setVisibility(View.INVISIBLE);
   2406             mBackdropFront.animate().cancel();
   2407             mBackdropFront.setImageDrawable(null);
   2408         }
   2409     };
   2410 
   2411     /**
   2412      * Refresh or remove lockscreen artwork from media metadata or the lockscreen wallpaper.
   2413      */
   2414     public void updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation) {
   2415         Trace.beginSection("StatusBar#updateMediaMetaData");
   2416         if (!SHOW_LOCKSCREEN_MEDIA_ARTWORK) {
   2417             Trace.endSection();
   2418             return;
   2419         }
   2420 
   2421         if (mBackdrop == null) {
   2422             Trace.endSection();
   2423             return; // called too early
   2424         }
   2425 
   2426         if (mLaunchTransitionFadingAway) {
   2427             mBackdrop.setVisibility(View.INVISIBLE);
   2428             Trace.endSection();
   2429             return;
   2430         }
   2431 
   2432         if (DEBUG_MEDIA) {
   2433             Log.v(TAG, "DEBUG_MEDIA: updating album art for notification " + mMediaNotificationKey
   2434                     + " metadata=" + mMediaMetadata
   2435                     + " metaDataChanged=" + metaDataChanged
   2436                     + " state=" + mState);
   2437         }
   2438 
   2439         Drawable artworkDrawable = null;
   2440         if (mMediaMetadata != null) {
   2441             Bitmap artworkBitmap = null;
   2442             artworkBitmap = mMediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ART);
   2443             if (artworkBitmap == null) {
   2444                 artworkBitmap = mMediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
   2445                 // might still be null
   2446             }
   2447             if (artworkBitmap != null) {
   2448                 artworkDrawable = new BitmapDrawable(mBackdropBack.getResources(), artworkBitmap);
   2449             }
   2450         }
   2451         boolean allowWhenShade = false;
   2452         if (ENABLE_LOCKSCREEN_WALLPAPER && artworkDrawable == null) {
   2453             Bitmap lockWallpaper = mLockscreenWallpaper.getBitmap();
   2454             if (lockWallpaper != null) {
   2455                 artworkDrawable = new LockscreenWallpaper.WallpaperDrawable(
   2456                         mBackdropBack.getResources(), lockWallpaper);
   2457                 // We're in the SHADE mode on the SIM screen - yet we still need to show
   2458                 // the lockscreen wallpaper in that mode.
   2459                 allowWhenShade = mStatusBarKeyguardViewManager != null
   2460                         && mStatusBarKeyguardViewManager.isShowing();
   2461             }
   2462         }
   2463 
   2464         boolean hideBecauseOccluded = mStatusBarKeyguardViewManager != null
   2465                 && mStatusBarKeyguardViewManager.isOccluded();
   2466 
   2467         final boolean hasArtwork = artworkDrawable != null;
   2468 
   2469         if ((hasArtwork || DEBUG_MEDIA_FAKE_ARTWORK)
   2470                 && (mState != StatusBarState.SHADE || allowWhenShade)
   2471                 && mFingerprintUnlockController.getMode()
   2472                         != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
   2473                 && !hideBecauseOccluded) {
   2474             // time to show some art!
   2475             if (mBackdrop.getVisibility() != View.VISIBLE) {
   2476                 mBackdrop.setVisibility(View.VISIBLE);
   2477                 if (allowEnterAnimation) {
   2478                     mBackdrop.setAlpha(SRC_MIN_ALPHA);
   2479                     mBackdrop.animate().alpha(1f);
   2480                 } else {
   2481                     mBackdrop.animate().cancel();
   2482                     mBackdrop.setAlpha(1f);
   2483                 }
   2484                 mStatusBarWindowManager.setBackdropShowing(true);
   2485                 metaDataChanged = true;
   2486                 if (DEBUG_MEDIA) {
   2487                     Log.v(TAG, "DEBUG_MEDIA: Fading in album artwork");
   2488                 }
   2489             }
   2490             if (metaDataChanged) {
   2491                 if (mBackdropBack.getDrawable() != null) {
   2492                     Drawable drawable =
   2493                             mBackdropBack.getDrawable().getConstantState()
   2494                                     .newDrawable(mBackdropFront.getResources()).mutate();
   2495                     mBackdropFront.setImageDrawable(drawable);
   2496                     if (mScrimSrcModeEnabled) {
   2497                         mBackdropFront.getDrawable().mutate().setXfermode(mSrcOverXferMode);
   2498                     }
   2499                     mBackdropFront.setAlpha(1f);
   2500                     mBackdropFront.setVisibility(View.VISIBLE);
   2501                 } else {
   2502                     mBackdropFront.setVisibility(View.INVISIBLE);
   2503                 }
   2504 
   2505                 if (DEBUG_MEDIA_FAKE_ARTWORK) {
   2506                     final int c = 0xFF000000 | (int)(Math.random() * 0xFFFFFF);
   2507                     Log.v(TAG, String.format("DEBUG_MEDIA: setting new color: 0x%08x", c));
   2508                     mBackdropBack.setBackgroundColor(0xFFFFFFFF);
   2509                     mBackdropBack.setImageDrawable(new ColorDrawable(c));
   2510                 } else {
   2511                     mBackdropBack.setImageDrawable(artworkDrawable);
   2512                 }
   2513                 if (mScrimSrcModeEnabled) {
   2514                     mBackdropBack.getDrawable().mutate().setXfermode(mSrcXferMode);
   2515                 }
   2516 
   2517                 if (mBackdropFront.getVisibility() == View.VISIBLE) {
   2518                     if (DEBUG_MEDIA) {
   2519                         Log.v(TAG, "DEBUG_MEDIA: Crossfading album artwork from "
   2520                                 + mBackdropFront.getDrawable()
   2521                                 + " to "
   2522                                 + mBackdropBack.getDrawable());
   2523                     }
   2524                     mBackdropFront.animate()
   2525                             .setDuration(250)
   2526                             .alpha(0f).withEndAction(mHideBackdropFront);
   2527                 }
   2528             }
   2529         } else {
   2530             // need to hide the album art, either because we are unlocked or because
   2531             // the metadata isn't there to support it
   2532             if (mBackdrop.getVisibility() != View.GONE) {
   2533                 if (DEBUG_MEDIA) {
   2534                     Log.v(TAG, "DEBUG_MEDIA: Fading out album artwork");
   2535                 }
   2536                 if (mFingerprintUnlockController.getMode()
   2537                         == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
   2538                         || hideBecauseOccluded) {
   2539 
   2540                     // We are unlocking directly - no animation!
   2541                     mBackdrop.setVisibility(View.GONE);
   2542                     mBackdropBack.setImageDrawable(null);
   2543                     mStatusBarWindowManager.setBackdropShowing(false);
   2544                 } else {
   2545                     mStatusBarWindowManager.setBackdropShowing(false);
   2546                     mBackdrop.animate()
   2547                             .alpha(SRC_MIN_ALPHA)
   2548                             .setInterpolator(Interpolators.ACCELERATE_DECELERATE)
   2549                             .setDuration(300)
   2550                             .setStartDelay(0)
   2551                             .withEndAction(new Runnable() {
   2552                                 @Override
   2553                                 public void run() {
   2554                                     mBackdrop.setVisibility(View.GONE);
   2555                                     mBackdropFront.animate().cancel();
   2556                                     mBackdropBack.setImageDrawable(null);
   2557                                     mHandler.post(mHideBackdropFront);
   2558                                 }
   2559                             });
   2560                     if (mKeyguardFadingAway) {
   2561                         mBackdrop.animate()
   2562                                 // Make it disappear faster, as the focus should be on the activity
   2563                                 // behind.
   2564                                 .setDuration(mKeyguardFadingAwayDuration / 2)
   2565                                 .setStartDelay(mKeyguardFadingAwayDelay)
   2566                                 .setInterpolator(Interpolators.LINEAR)
   2567                                 .start();
   2568                     }
   2569                 }
   2570             }
   2571         }
   2572         Trace.endSection();
   2573     }
   2574 
   2575     private void updateReportRejectedTouchVisibility() {
   2576         if (mReportRejectedTouch == null) {
   2577             return;
   2578         }
   2579         mReportRejectedTouch.setVisibility(mState == StatusBarState.KEYGUARD
   2580                 && mFalsingManager.isReportingEnabled() ? View.VISIBLE : View.INVISIBLE);
   2581     }
   2582 
   2583     /**
   2584      * State is one or more of the DISABLE constants from StatusBarManager.
   2585      */
   2586     @Override
   2587     public void disable(int state1, int state2, boolean animate) {
   2588         animate &= mStatusBarWindowState != WINDOW_STATE_HIDDEN;
   2589         mDisabledUnmodified1 = state1;
   2590         mDisabledUnmodified2 = state2;
   2591         final int old1 = mDisabled1;
   2592         final int diff1 = state1 ^ old1;
   2593         mDisabled1 = state1;
   2594 
   2595         final int old2 = mDisabled2;
   2596         final int diff2 = state2 ^ old2;
   2597         mDisabled2 = state2;
   2598 
   2599         if (DEBUG) {
   2600             Log.d(TAG, String.format("disable1: 0x%08x -> 0x%08x (diff1: 0x%08x)",
   2601                 old1, state1, diff1));
   2602             Log.d(TAG, String.format("disable2: 0x%08x -> 0x%08x (diff2: 0x%08x)",
   2603                 old2, state2, diff2));
   2604         }
   2605 
   2606         StringBuilder flagdbg = new StringBuilder();
   2607         flagdbg.append("disable<");
   2608         flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_EXPAND))                ? 'E' : 'e');
   2609         flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_EXPAND))                ? '!' : ' ');
   2610         flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS))    ? 'I' : 'i');
   2611         flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_NOTIFICATION_ICONS))    ? '!' : ' ');
   2612         flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS))   ? 'A' : 'a');
   2613         flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_NOTIFICATION_ALERTS))   ? '!' : ' ');
   2614         flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_SYSTEM_INFO))           ? 'S' : 's');
   2615         flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_SYSTEM_INFO))           ? '!' : ' ');
   2616         flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_BACK))                  ? 'B' : 'b');
   2617         flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_BACK))                  ? '!' : ' ');
   2618         flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_HOME))                  ? 'H' : 'h');
   2619         flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_HOME))                  ? '!' : ' ');
   2620         flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_RECENT))                ? 'R' : 'r');
   2621         flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_RECENT))                ? '!' : ' ');
   2622         flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_CLOCK))                 ? 'C' : 'c');
   2623         flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_CLOCK))                 ? '!' : ' ');
   2624         flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_SEARCH))                ? 'S' : 's');
   2625         flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_SEARCH))                ? '!' : ' ');
   2626         flagdbg.append(0 != ((state2 & StatusBarManager.DISABLE2_QUICK_SETTINGS))       ? 'Q' : 'q');
   2627         flagdbg.append(0 != ((diff2  & StatusBarManager.DISABLE2_QUICK_SETTINGS))       ? '!' : ' ');
   2628         flagdbg.append('>');
   2629         Log.d(TAG, flagdbg.toString());
   2630 
   2631         if ((diff1 & StatusBarManager.DISABLE_EXPAND) != 0) {
   2632             if ((state1 & StatusBarManager.DISABLE_EXPAND) != 0) {
   2633                 animateCollapsePanels();
   2634             }
   2635         }
   2636 
   2637         if ((diff1 & StatusBarManager.DISABLE_RECENT) != 0) {
   2638             if ((state1 & StatusBarManager.DISABLE_RECENT) != 0) {
   2639                 // close recents if it's visible
   2640                 mHandler.removeMessages(MSG_HIDE_RECENT_APPS);
   2641                 mHandler.sendEmptyMessage(MSG_HIDE_RECENT_APPS);
   2642             }
   2643         }
   2644 
   2645         if ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) {
   2646             mDisableNotificationAlerts =
   2647                     (state1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
   2648             mHeadsUpObserver.onChange(true);
   2649         }
   2650 
   2651         if ((diff2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) {
   2652             updateQsExpansionEnabled();
   2653         }
   2654     }
   2655 
   2656     /**
   2657      * Reapplies the disable flags as last requested by StatusBarManager.
   2658      *
   2659      * This needs to be called if state used by {@link #adjustDisableFlags} changes.
   2660      */
   2661     public void recomputeDisableFlags(boolean animate) {
   2662         mCommandQueue.recomputeDisableFlags(animate);
   2663     }
   2664 
   2665     protected H createHandler() {
   2666         return new StatusBar.H();
   2667     }
   2668 
   2669     @Override
   2670     public void startActivity(Intent intent, boolean dismissShade) {
   2671         startActivityDismissingKeyguard(intent, false, dismissShade);
   2672     }
   2673 
   2674     @Override
   2675     public void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade) {
   2676         startActivityDismissingKeyguard(intent, onlyProvisioned, dismissShade);
   2677     }
   2678 
   2679     @Override
   2680     public void startActivity(Intent intent, boolean dismissShade, Callback callback) {
   2681         startActivityDismissingKeyguard(intent, false, dismissShade,
   2682                 false /* disallowEnterPictureInPictureWhileLaunching */, callback);
   2683     }
   2684 
   2685     public void setQsExpanded(boolean expanded) {
   2686         mStatusBarWindowManager.setQsExpanded(expanded);
   2687         mNotificationPanel.setStatusAccessibilityImportance(expanded
   2688                 ? View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
   2689                 : View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
   2690     }
   2691 
   2692     public boolean isGoingToNotificationShade() {
   2693         return mLeaveOpenOnKeyguardHide;
   2694     }
   2695 
   2696     public boolean isWakeUpComingFromTouch() {
   2697         return mWakeUpComingFromTouch;
   2698     }
   2699 
   2700     public boolean isFalsingThresholdNeeded() {
   2701         return getBarState() == StatusBarState.KEYGUARD;
   2702     }
   2703 
   2704     public boolean isDozing() {
   2705         return mDozing;
   2706     }
   2707 
   2708     @Override  // NotificationData.Environment
   2709     public String getCurrentMediaNotificationKey() {
   2710         return mMediaNotificationKey;
   2711     }
   2712 
   2713     public boolean isScrimSrcModeEnabled() {
   2714         return mScrimSrcModeEnabled;
   2715     }
   2716 
   2717     /**
   2718      * To be called when there's a state change in StatusBarKeyguardViewManager.
   2719      */
   2720     public void onKeyguardViewManagerStatesUpdated() {
   2721         logStateToEventlog();
   2722     }
   2723 
   2724     @Override  // UnlockMethodCache.OnUnlockMethodChangedListener
   2725     public void onUnlockMethodStateChanged() {
   2726         logStateToEventlog();
   2727     }
   2728 
   2729     @Override
   2730     public void onHeadsUpPinnedModeChanged(boolean inPinnedMode) {
   2731         if (inPinnedMode) {
   2732             mStatusBarWindowManager.setHeadsUpShowing(true);
   2733             mStatusBarWindowManager.setForceStatusBarVisible(true);
   2734             if (mNotificationPanel.isFullyCollapsed()) {
   2735                 // We need to ensure that the touchable region is updated before the window will be
   2736                 // resized, in order to not catch any touches. A layout will ensure that
   2737                 // onComputeInternalInsets will be called and after that we can resize the layout. Let's
   2738                 // make sure that the window stays small for one frame until the touchableRegion is set.
   2739                 mNotificationPanel.requestLayout();
   2740                 mStatusBarWindowManager.setForceWindowCollapsed(true);
   2741                 mNotificationPanel.post(new Runnable() {
   2742                     @Override
   2743                     public void run() {
   2744                         mStatusBarWindowManager.setForceWindowCollapsed(false);
   2745                     }
   2746                 });
   2747             }
   2748         } else {
   2749             if (!mNotificationPanel.isFullyCollapsed() || mNotificationPanel.isTracking()) {
   2750                 // We are currently tracking or is open and the shade doesn't need to be kept
   2751                 // open artificially.
   2752                 mStatusBarWindowManager.setHeadsUpShowing(false);
   2753             } else {
   2754                 // we need to keep the panel open artificially, let's wait until the animation
   2755                 // is finished.
   2756                 mHeadsUpManager.setHeadsUpGoingAway(true);
   2757                 mStackScroller.runAfterAnimationFinished(new Runnable() {
   2758                     @Override
   2759                     public void run() {
   2760                         if (!mHeadsUpManager.hasPinnedHeadsUp()) {
   2761                             mStatusBarWindowManager.setHeadsUpShowing(false);
   2762                             mHeadsUpManager.setHeadsUpGoingAway(false);
   2763                         }
   2764                         removeRemoteInputEntriesKeptUntilCollapsed();
   2765                     }
   2766                 });
   2767             }
   2768         }
   2769     }
   2770 
   2771     @Override
   2772     public void onHeadsUpPinned(ExpandableNotificationRow headsUp) {
   2773         dismissVolumeDialog();
   2774     }
   2775 
   2776     @Override
   2777     public void onHeadsUpUnPinned(ExpandableNotificationRow headsUp) {
   2778     }
   2779 
   2780     @Override
   2781     public void onHeadsUpStateChanged(Entry entry, boolean isHeadsUp) {
   2782         if (!isHeadsUp && mHeadsUpEntriesToRemoveOnSwitch.contains(entry)) {
   2783             removeNotification(entry.key, mLatestRankingMap);
   2784             mHeadsUpEntriesToRemoveOnSwitch.remove(entry);
   2785             if (mHeadsUpEntriesToRemoveOnSwitch.isEmpty()) {
   2786                 mLatestRankingMap = null;
   2787             }
   2788         } else {
   2789             updateNotificationRanking(null);
   2790             if (isHeadsUp) {
   2791                 mDozeServiceHost.fireNotificationHeadsUp();
   2792             }
   2793         }
   2794 
   2795     }
   2796 
   2797     protected void updateHeadsUp(String key, Entry entry, boolean shouldPeek,
   2798             boolean alertAgain) {
   2799         final boolean wasHeadsUp = isHeadsUp(key);
   2800         if (wasHeadsUp) {
   2801             if (!shouldPeek) {
   2802                 // We don't want this to be interrupting anymore, lets remove it
   2803                 mHeadsUpManager.removeNotification(key, false /* ignoreEarliestRemovalTime */);
   2804             } else {
   2805                 mHeadsUpManager.updateNotification(entry, alertAgain);
   2806             }
   2807         } else if (shouldPeek && alertAgain) {
   2808             // This notification was updated to be a heads-up, show it!
   2809             mHeadsUpManager.showNotification(entry);
   2810         }
   2811     }
   2812 
   2813     protected void setHeadsUpUser(int newUserId) {
   2814         if (mHeadsUpManager != null) {
   2815             mHeadsUpManager.setUser(newUserId);
   2816         }
   2817     }
   2818 
   2819     public boolean isHeadsUp(String key) {
   2820         return mHeadsUpManager.isHeadsUp(key);
   2821     }
   2822 
   2823     protected boolean isSnoozedPackage(StatusBarNotification sbn) {
   2824         return mHeadsUpManager.isSnoozed(sbn.getPackageName());
   2825     }
   2826 
   2827     public boolean isKeyguardCurrentlySecure() {
   2828         return !mUnlockMethodCache.canSkipBouncer();
   2829     }
   2830 
   2831     public void setPanelExpanded(boolean isExpanded) {
   2832         mPanelExpanded = isExpanded;
   2833         updateHideIconsForBouncer(false /* animate */);
   2834         mStatusBarWindowManager.setPanelExpanded(isExpanded);
   2835         mVisualStabilityManager.setPanelExpanded(isExpanded);
   2836         if (isExpanded && getBarState() != StatusBarState.KEYGUARD) {
   2837             if (DEBUG) {
   2838                 Log.v(TAG, "clearing notification effects from setPanelExpanded");
   2839             }
   2840             clearNotificationEffects();
   2841         }
   2842 
   2843         if (!isExpanded) {
   2844             removeRemoteInputEntriesKeptUntilCollapsed();
   2845         }
   2846     }
   2847 
   2848     private void removeRemoteInputEntriesKeptUntilCollapsed() {
   2849         for (int i = 0; i < mRemoteInputEntriesToRemoveOnCollapse.size(); i++) {
   2850             Entry entry = mRemoteInputEntriesToRemoveOnCollapse.valueAt(i);
   2851             mRemoteInputController.removeRemoteInput(entry, null);
   2852             removeNotification(entry.key, mLatestRankingMap);
   2853         }
   2854         mRemoteInputEntriesToRemoveOnCollapse.clear();
   2855     }
   2856 
   2857     public NotificationStackScrollLayout getNotificationScrollLayout() {
   2858         return mStackScroller;
   2859     }
   2860 
   2861     public boolean isPulsing() {
   2862         return mDozeScrimController.isPulsing();
   2863     }
   2864 
   2865     @Override
   2866     public void onReorderingAllowed() {
   2867         updateNotifications();
   2868     }
   2869 
   2870     public boolean isLaunchTransitionFadingAway() {
   2871         return mLaunchTransitionFadingAway;
   2872     }
   2873 
   2874     public boolean hideStatusBarIconsWhenExpanded() {
   2875         return mNotificationPanel.hideStatusBarIconsWhenExpanded();
   2876     }
   2877 
   2878     @Override
   2879     public void onColorsChanged(ColorExtractor extractor, int which) {
   2880         updateTheme();
   2881     }
   2882 
   2883     public boolean isUsingDarkTheme() {
   2884         OverlayInfo themeInfo = null;
   2885         try {
   2886             themeInfo = mOverlayManager.getOverlayInfo("com.android.systemui.theme.dark",
   2887                     mCurrentUserId);
   2888         } catch (RemoteException e) {
   2889             e.printStackTrace();
   2890         }
   2891         return themeInfo != null && themeInfo.isEnabled();
   2892     }
   2893 
   2894     @Nullable
   2895     public View getAmbientIndicationContainer() {
   2896         return mAmbientIndicationContainer;
   2897     }
   2898 
   2899     public void setOccluded(boolean occluded) {
   2900         mIsOccluded = occluded;
   2901         updateHideIconsForBouncer(false /* animate */);
   2902     }
   2903 
   2904     public boolean hideStatusBarIconsForBouncer() {
   2905         return mHideIconsForBouncer || mWereIconsJustHidden;
   2906     }
   2907 
   2908     /**
   2909      * @param animate should the change of the icons be animated.
   2910      */
   2911     private void updateHideIconsForBouncer(boolean animate) {
   2912         boolean shouldHideIconsForBouncer = !mPanelExpanded && mTopHidesStatusBar && mIsOccluded
   2913                 && (mBouncerShowing || mStatusBarWindowHidden);
   2914         if (mHideIconsForBouncer != shouldHideIconsForBouncer) {
   2915             mHideIconsForBouncer = shouldHideIconsForBouncer;
   2916             if (!shouldHideIconsForBouncer && mBouncerWasShowingWhenHidden) {
   2917                 // We're delaying the showing, since most of the time the fullscreen app will
   2918                 // hide the icons again and we don't want them to fade in and out immediately again.
   2919                 mWereIconsJustHidden = true;
   2920                 mHandler.postDelayed(() -> {
   2921                     mWereIconsJustHidden = false;
   2922                     recomputeDisableFlags(true);
   2923                 }, 500);
   2924             } else {
   2925                 recomputeDisableFlags(animate);
   2926             }
   2927         }
   2928         if (shouldHideIconsForBouncer) {
   2929             mBouncerWasShowingWhenHidden = mBouncerShowing;
   2930         }
   2931     }
   2932 
   2933     /**
   2934      * All changes to the status bar and notifications funnel through here and are batched.
   2935      */
   2936     protected class H extends Handler {
   2937         @Override
   2938         public void handleMessage(Message m) {
   2939             switch (m.what) {
   2940                 case MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU:
   2941                     toggleKeyboardShortcuts(m.arg1);
   2942                     break;
   2943                 case MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU:
   2944                     dismissKeyboardShortcuts();
   2945                     break;
   2946                 // End old BaseStatusBar.H handling.
   2947                 case MSG_OPEN_NOTIFICATION_PANEL:
   2948                     animateExpandNotificationsPanel();
   2949                     break;
   2950                 case MSG_OPEN_SETTINGS_PANEL:
   2951                     animateExpandSettingsPanel((String) m.obj);
   2952                     break;
   2953                 case MSG_CLOSE_PANELS:
   2954                     animateCollapsePanels();
   2955                     break;
   2956                 case MSG_LAUNCH_TRANSITION_TIMEOUT:
   2957                     onLaunchTransitionTimeout();
   2958                     break;
   2959             }
   2960         }
   2961     }
   2962 
   2963     public void maybeEscalateHeadsUp() {
   2964         Collection<HeadsUpManager.HeadsUpEntry> entries = mHeadsUpManager.getAllEntries();
   2965         for (HeadsUpManager.HeadsUpEntry entry : entries) {
   2966             final StatusBarNotification sbn = entry.entry.notification;
   2967             final Notification notification = sbn.getNotification();
   2968             if (notification.fullScreenIntent != null) {
   2969                 if (DEBUG) {
   2970                     Log.d(TAG, "converting a heads up to fullScreen");
   2971                 }
   2972                 try {
   2973                     EventLog.writeEvent(EventLogTags.SYSUI_HEADS_UP_ESCALATION,
   2974                             sbn.getKey());
   2975                     notification.fullScreenIntent.send();
   2976                     entry.entry.notifyFullScreenIntentLaunched();
   2977                 } catch (PendingIntent.CanceledException e) {
   2978                 }
   2979             }
   2980         }
   2981         mHeadsUpManager.releaseAllImmediately();
   2982     }
   2983 
   2984     /**
   2985      * Called for system navigation gestures. First action opens the panel, second opens
   2986      * settings. Down action closes the entire panel.
   2987      */
   2988     @Override
   2989     public void handleSystemKey(int key) {
   2990         if (SPEW) Log.d(TAG, "handleNavigationKey: " + key);
   2991         if (!panelsEnabled() || !mKeyguardMonitor.isDeviceInteractive()
   2992                 || mKeyguardMonitor.isShowing() && !mKeyguardMonitor.isOccluded()) {
   2993             return;
   2994         }
   2995 
   2996         // Panels are not available in setup
   2997         if (!mUserSetup) return;
   2998 
   2999         if (KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP == key) {
   3000             mMetricsLogger.action(MetricsEvent.ACTION_SYSTEM_NAVIGATION_KEY_UP);
   3001             mNotificationPanel.collapse(false /* delayed */, 1.0f /* speedUpFactor */);
   3002         } else if (KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN == key) {
   3003             mMetricsLogger.action(MetricsEvent.ACTION_SYSTEM_NAVIGATION_KEY_DOWN);
   3004             if (mNotificationPanel.isFullyCollapsed()) {
   3005                 mNotificationPanel.expand(true /* animate */);
   3006                 mMetricsLogger.count(NotificationPanelView.COUNTER_PANEL_OPEN, 1);
   3007             } else if (!mNotificationPanel.isInSettings() && !mNotificationPanel.isExpanding()){
   3008                 mNotificationPanel.flingSettings(0 /* velocity */, true /* expand */);
   3009                 mMetricsLogger.count(NotificationPanelView.COUNTER_PANEL_OPEN_QS, 1);
   3010             }
   3011         }
   3012 
   3013     }
   3014 
   3015     boolean panelsEnabled() {
   3016         return (mDisabled1 & StatusBarManager.DISABLE_EXPAND) == 0 && !ONLY_CORE_APPS;
   3017     }
   3018 
   3019     void makeExpandedVisible(boolean force) {
   3020         if (SPEW) Log.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible);
   3021         if (!force && (mExpandedVisible || !panelsEnabled())) {
   3022             return;
   3023         }
   3024 
   3025         mExpandedVisible = true;
   3026 
   3027         // Expand the window to encompass the full screen in anticipation of the drag.
   3028         // This is only possible to do atomically because the status bar is at the top of the screen!
   3029         mStatusBarWindowManager.setPanelVisible(true);
   3030 
   3031         visibilityChanged(true);
   3032         mWaitingForKeyguardExit = false;
   3033         recomputeDisableFlags(!force /* animate */);
   3034         setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true);
   3035     }
   3036 
   3037     public void animateCollapsePanels() {
   3038         animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
   3039     }
   3040 
   3041     private final Runnable mAnimateCollapsePanels = new Runnable() {
   3042         @Override
   3043         public void run() {
   3044             animateCollapsePanels();
   3045         }
   3046     };
   3047 
   3048     public void postAnimateCollapsePanels() {
   3049         mHandler.post(mAnimateCollapsePanels);
   3050     }
   3051 
   3052     public void postAnimateForceCollapsePanels() {
   3053         mHandler.post(new Runnable() {
   3054             @Override
   3055             public void run() {
   3056                 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */);
   3057             }
   3058         });
   3059     }
   3060 
   3061     public void postAnimateOpenPanels() {
   3062         mHandler.sendEmptyMessage(MSG_OPEN_SETTINGS_PANEL);
   3063     }
   3064 
   3065     @Override
   3066     public void togglePanel() {
   3067         if (mPanelExpanded) {
   3068             animateCollapsePanels();
   3069         } else {
   3070             animateExpandNotificationsPanel();
   3071         }
   3072     }
   3073 
   3074     @Override
   3075     public void animateCollapsePanels(int flags) {
   3076         animateCollapsePanels(flags, false /* force */, false /* delayed */,
   3077                 1.0f /* speedUpFactor */);
   3078     }
   3079 
   3080     public void animateCollapsePanels(int flags, boolean force) {
   3081         animateCollapsePanels(flags, force, false /* delayed */, 1.0f /* speedUpFactor */);
   3082     }
   3083 
   3084     public void animateCollapsePanels(int flags, boolean force, boolean delayed) {
   3085         animateCollapsePanels(flags, force, delayed, 1.0f /* speedUpFactor */);
   3086     }
   3087 
   3088     public void animateCollapsePanels(int flags, boolean force, boolean delayed,
   3089             float speedUpFactor) {
   3090         if (!force && mState != StatusBarState.SHADE) {
   3091             runPostCollapseRunnables();
   3092             return;
   3093         }
   3094         if (SPEW) {
   3095             Log.d(TAG, "animateCollapse():"
   3096                     + " mExpandedVisible=" + mExpandedVisible
   3097                     + " flags=" + flags);
   3098         }
   3099 
   3100         if ((flags & CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL) == 0) {
   3101             if (!mHandler.hasMessages(MSG_HIDE_RECENT_APPS)) {
   3102                 mHandler.removeMessages(MSG_HIDE_RECENT_APPS);
   3103                 mHandler.sendEmptyMessage(MSG_HIDE_RECENT_APPS);
   3104             }
   3105         }
   3106 
   3107         if (mStatusBarWindow != null && mNotificationPanel.canPanelBeCollapsed()) {
   3108             // release focus immediately to kick off focus change transition
   3109             mStatusBarWindowManager.setStatusBarFocusable(false);
   3110 
   3111             mStatusBarWindow.cancelExpandHelper();
   3112             mStatusBarView.collapsePanel(true /* animate */, delayed, speedUpFactor);
   3113         }
   3114     }
   3115 
   3116     private void runPostCollapseRunnables() {
   3117         ArrayList<Runnable> clonedList = new ArrayList<>(mPostCollapseRunnables);
   3118         mPostCollapseRunnables.clear();
   3119         int size = clonedList.size();
   3120         for (int i = 0; i < size; i++) {
   3121             clonedList.get(i).run();
   3122         }
   3123         mStatusBarKeyguardViewManager.readyForKeyguardDone();
   3124     }
   3125 
   3126     @Override
   3127     public void animateExpandNotificationsPanel() {
   3128         if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible);
   3129         if (!panelsEnabled()) {
   3130             return ;
   3131         }
   3132 
   3133         mNotificationPanel.expand(true /* animate */);
   3134 
   3135         if (false) postStartTracing();
   3136     }
   3137 
   3138     @Override
   3139     public void animateExpandSettingsPanel(String subPanel) {
   3140         if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible);
   3141         if (!panelsEnabled()) {
   3142             return;
   3143         }
   3144 
   3145         // Settings are not available in setup
   3146         if (!mUserSetup) return;
   3147 
   3148 
   3149         if (subPanel != null) {
   3150             mQSPanel.openDetails(subPanel);
   3151         }
   3152         mNotificationPanel.expandWithQs();
   3153 
   3154         if (false) postStartTracing();
   3155     }
   3156 
   3157     public void animateCollapseQuickSettings() {
   3158         if (mState == StatusBarState.SHADE) {
   3159             mStatusBarView.collapsePanel(true, false /* delayed */, 1.0f /* speedUpFactor */);
   3160         }
   3161     }
   3162 
   3163     void makeExpandedInvisible() {
   3164         if (SPEW) Log.d(TAG, "makeExpandedInvisible: mExpandedVisible=" + mExpandedVisible
   3165                 + " mExpandedVisible=" + mExpandedVisible);
   3166 
   3167         if (!mExpandedVisible || mStatusBarWindow == null) {
   3168             return;
   3169         }
   3170 
   3171         // Ensure the panel is fully collapsed (just in case; bug 6765842, 7260868)
   3172         mStatusBarView.collapsePanel(/*animate=*/ false, false /* delayed*/,
   3173                 1.0f /* speedUpFactor */);
   3174 
   3175         mNotificationPanel.closeQs();
   3176 
   3177         mExpandedVisible = false;
   3178         visibilityChanged(false);
   3179 
   3180         // Shrink the window to the size of the status bar only
   3181         mStatusBarWindowManager.setPanelVisible(false);
   3182         mStatusBarWindowManager.setForceStatusBarVisible(false);
   3183 
   3184         // Close any guts that might be visible
   3185         closeAndSaveGuts(true /* removeLeavebehind */, true /* force */, true /* removeControls */,
   3186                 -1 /* x */, -1 /* y */, true /* resetMenu */);
   3187 
   3188         runPostCollapseRunnables();
   3189         setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
   3190         showBouncerIfKeyguard();
   3191         recomputeDisableFlags(mNotificationPanel.hideStatusBarIconsWhenExpanded() /* animate */);
   3192 
   3193         // Trimming will happen later if Keyguard is showing - doing it here might cause a jank in
   3194         // the bouncer appear animation.
   3195         if (!mStatusBarKeyguardViewManager.isShowing()) {
   3196             WindowManagerGlobal.getInstance().trimMemory(ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
   3197         }
   3198     }
   3199 
   3200     public boolean interceptTouchEvent(MotionEvent event) {
   3201         if (DEBUG_GESTURES) {
   3202             if (event.getActionMasked() != MotionEvent.ACTION_MOVE) {
   3203                 EventLog.writeEvent(EventLogTags.SYSUI_STATUSBAR_TOUCH,
   3204                         event.getActionMasked(), (int) event.getX(), (int) event.getY(),
   3205                         mDisabled1, mDisabled2);
   3206             }
   3207 
   3208         }
   3209 
   3210         if (SPEW) {
   3211             Log.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled1="
   3212                 + mDisabled1 + " mDisabled2=" + mDisabled2 + " mTracking=" + mTracking);
   3213         } else if (CHATTY) {
   3214             if (event.getAction() != MotionEvent.ACTION_MOVE) {
   3215                 Log.d(TAG, String.format(
   3216                             "panel: %s at (%f, %f) mDisabled1=0x%08x mDisabled2=0x%08x",
   3217                             MotionEvent.actionToString(event.getAction()),
   3218                             event.getRawX(), event.getRawY(), mDisabled1, mDisabled2));
   3219             }
   3220         }
   3221 
   3222         if (DEBUG_GESTURES) {
   3223             mGestureRec.add(event);
   3224         }
   3225 
   3226         if (mStatusBarWindowState == WINDOW_STATE_SHOWING) {
   3227             final boolean upOrCancel =
   3228                     event.getAction() == MotionEvent.ACTION_UP ||
   3229                     event.getAction() == MotionEvent.ACTION_CANCEL;
   3230             if (upOrCancel && !mExpandedVisible) {
   3231                 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
   3232             } else {
   3233                 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true);
   3234             }
   3235         }
   3236         return false;
   3237     }
   3238 
   3239     public GestureRecorder getGestureRecorder() {
   3240         return mGestureRec;
   3241     }
   3242 
   3243     public FingerprintUnlockController getFingerprintUnlockController() {
   3244         return mFingerprintUnlockController;
   3245     }
   3246 
   3247     @Override // CommandQueue
   3248     public void setWindowState(int window, int state) {
   3249         boolean showing = state == WINDOW_STATE_SHOWING;
   3250         if (mStatusBarWindow != null
   3251                 && window == StatusBarManager.WINDOW_STATUS_BAR
   3252                 && mStatusBarWindowState != state) {
   3253             mStatusBarWindowState = state;
   3254             if (DEBUG_WINDOW_STATE) Log.d(TAG, "Status bar " + windowStateToString(state));
   3255             if (!showing && mState == StatusBarState.SHADE) {
   3256                 mStatusBarView.collapsePanel(false /* animate */, false /* delayed */,
   3257                         1.0f /* speedUpFactor */);
   3258             }
   3259             if (mStatusBarView != null) {
   3260                 mStatusBarWindowHidden = state == WINDOW_STATE_HIDDEN;
   3261                 updateHideIconsForBouncer(false /* animate */);
   3262             }
   3263         }
   3264     }
   3265 
   3266     @Override // CommandQueue
   3267     public void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis,
   3268             int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
   3269         final int oldVal = mSystemUiVisibility;
   3270         final int newVal = (oldVal&~mask) | (vis&mask);
   3271         final int diff = newVal ^ oldVal;
   3272         if (DEBUG) Log.d(TAG, String.format(
   3273                 "setSystemUiVisibility vis=%s mask=%s oldVal=%s newVal=%s diff=%s",
   3274                 Integer.toHexString(vis), Integer.toHexString(mask),
   3275                 Integer.toHexString(oldVal), Integer.toHexString(newVal),
   3276                 Integer.toHexString(diff)));
   3277         boolean sbModeChanged = false;
   3278         if (diff != 0) {
   3279             mSystemUiVisibility = newVal;
   3280 
   3281             // update low profile
   3282             if ((diff & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0) {
   3283                 setAreThereNotifications();
   3284             }
   3285 
   3286             // ready to unhide
   3287             if ((vis & View.STATUS_BAR_UNHIDE) != 0) {
   3288                 mSystemUiVisibility &= ~View.STATUS_BAR_UNHIDE;
   3289                 mNoAnimationOnNextBarModeChange = true;
   3290             }
   3291 
   3292             // update status bar mode
   3293             final int sbMode = computeStatusBarMode(oldVal, newVal);
   3294 
   3295             sbModeChanged = sbMode != -1;
   3296             if (sbModeChanged && sbMode != mStatusBarMode) {
   3297                 if (sbMode != mStatusBarMode) {
   3298                     mStatusBarMode = sbMode;
   3299                     checkBarModes();
   3300                 }
   3301                 touchAutoHide();
   3302             }
   3303 
   3304             if ((vis & View.NAVIGATION_BAR_UNHIDE) != 0) {
   3305                 mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE;
   3306             }
   3307 
   3308             // send updated sysui visibility to window manager
   3309             notifyUiVisibilityChanged(mSystemUiVisibility);
   3310         }
   3311 
   3312         mLightBarController.onSystemUiVisibilityChanged(fullscreenStackVis, dockedStackVis,
   3313                 mask, fullscreenStackBounds, dockedStackBounds, sbModeChanged, mStatusBarMode);
   3314     }
   3315 
   3316     void touchAutoHide() {
   3317         // update transient bar autohide
   3318         if (mStatusBarMode == MODE_SEMI_TRANSPARENT || (mNavigationBar != null
   3319                 && mNavigationBar.isSemiTransparent())) {
   3320             scheduleAutohide();
   3321         } else {
   3322             cancelAutohide();
   3323         }
   3324     }
   3325 
   3326     protected int computeStatusBarMode(int oldVal, int newVal) {
   3327         return computeBarMode(oldVal, newVal, View.STATUS_BAR_TRANSIENT,
   3328                 View.STATUS_BAR_TRANSLUCENT, View.STATUS_BAR_TRANSPARENT);
   3329     }
   3330 
   3331     protected BarTransitions getStatusBarTransitions() {
   3332         return mStatusBarView.getBarTransitions();
   3333     }
   3334 
   3335     protected int computeBarMode(int oldVis, int newVis,
   3336             int transientFlag, int translucentFlag, int transparentFlag) {
   3337         final int oldMode = barMode(oldVis, transientFlag, translucentFlag, transparentFlag);
   3338         final int newMode = barMode(newVis, transientFlag, translucentFlag, transparentFlag);
   3339         if (oldMode == newMode) {
   3340             return -1; // no mode change
   3341         }
   3342         return newMode;
   3343     }
   3344 
   3345     private int barMode(int vis, int transientFlag, int translucentFlag, int transparentFlag) {
   3346         int lightsOutTransparent = View.SYSTEM_UI_FLAG_LOW_PROFILE | transparentFlag;
   3347         return (vis & transientFlag) != 0 ? MODE_SEMI_TRANSPARENT
   3348                 : (vis & translucentFlag) != 0 ? MODE_TRANSLUCENT
   3349                 : (vis & lightsOutTransparent) == lightsOutTransparent ? MODE_LIGHTS_OUT_TRANSPARENT
   3350                 : (vis & transparentFlag) != 0 ? MODE_TRANSPARENT
   3351                 : (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0 ? MODE_LIGHTS_OUT
   3352                 : MODE_OPAQUE;
   3353     }
   3354 
   3355     void checkBarModes() {
   3356         if (mDemoMode) return;
   3357         if (mStatusBarView != null) checkBarMode(mStatusBarMode, mStatusBarWindowState,
   3358                 getStatusBarTransitions());
   3359         if (mNavigationBar != null) mNavigationBar.checkNavBarModes();
   3360         mNoAnimationOnNextBarModeChange = false;
   3361     }
   3362 
   3363     // Called by NavigationBarFragment
   3364     void setQsScrimEnabled(boolean scrimEnabled) {
   3365         mNotificationPanel.setQsScrimEnabled(scrimEnabled);
   3366     }
   3367 
   3368     void checkBarMode(int mode, int windowState, BarTransitions transitions) {
   3369         final boolean powerSave = mBatteryController.isPowerSave();
   3370         final boolean anim = !mNoAnimationOnNextBarModeChange && mDeviceInteractive
   3371                 && windowState != WINDOW_STATE_HIDDEN && !powerSave;
   3372         if (powerSave && getBarState() == StatusBarState.SHADE) {
   3373             mode = MODE_WARNING;
   3374         }
   3375         transitions.transitionTo(mode, anim);
   3376     }
   3377 
   3378     private void finishBarAnimations() {
   3379         if (mStatusBarView != null) {
   3380             mStatusBarView.getBarTransitions().finishAnimations();
   3381         }
   3382         if (mNavigationBar != null) {
   3383             mNavigationBar.finishBarAnimations();
   3384         }
   3385     }
   3386 
   3387     private final Runnable mCheckBarModes = new Runnable() {
   3388         @Override
   3389         public void run() {
   3390             checkBarModes();
   3391         }
   3392     };
   3393 
   3394     public void setInteracting(int barWindow, boolean interacting) {
   3395         final boolean changing = ((mInteractingWindows & barWindow) != 0) != interacting;
   3396         mInteractingWindows = interacting
   3397                 ? (mInteractingWindows | barWindow)
   3398                 : (mInteractingWindows & ~barWindow);
   3399         if (mInteractingWindows != 0) {
   3400             suspendAutohide();
   3401         } else {
   3402             resumeSuspendedAutohide();
   3403         }
   3404         // manually dismiss the volume panel when interacting with the nav bar
   3405         if (changing && interacting && barWindow == StatusBarManager.WINDOW_NAVIGATION_BAR) {
   3406             touchAutoDim();
   3407             dismissVolumeDialog();
   3408         }
   3409         checkBarModes();
   3410     }
   3411 
   3412     private void dismissVolumeDialog() {
   3413         if (mVolumeComponent != null) {
   3414             mVolumeComponent.dismissNow();
   3415         }
   3416     }
   3417 
   3418     private void resumeSuspendedAutohide() {
   3419         if (mAutohideSuspended) {
   3420             scheduleAutohide();
   3421             mHandler.postDelayed(mCheckBarModes, 500); // longer than home -> launcher
   3422         }
   3423     }
   3424 
   3425     private void suspendAutohide() {
   3426         mHandler.removeCallbacks(mAutohide);
   3427         mHandler.removeCallbacks(mCheckBarModes);
   3428         mAutohideSuspended = (mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0;
   3429     }
   3430 
   3431     private void cancelAutohide() {
   3432         mAutohideSuspended = false;
   3433         mHandler.removeCallbacks(mAutohide);
   3434     }
   3435 
   3436     private void scheduleAutohide() {
   3437         cancelAutohide();
   3438         mHandler.postDelayed(mAutohide, AUTOHIDE_TIMEOUT_MS);
   3439     }
   3440 
   3441     public void touchAutoDim() {
   3442         if (mNavigationBar != null) {
   3443             mNavigationBar.getBarTransitions().setAutoDim(false);
   3444         }
   3445         mHandler.removeCallbacks(mAutoDim);
   3446         if (mState != StatusBarState.KEYGUARD && mState != StatusBarState.SHADE_LOCKED) {
   3447             mHandler.postDelayed(mAutoDim, AUTOHIDE_TIMEOUT_MS);
   3448         }
   3449     }
   3450 
   3451     void checkUserAutohide(View v, MotionEvent event) {
   3452         if ((mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0  // a transient bar is revealed
   3453                 && event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar
   3454                 && event.getX() == 0 && event.getY() == 0  // a touch outside both bars
   3455                 && !mRemoteInputController.isRemoteInputActive()) { // not due to typing in IME
   3456             userAutohide();
   3457         }
   3458     }
   3459 
   3460     private void checkRemoteInputOutside(MotionEvent event) {
   3461         if (event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar
   3462                 && event.getX() == 0 && event.getY() == 0  // a touch outside both bars
   3463                 && mRemoteInputController.isRemoteInputActive()) {
   3464             mRemoteInputController.closeRemoteInputs();
   3465         }
   3466     }
   3467 
   3468     private void userAutohide() {
   3469         cancelAutohide();
   3470         mHandler.postDelayed(mAutohide, 350); // longer than app gesture -> flag clear
   3471     }
   3472 
   3473     private boolean areLightsOn() {
   3474         return 0 == (mSystemUiVisibility & View.SYSTEM_UI_FLAG_LOW_PROFILE);
   3475     }
   3476 
   3477     public void setLightsOn(boolean on) {
   3478         Log.v(TAG, "setLightsOn(" + on + ")");
   3479         if (on) {
   3480             setSystemUiVisibility(0, 0, 0, View.SYSTEM_UI_FLAG_LOW_PROFILE,
   3481                     mLastFullscreenStackBounds, mLastDockedStackBounds);
   3482         } else {
   3483             setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE, 0, 0,
   3484                     View.SYSTEM_UI_FLAG_LOW_PROFILE, mLastFullscreenStackBounds,
   3485                     mLastDockedStackBounds);
   3486         }
   3487     }
   3488 
   3489     private void notifyUiVisibilityChanged(int vis) {
   3490         try {
   3491             if (mLastDispatchedSystemUiVisibility != vis) {
   3492                 mWindowManagerService.statusBarVisibilityChanged(vis);
   3493                 mLastDispatchedSystemUiVisibility = vis;
   3494             }
   3495         } catch (RemoteException ex) {
   3496         }
   3497     }
   3498 
   3499     @Override
   3500     public void topAppWindowChanged(boolean showMenu) {
   3501         if (SPEW) {
   3502             Log.d(TAG, (showMenu?"showing":"hiding") + " the MENU button");
   3503         }
   3504 
   3505         // See above re: lights-out policy for legacy apps.
   3506         if (showMenu) setLightsOn(true);
   3507     }
   3508 
   3509     public static String viewInfo(View v) {
   3510         return "[(" + v.getLeft() + "," + v.getTop() + ")(" + v.getRight() + "," + v.getBottom()
   3511                 + ") " + v.getWidth() + "x" + v.getHeight() + "]";
   3512     }
   3513 
   3514     @Override
   3515     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   3516         synchronized (mQueueLock) {
   3517             pw.println("Current Status Bar state:");
   3518             pw.println("  mExpandedVisible=" + mExpandedVisible
   3519                     + ", mTrackingPosition=" + mTrackingPosition);
   3520             pw.println("  mTracking=" + mTracking);
   3521             pw.println("  mDisplayMetrics=" + mDisplayMetrics);
   3522             pw.println("  mStackScroller: " + viewInfo(mStackScroller));
   3523             pw.println("  mStackScroller: " + viewInfo(mStackScroller)
   3524                     + " scroll " + mStackScroller.getScrollX()
   3525                     + "," + mStackScroller.getScrollY());
   3526         }
   3527         pw.print("  mPendingNotifications=");
   3528         if (mPendingNotifications.size() == 0) {
   3529             pw.println("null");
   3530         } else {
   3531             for (Entry entry : mPendingNotifications.values()) {
   3532                 pw.println(entry.notification);
   3533             }
   3534         }
   3535 
   3536         pw.print("  mInteractingWindows="); pw.println(mInteractingWindows);
   3537         pw.print("  mStatusBarWindowState=");
   3538         pw.println(windowStateToString(mStatusBarWindowState));
   3539         pw.print("  mStatusBarMode=");
   3540         pw.println(BarTransitions.modeToString(mStatusBarMode));
   3541         pw.print("  mDozing="); pw.println(mDozing);
   3542         pw.print("  mZenMode=");
   3543         pw.println(Settings.Global.zenModeToString(mZenMode));
   3544         pw.print("  mUseHeadsUp=");
   3545         pw.println(mUseHeadsUp);
   3546         pw.print("  mKeyToRemoveOnGutsClosed=");
   3547         pw.println(mKeyToRemoveOnGutsClosed);
   3548         if (mStatusBarView != null) {
   3549             dumpBarTransitions(pw, "mStatusBarView", mStatusBarView.getBarTransitions());
   3550         }
   3551 
   3552         pw.print("  mMediaSessionManager=");
   3553         pw.println(mMediaSessionManager);
   3554         pw.print("  mMediaNotificationKey=");
   3555         pw.println(mMediaNotificationKey);
   3556         pw.print("  mMediaController=");
   3557         pw.print(mMediaController);
   3558         if (mMediaController != null) {
   3559             pw.print(" state=" + mMediaController.getPlaybackState());
   3560         }
   3561         pw.println();
   3562         pw.print("  mMediaMetadata=");
   3563         pw.print(mMediaMetadata);
   3564         if (mMediaMetadata != null) {
   3565             pw.print(" title=" + mMediaMetadata.getText(MediaMetadata.METADATA_KEY_TITLE));
   3566         }
   3567         pw.println();
   3568 
   3569         pw.println("  Panels: ");
   3570         if (mNotificationPanel != null) {
   3571             pw.println("    mNotificationPanel=" +
   3572                 mNotificationPanel + " params=" + mNotificationPanel.getLayoutParams().debug(""));
   3573             pw.print  ("      ");
   3574             mNotificationPanel.dump(fd, pw, args);
   3575         }
   3576         pw.println("  mStackScroller: ");
   3577         if (mStackScroller != null) {
   3578             pw.print  ("      ");
   3579             mStackScroller.dump(fd, pw, args);
   3580         }
   3581         pw.println("  Theme:");
   3582         if (mOverlayManager == null) {
   3583             pw.println("    overlay manager not initialized!");
   3584         } else {
   3585             pw.println("    dark overlay on: " + isUsingDarkTheme());
   3586         }
   3587         final boolean lightWpTheme = mContext.getThemeResId() == R.style.Theme_SystemUI_Light;
   3588         pw.println("    light wallpaper theme: " + lightWpTheme);
   3589 
   3590         DozeLog.dump(pw);
   3591 
   3592         if (mFingerprintUnlockController != null) {
   3593             mFingerprintUnlockController.dump(pw);
   3594         }
   3595 
   3596         if (mScrimController != null) {
   3597             mScrimController.dump(pw);
   3598         }
   3599 
   3600         if (DUMPTRUCK) {
   3601             synchronized (mNotificationData) {
   3602                 mNotificationData.dump(pw, "  ");
   3603             }
   3604 
   3605             if (false) {
   3606                 pw.println("see the logcat for a dump of the views we have created.");
   3607                 // must happen on ui thread
   3608                 mHandler.post(new Runnable() {
   3609                         @Override
   3610                         public void run() {
   3611                             mStatusBarView.getLocationOnScreen(mAbsPos);
   3612                             Log.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
   3613                                     + ") " + mStatusBarView.getWidth() + "x"
   3614                                     + getStatusBarHeight());
   3615                             mStatusBarView.debug();
   3616                         }
   3617                     });
   3618             }
   3619         }
   3620 
   3621         if (DEBUG_GESTURES) {
   3622             pw.print("  status bar gestures: ");
   3623             mGestureRec.dump(fd, pw, args);
   3624         }
   3625 
   3626         if (mHeadsUpManager != null) {
   3627             mHeadsUpManager.dump(fd, pw, args);
   3628         } else {
   3629             pw.println("  mHeadsUpManager: null");
   3630         }
   3631         if (mGroupManager != null) {
   3632             mGroupManager.dump(fd, pw, args);
   3633         } else {
   3634             pw.println("  mGroupManager: null");
   3635         }
   3636 
   3637         if (mLightBarController != null) {
   3638             mLightBarController.dump(fd, pw, args);
   3639         }
   3640 
   3641         if (KeyguardUpdateMonitor.getInstance(mContext) != null) {
   3642             KeyguardUpdateMonitor.getInstance(mContext).dump(fd, pw, args);
   3643         }
   3644 
   3645         FalsingManager.getInstance(mContext).dump(pw);
   3646         FalsingLog.dump(pw);
   3647 
   3648         pw.println("SharedPreferences:");
   3649         for (Map.Entry<String, ?> entry : Prefs.getAll(mContext).entrySet()) {
   3650             pw.print("  "); pw.print(entry.getKey()); pw.print("="); pw.println(entry.getValue());
   3651         }
   3652     }
   3653 
   3654     static void dumpBarTransitions(PrintWriter pw, String var, BarTransitions transitions) {
   3655         pw.print("  "); pw.print(var); pw.print(".BarTransitions.mMode=");
   3656         pw.println(BarTransitions.modeToString(transitions.getMode()));
   3657     }
   3658 
   3659     public void createAndAddWindows() {
   3660         addStatusBarWindow();
   3661     }
   3662 
   3663     private void addStatusBarWindow() {
   3664         makeStatusBarView();
   3665         mStatusBarWindowManager = Dependency.get(StatusBarWindowManager.class);
   3666         mRemoteInputController = new RemoteInputController(mHeadsUpManager);
   3667         mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());
   3668     }
   3669 
   3670     // called by makeStatusbar and also by PhoneStatusBarView
   3671     void updateDisplaySize() {
   3672         mDisplay.getMetrics(mDisplayMetrics);
   3673         mDisplay.getSize(mCurrentDisplaySize);
   3674         if (DEBUG_GESTURES) {
   3675             mGestureRec.tag("display",
   3676                     String.format("%dx%d", mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels));
   3677         }
   3678     }
   3679 
   3680     float getDisplayDensity() {
   3681         return mDisplayMetrics.density;
   3682     }
   3683 
   3684     public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned,
   3685             boolean dismissShade) {
   3686         startActivityDismissingKeyguard(intent, onlyProvisioned, dismissShade,
   3687                 false /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */);
   3688     }
   3689 
   3690     public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned,
   3691             final boolean dismissShade, final boolean disallowEnterPictureInPictureWhileLaunching,
   3692             final Callback callback) {
   3693         if (onlyProvisioned && !isDeviceProvisioned()) return;
   3694 
   3695         final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity(
   3696                 mContext, intent, mCurrentUserId);
   3697         Runnable runnable = new Runnable() {
   3698             @Override
   3699             public void run() {
   3700                 mAssistManager.hideAssist();
   3701                 intent.setFlags(
   3702                         Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
   3703                 int result = ActivityManager.START_CANCELED;
   3704                 ActivityOptions options = new ActivityOptions(getActivityOptions());
   3705                 options.setDisallowEnterPictureInPictureWhileLaunching(
   3706                         disallowEnterPictureInPictureWhileLaunching);
   3707                 if (intent == KeyguardBottomAreaView.INSECURE_CAMERA_INTENT) {
   3708                     // Normally an activity will set it's requested rotation
   3709                     // animation on its window. However when launching an activity
   3710                     // causes the orientation to change this is too late. In these cases
   3711                     // the default animation is used. This doesn't look good for
   3712                     // the camera (as it rotates the camera contents out of sync
   3713                     // with physical reality). So, we ask the WindowManager to
   3714                     // force the crossfade animation if an orientation change
   3715                     // happens to occur during the launch.
   3716                     options.setRotationAnimationHint(
   3717                             WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS);
   3718                 }
   3719                 try {
   3720                     result = ActivityManager.getService().startActivityAsUser(
   3721                             null, mContext.getBasePackageName(),
   3722                             intent,
   3723                             intent.resolveTypeIfNeeded(mContext.getContentResolver()),
   3724                             null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null,
   3725                             options.toBundle(), UserHandle.CURRENT.getIdentifier());
   3726                 } catch (RemoteException e) {
   3727                     Log.w(TAG, "Unable to start activity", e);
   3728                 }
   3729                 if (callback != null) {
   3730                     callback.onActivityStarted(result);
   3731                 }
   3732             }
   3733         };
   3734         Runnable cancelRunnable = new Runnable() {
   3735             @Override
   3736             public void run() {
   3737                 if (callback != null) {
   3738                     callback.onActivityStarted(ActivityManager.START_CANCELED);
   3739                 }
   3740             }
   3741         };
   3742         executeRunnableDismissingKeyguard(runnable, cancelRunnable, dismissShade,
   3743                 afterKeyguardGone, true /* deferred */);
   3744     }
   3745 
   3746     public void readyForKeyguardDone() {
   3747         mStatusBarKeyguardViewManager.readyForKeyguardDone();
   3748     }
   3749 
   3750     public void executeRunnableDismissingKeyguard(final Runnable runnable,
   3751             final Runnable cancelAction,
   3752             final boolean dismissShade,
   3753             final boolean afterKeyguardGone,
   3754             final boolean deferred) {
   3755         dismissKeyguardThenExecute(() -> {
   3756             if (runnable != null) {
   3757                 if (mStatusBarKeyguardViewManager.isShowing()
   3758                         && mStatusBarKeyguardViewManager.isOccluded()) {
   3759                     mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(runnable);
   3760                 } else {
   3761                     AsyncTask.execute(runnable);
   3762                 }
   3763             }
   3764             if (dismissShade) {
   3765                 if (mExpandedVisible) {
   3766                     animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */,
   3767                             true /* delayed*/);
   3768                 } else {
   3769 
   3770                     // Do it after DismissAction has been processed to conserve the needed ordering.
   3771                     mHandler.post(this::runPostCollapseRunnables);
   3772                 }
   3773             } else if (isInLaunchTransition() && mNotificationPanel.isLaunchTransitionFinished()) {
   3774 
   3775                 // We are not dismissing the shade, but the launch transition is already finished,
   3776                 // so nobody will call readyForKeyguardDone anymore. Post it such that
   3777                 // keyguardDonePending gets called first.
   3778                 mHandler.post(mStatusBarKeyguardViewManager::readyForKeyguardDone);
   3779             }
   3780             return deferred;
   3781         }, cancelAction, afterKeyguardGone);
   3782     }
   3783 
   3784     private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
   3785         @Override
   3786         public void onReceive(Context context, Intent intent) {
   3787             if (DEBUG) Log.v(TAG, "onReceive: " + intent);
   3788             String action = intent.getAction();
   3789             if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
   3790                 KeyboardShortcuts.dismiss();
   3791                 if (mRemoteInputController != null) {
   3792                     mRemoteInputController.closeRemoteInputs();
   3793                 }
   3794                 if (isCurrentProfile(getSendingUserId())) {
   3795                     int flags = CommandQueue.FLAG_EXCLUDE_NONE;
   3796                     String reason = intent.getStringExtra("reason");
   3797                     if (reason != null && reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) {
   3798                         flags |= CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL;
   3799                     }
   3800                     animateCollapsePanels(flags);
   3801                 }
   3802             }
   3803             else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
   3804                 finishBarAnimations();
   3805                 resetUserExpandedStates();
   3806             }
   3807             else if (DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG.equals(action)) {
   3808                 mQSPanel.showDeviceMonitoringDialog();
   3809             }
   3810         }
   3811     };
   3812 
   3813     private BroadcastReceiver mDemoReceiver = new BroadcastReceiver() {
   3814         @Override
   3815         public void onReceive(Context context, Intent intent) {
   3816             if (DEBUG) Log.v(TAG, "onReceive: " + intent);
   3817             String action = intent.getAction();
   3818             if (ACTION_DEMO.equals(action)) {
   3819                 Bundle bundle = intent.getExtras();
   3820                 if (bundle != null) {
   3821                     String command = bundle.getString("command", "").trim().toLowerCase();
   3822                     if (command.length() > 0) {
   3823                         try {
   3824                             dispatchDemoCommand(command, bundle);
   3825                         } catch (Throwable t) {
   3826                             Log.w(TAG, "Error running demo command, intent=" + intent, t);
   3827                         }
   3828                     }
   3829                 }
   3830             } else if (ACTION_FAKE_ARTWORK.equals(action)) {
   3831                 if (DEBUG_MEDIA_FAKE_ARTWORK) {
   3832                     updateMediaMetaData(true, true);
   3833                 }
   3834             }
   3835         }
   3836     };
   3837 
   3838     public void resetUserExpandedStates() {
   3839         ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
   3840         final int notificationCount = activeNotifications.size();
   3841         for (int i = 0; i < notificationCount; i++) {
   3842             NotificationData.Entry entry = activeNotifications.get(i);
   3843             if (entry.row != null) {
   3844                 entry.row.resetUserExpansion();
   3845             }
   3846         }
   3847     }
   3848 
   3849     protected void dismissKeyguardThenExecute(OnDismissAction action, boolean afterKeyguardGone) {
   3850         dismissKeyguardThenExecute(action, null /* cancelRunnable */, afterKeyguardGone);
   3851     }
   3852 
   3853     private void dismissKeyguardThenExecute(OnDismissAction action, Runnable cancelAction,
   3854             boolean afterKeyguardGone) {
   3855         if (mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_ASLEEP
   3856                 && mUnlockMethodCache.canSkipBouncer()
   3857                 && !mLeaveOpenOnKeyguardHide
   3858                 && isPulsing()) {
   3859             // Reuse the fingerprint wake-and-unlock transition if we dismiss keyguard from a pulse.
   3860             // TODO: Factor this transition out of FingerprintUnlockController.
   3861             mFingerprintUnlockController.startWakeAndUnlock(
   3862                     FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING);
   3863         }
   3864         if (mStatusBarKeyguardViewManager.isShowing()) {
   3865             mStatusBarKeyguardViewManager.dismissWithAction(action, cancelAction,
   3866                     afterKeyguardGone);
   3867         } else {
   3868             action.onDismiss();
   3869         }
   3870     }
   3871 
   3872     // SystemUIService notifies SystemBars of configuration changes, which then calls down here
   3873     @Override
   3874     public void onConfigChanged(Configuration newConfig) {
   3875         updateResources();
   3876         updateDisplaySize(); // populates mDisplayMetrics
   3877 
   3878         if (DEBUG) {
   3879             Log.v(TAG, "configuration changed: " + mContext.getResources().getConfiguration());
   3880         }
   3881 
   3882         updateRowStates();
   3883         mScreenPinningRequest.onConfigurationChanged();
   3884     }
   3885 
   3886     public void userSwitched(int newUserId) {
   3887         // Begin old BaseStatusBar.userSwitched
   3888         setHeadsUpUser(newUserId);
   3889         // End old BaseStatusBar.userSwitched
   3890         if (MULTIUSER_DEBUG) mNotificationPanelDebugText.setText("USER " + newUserId);
   3891         animateCollapsePanels();
   3892         updatePublicMode();
   3893         mNotificationData.filterAndSort();
   3894         if (mReinflateNotificationsOnUserSwitched) {
   3895             updateNotificationsOnDensityOrFontScaleChanged();
   3896             mReinflateNotificationsOnUserSwitched = false;
   3897         }
   3898         updateNotificationShade();
   3899         clearCurrentMediaNotification();
   3900         setLockscreenUser(newUserId);
   3901     }
   3902 
   3903     protected void setLockscreenUser(int newUserId) {
   3904         mLockscreenWallpaper.setCurrentUser(newUserId);
   3905         mScrimController.setCurrentUser(newUserId);
   3906         updateMediaMetaData(true, false);
   3907     }
   3908 
   3909     /**
   3910      * Reload some of our resources when the configuration changes.
   3911      *
   3912      * We don't reload everything when the configuration changes -- we probably
   3913      * should, but getting that smooth is tough.  Someday we'll fix that.  In the
   3914      * meantime, just update the things that we know change.
   3915      */
   3916     void updateResources() {
   3917         // Update the quick setting tiles
   3918         if (mQSPanel != null) {
   3919             mQSPanel.updateResources();
   3920         }
   3921 
   3922         loadDimens();
   3923 
   3924         if (mNotificationPanel != null) {
   3925             mNotificationPanel.updateResources();
   3926         }
   3927         if (mBrightnessMirrorController != null) {
   3928             mBrightnessMirrorController.updateResources();
   3929         }
   3930     }
   3931 
   3932     protected void loadDimens() {
   3933         final Resources res = mContext.getResources();
   3934 
   3935         int oldBarHeight = mNaturalBarHeight;
   3936         mNaturalBarHeight = res.getDimensionPixelSize(
   3937                 com.android.internal.R.dimen.status_bar_height);
   3938         if (mStatusBarWindowManager != null && mNaturalBarHeight != oldBarHeight) {
   3939             mStatusBarWindowManager.setBarHeight(mNaturalBarHeight);
   3940         }
   3941         mMaxAllowedKeyguardNotifications = res.getInteger(
   3942                 R.integer.keyguard_max_notification_count);
   3943 
   3944         if (DEBUG) Log.v(TAG, "defineSlots");
   3945     }
   3946 
   3947     // Visibility reporting
   3948 
   3949     protected void handleVisibleToUserChanged(boolean visibleToUser) {
   3950         if (visibleToUser) {
   3951             handleVisibleToUserChangedImpl(visibleToUser);
   3952             startNotificationLogging();
   3953         } else {
   3954             stopNotificationLogging();
   3955             handleVisibleToUserChangedImpl(visibleToUser);
   3956         }
   3957     }
   3958 
   3959     void handlePeekToExpandTransistion() {
   3960         try {
   3961             // consider the transition from peek to expanded to be a panel open,
   3962             // but not one that clears notification effects.
   3963             int notificationLoad = mNotificationData.getActiveNotifications().size();
   3964             mBarService.onPanelRevealed(false, notificationLoad);
   3965         } catch (RemoteException ex) {
   3966             // Won't fail unless the world has ended.
   3967         }
   3968     }
   3969 
   3970     /**
   3971      * The LEDs are turned off when the notification panel is shown, even just a little bit.
   3972      * See also StatusBar.setPanelExpanded for another place where we attempt to do this.
   3973      */
   3974     // Old BaseStatusBar.handleVisibileToUserChanged
   3975     private void handleVisibleToUserChangedImpl(boolean visibleToUser) {
   3976         try {
   3977             if (visibleToUser) {
   3978                 boolean pinnedHeadsUp = mHeadsUpManager.hasPinnedHeadsUp();
   3979                 boolean clearNotificationEffects =
   3980                         !isPanelFullyCollapsed() &&
   3981                         (mState == StatusBarState.SHADE || mState == StatusBarState.SHADE_LOCKED);
   3982                 int notificationLoad = mNotificationData.getActiveNotifications().size();
   3983                 if (pinnedHeadsUp && isPanelFullyCollapsed())  {
   3984                     notificationLoad = 1;
   3985                 }
   3986                 mBarService.onPanelRevealed(clearNotificationEffects, notificationLoad);
   3987             } else {
   3988                 mBarService.onPanelHidden();
   3989             }
   3990         } catch (RemoteException ex) {
   3991             // Won't fail unless the world has ended.
   3992         }
   3993     }
   3994 
   3995     private void stopNotificationLogging() {
   3996         // Report all notifications as invisible and turn down the
   3997         // reporter.
   3998         if (!mCurrentlyVisibleNotifications.isEmpty()) {
   3999             logNotificationVisibilityChanges(Collections.<NotificationVisibility>emptyList(),
   4000                     mCurrentlyVisibleNotifications);
   4001             recycleAllVisibilityObjects(mCurrentlyVisibleNotifications);
   4002         }
   4003         mHandler.removeCallbacks(mVisibilityReporter);
   4004         mStackScroller.setChildLocationsChangedListener(null);
   4005     }
   4006 
   4007     private void startNotificationLogging() {
   4008         mStackScroller.setChildLocationsChangedListener(mNotificationLocationsChangedListener);
   4009         // Some transitions like mVisibleToUser=false -> mVisibleToUser=true don't
   4010         // cause the scroller to emit child location events. Hence generate
   4011         // one ourselves to guarantee that we're reporting visible
   4012         // notifications.
   4013         // (Note that in cases where the scroller does emit events, this
   4014         // additional event doesn't break anything.)
   4015         mNotificationLocationsChangedListener.onChildLocationsChanged(mStackScroller);
   4016     }
   4017 
   4018     private void logNotificationVisibilityChanges(
   4019             Collection<NotificationVisibility> newlyVisible,
   4020             Collection<NotificationVisibility> noLongerVisible) {
   4021         if (newlyVisible.isEmpty() && noLongerVisible.isEmpty()) {
   4022             return;
   4023         }
   4024         NotificationVisibility[] newlyVisibleAr =
   4025                 newlyVisible.toArray(new NotificationVisibility[newlyVisible.size()]);
   4026         NotificationVisibility[] noLongerVisibleAr =
   4027                 noLongerVisible.toArray(new NotificationVisibility[noLongerVisible.size()]);
   4028         try {
   4029             mBarService.onNotificationVisibilityChanged(newlyVisibleAr, noLongerVisibleAr);
   4030         } catch (RemoteException e) {
   4031             // Ignore.
   4032         }
   4033 
   4034         final int N = newlyVisible.size();
   4035         if (N > 0) {
   4036             String[] newlyVisibleKeyAr = new String[N];
   4037             for (int i = 0; i < N; i++) {
   4038                 newlyVisibleKeyAr[i] = newlyVisibleAr[i].key;
   4039             }
   4040 
   4041             setNotificationsShown(newlyVisibleKeyAr);
   4042         }
   4043     }
   4044 
   4045     // State logging
   4046 
   4047     private void logStateToEventlog() {
   4048         boolean isShowing = mStatusBarKeyguardViewManager.isShowing();
   4049         boolean isOccluded = mStatusBarKeyguardViewManager.isOccluded();
   4050         boolean isBouncerShowing = mStatusBarKeyguardViewManager.isBouncerShowing();
   4051         boolean isSecure = mUnlockMethodCache.isMethodSecure();
   4052         boolean canSkipBouncer = mUnlockMethodCache.canSkipBouncer();
   4053         int stateFingerprint = getLoggingFingerprint(mState,
   4054                 isShowing,
   4055                 isOccluded,
   4056                 isBouncerShowing,
   4057                 isSecure,
   4058                 canSkipBouncer);
   4059         if (stateFingerprint != mLastLoggedStateFingerprint) {
   4060             if (mStatusBarStateLog == null) {
   4061                 mStatusBarStateLog = new LogMaker(MetricsEvent.VIEW_UNKNOWN);
   4062             }
   4063             mMetricsLogger.write(mStatusBarStateLog
   4064                     .setCategory(isBouncerShowing ? MetricsEvent.BOUNCER : MetricsEvent.LOCKSCREEN)
   4065                     .setType(isShowing ? MetricsEvent.TYPE_OPEN : MetricsEvent.TYPE_CLOSE)
   4066                     .setSubtype(isSecure ? 1 : 0));
   4067             EventLogTags.writeSysuiStatusBarState(mState,
   4068                     isShowing ? 1 : 0,
   4069                     isOccluded ? 1 : 0,
   4070                     isBouncerShowing ? 1 : 0,
   4071                     isSecure ? 1 : 0,
   4072                     canSkipBouncer ? 1 : 0);
   4073             mLastLoggedStateFingerprint = stateFingerprint;
   4074         }
   4075     }
   4076 
   4077     /**
   4078      * Returns a fingerprint of fields logged to eventlog
   4079      */
   4080     private static int getLoggingFingerprint(int statusBarState, boolean keyguardShowing,
   4081             boolean keyguardOccluded, boolean bouncerShowing, boolean secure,
   4082             boolean currentlyInsecure) {
   4083         // Reserve 8 bits for statusBarState. We'll never go higher than
   4084         // that, right? Riiiight.
   4085         return (statusBarState & 0xFF)
   4086                 | ((keyguardShowing   ? 1 : 0) <<  8)
   4087                 | ((keyguardOccluded  ? 1 : 0) <<  9)
   4088                 | ((bouncerShowing    ? 1 : 0) << 10)
   4089                 | ((secure            ? 1 : 0) << 11)
   4090                 | ((currentlyInsecure ? 1 : 0) << 12);
   4091     }
   4092 
   4093     //
   4094     // tracing
   4095     //
   4096 
   4097     void postStartTracing() {
   4098         mHandler.postDelayed(mStartTracing, 3000);
   4099     }
   4100 
   4101     void vibrate() {
   4102         android.os.Vibrator vib = (android.os.Vibrator)mContext.getSystemService(
   4103                 Context.VIBRATOR_SERVICE);
   4104         vib.vibrate(250, VIBRATION_ATTRIBUTES);
   4105     }
   4106 
   4107     Runnable mStartTracing = new Runnable() {
   4108         @Override
   4109         public void run() {
   4110             vibrate();
   4111             SystemClock.sleep(250);
   4112             Log.d(TAG, "startTracing");
   4113             android.os.Debug.startMethodTracing("/data/statusbar-traces/trace");
   4114             mHandler.postDelayed(mStopTracing, 10000);
   4115         }
   4116     };
   4117 
   4118     Runnable mStopTracing = new Runnable() {
   4119         @Override
   4120         public void run() {
   4121             android.os.Debug.stopMethodTracing();
   4122             Log.d(TAG, "stopTracing");
   4123             vibrate();
   4124         }
   4125     };
   4126 
   4127     @Override
   4128     public void postQSRunnableDismissingKeyguard(final Runnable runnable) {
   4129         mHandler.post(() -> {
   4130             mLeaveOpenOnKeyguardHide = true;
   4131             executeRunnableDismissingKeyguard(() -> mHandler.post(runnable), null, false, false,
   4132                     false);
   4133         });
   4134     }
   4135 
   4136     @Override
   4137     public void postStartActivityDismissingKeyguard(final PendingIntent intent) {
   4138         mHandler.post(() -> startPendingIntentDismissingKeyguard(intent));
   4139     }
   4140 
   4141     @Override
   4142     public void postStartActivityDismissingKeyguard(final Intent intent, int delay) {
   4143         mHandler.postDelayed(() ->
   4144                 handleStartActivityDismissingKeyguard(intent, true /*onlyProvisioned*/), delay);
   4145     }
   4146 
   4147     private void handleStartActivityDismissingKeyguard(Intent intent, boolean onlyProvisioned) {
   4148         startActivityDismissingKeyguard(intent, onlyProvisioned, true /* dismissShade */);
   4149     }
   4150 
   4151     private static class FastColorDrawable extends Drawable {
   4152         private final int mColor;
   4153 
   4154         public FastColorDrawable(int color) {
   4155             mColor = 0xff000000 | color;
   4156         }
   4157 
   4158         @Override
   4159         public void draw(Canvas canvas) {
   4160             canvas.drawColor(mColor, PorterDuff.Mode.SRC);
   4161         }
   4162 
   4163         @Override
   4164         public void setAlpha(int alpha) {
   4165         }
   4166 
   4167         @Override
   4168         public void setColorFilter(ColorFilter colorFilter) {
   4169         }
   4170 
   4171         @Override
   4172         public int getOpacity() {
   4173             return PixelFormat.OPAQUE;
   4174         }
   4175 
   4176         @Override
   4177         public void setBounds(int left, int top, int right, int bottom) {
   4178         }
   4179 
   4180         @Override
   4181         public void setBounds(Rect bounds) {
   4182         }
   4183     }
   4184 
   4185     public void destroy() {
   4186         // Begin old BaseStatusBar.destroy().
   4187         mContext.unregisterReceiver(mBaseBroadcastReceiver);
   4188         try {
   4189             mNotificationListener.unregisterAsSystemService();
   4190         } catch (RemoteException e) {
   4191             // Ignore.
   4192         }
   4193         mDeviceProvisionedController.removeCallback(mDeviceProvisionedListener);
   4194         // End old BaseStatusBar.destroy().
   4195         if (mStatusBarWindow != null) {
   4196             mWindowManager.removeViewImmediate(mStatusBarWindow);
   4197             mStatusBarWindow = null;
   4198         }
   4199         if (mNavigationBarView != null) {
   4200             mWindowManager.removeViewImmediate(mNavigationBarView);
   4201             mNavigationBarView = null;
   4202         }
   4203         mContext.unregisterReceiver(mBroadcastReceiver);
   4204         mContext.unregisterReceiver(mDemoReceiver);
   4205         mAssistManager.destroy();
   4206 
   4207         if (mQSPanel != null && mQSPanel.getHost() != null) {
   4208             mQSPanel.getHost().destroy();
   4209         }
   4210         Dependency.get(ActivityStarterDelegate.class).setActivityStarterImpl(null);
   4211         mDeviceProvisionedController.removeCallback(mUserSetupObserver);
   4212         Dependency.get(ConfigurationController.class).removeCallback(this);
   4213     }
   4214 
   4215     private boolean mDemoModeAllowed;
   4216     private boolean mDemoMode;
   4217 
   4218     @Override
   4219     public void dispatchDemoCommand(String command, Bundle args) {
   4220         if (!mDemoModeAllowed) {
   4221             mDemoModeAllowed = Settings.Global.getInt(mContext.getContentResolver(),
   4222                     DEMO_MODE_ALLOWED, 0) != 0;
   4223         }
   4224         if (!mDemoModeAllowed) return;
   4225         if (command.equals(COMMAND_ENTER)) {
   4226             mDemoMode = true;
   4227         } else if (command.equals(COMMAND_EXIT)) {
   4228             mDemoMode = false;
   4229             checkBarModes();
   4230         } else if (!mDemoMode) {
   4231             // automatically enter demo mode on first demo command
   4232             dispatchDemoCommand(COMMAND_ENTER, new Bundle());
   4233         }
   4234         boolean modeChange = command.equals(COMMAND_ENTER) || command.equals(COMMAND_EXIT);
   4235         if ((modeChange || command.equals(COMMAND_VOLUME)) && mVolumeComponent != null) {
   4236             mVolumeComponent.dispatchDemoCommand(command, args);
   4237         }
   4238         if (modeChange || command.equals(COMMAND_CLOCK)) {
   4239             dispatchDemoCommandToView(command, args, R.id.clock);
   4240         }
   4241         if (modeChange || command.equals(COMMAND_BATTERY)) {
   4242             mBatteryController.dispatchDemoCommand(command, args);
   4243         }
   4244         if (modeChange || command.equals(COMMAND_STATUS)) {
   4245             ((StatusBarIconControllerImpl) mIconController).dispatchDemoCommand(command, args);
   4246         }
   4247         if (mNetworkController != null && (modeChange || command.equals(COMMAND_NETWORK))) {
   4248             mNetworkController.dispatchDemoCommand(command, args);
   4249         }
   4250         if (modeChange || command.equals(COMMAND_NOTIFICATIONS)) {
   4251             View notifications = mStatusBarView == null ? null
   4252                     : mStatusBarView.findViewById(R.id.notification_icon_area);
   4253             if (notifications != null) {
   4254                 String visible = args.getString("visible");
   4255                 int vis = mDemoMode && "false".equals(visible) ? View.INVISIBLE : View.VISIBLE;
   4256                 notifications.setVisibility(vis);
   4257             }
   4258         }
   4259         if (command.equals(COMMAND_BARS)) {
   4260             String mode = args.getString("mode");
   4261             int barMode = "opaque".equals(mode) ? MODE_OPAQUE :
   4262                     "translucent".equals(mode) ? MODE_TRANSLUCENT :
   4263                     "semi-transparent".equals(mode) ? MODE_SEMI_TRANSPARENT :
   4264                     "transparent".equals(mode) ? MODE_TRANSPARENT :
   4265                     "warning".equals(mode) ? MODE_WARNING :
   4266                     -1;
   4267             if (barMode != -1) {
   4268                 boolean animate = true;
   4269                 if (mStatusBarView != null) {
   4270                     mStatusBarView.getBarTransitions().transitionTo(barMode, animate);
   4271                 }
   4272                 if (mNavigationBar != null) {
   4273                     mNavigationBar.getBarTransitions().transitionTo(barMode, animate);
   4274                 }
   4275             }
   4276         }
   4277     }
   4278 
   4279     private void dispatchDemoCommandToView(String command, Bundle args, int id) {
   4280         if (mStatusBarView == null) return;
   4281         View v = mStatusBarView.findViewById(id);
   4282         if (v instanceof DemoMode) {
   4283             ((DemoMode)v).dispatchDemoCommand(command, args);
   4284         }
   4285     }
   4286 
   4287     /**
   4288      * @return The {@link StatusBarState} the status bar is in.
   4289      */
   4290     public int getBarState() {
   4291         return mState;
   4292     }
   4293 
   4294     public boolean isPanelFullyCollapsed() {
   4295         return mNotificationPanel.isFullyCollapsed();
   4296     }
   4297 
   4298     public void showKeyguard() {
   4299         mKeyguardRequested = true;
   4300         mLeaveOpenOnKeyguardHide = false;
   4301         mPendingRemoteInputView = null;
   4302         updateIsKeyguard();
   4303         mAssistManager.onLockscreenShown();
   4304     }
   4305 
   4306     public boolean hideKeyguard() {
   4307         mKeyguardRequested = false;
   4308         return updateIsKeyguard();
   4309     }
   4310 
   4311     private boolean updateIsKeyguard() {
   4312         boolean wakeAndUnlocking = mFingerprintUnlockController.getMode()
   4313                 == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK;
   4314 
   4315         // For dozing, keyguard needs to be shown whenever the device is non-interactive. Otherwise
   4316         // there's no surface we can show to the user. Note that the device goes fully interactive
   4317         // late in the transition, so we also allow the device to start dozing once the screen has
   4318         // turned off fully.
   4319         boolean keyguardForDozing = mDozingRequested &&
   4320                 (!mDeviceInteractive || isGoingToSleep() && (isScreenFullyOff() || mIsKeyguard));
   4321         boolean shouldBeKeyguard = (mKeyguardRequested || keyguardForDozing) && !wakeAndUnlocking;
   4322         if (keyguardForDozing) {
   4323             updatePanelExpansionForKeyguard();
   4324         }
   4325         if (shouldBeKeyguard) {
   4326             if (isGoingToSleep()
   4327                     && mScreenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_TURNING_OFF) {
   4328                 // Delay showing the keyguard until screen turned off.
   4329             } else {
   4330                 showKeyguardImpl();
   4331             }
   4332         } else {
   4333             return hideKeyguardImpl();
   4334         }
   4335         return false;
   4336     }
   4337 
   4338     public void showKeyguardImpl() {
   4339         mIsKeyguard = true;
   4340         if (mLaunchTransitionFadingAway) {
   4341             mNotificationPanel.animate().cancel();
   4342             onLaunchTransitionFadingEnded();
   4343         }
   4344         mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
   4345         if (mUserSwitcherController != null && mUserSwitcherController.useFullscreenUserSwitcher()) {
   4346             setBarState(StatusBarState.FULLSCREEN_USER_SWITCHER);
   4347         } else {
   4348             setBarState(StatusBarState.KEYGUARD);
   4349         }
   4350         updateKeyguardState(false /* goingToFullShade */, false /* fromShadeLocked */);
   4351         updatePanelExpansionForKeyguard();
   4352         if (mDraggedDownRow != null) {
   4353             mDraggedDownRow.setUserLocked(false);
   4354             mDraggedDownRow.notifyHeightChanged(false  /* needsAnimation */);
   4355             mDraggedDownRow = null;
   4356         }
   4357     }
   4358 
   4359     private void updatePanelExpansionForKeyguard() {
   4360         if (mState == StatusBarState.KEYGUARD && mFingerprintUnlockController.getMode()
   4361                 != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK) {
   4362             instantExpandNotificationsPanel();
   4363         } else if (mState == StatusBarState.FULLSCREEN_USER_SWITCHER) {
   4364             instantCollapseNotificationPanel();
   4365         }
   4366     }
   4367 
   4368     private void onLaunchTransitionFadingEnded() {
   4369         mNotificationPanel.setAlpha(1.0f);
   4370         mNotificationPanel.onAffordanceLaunchEnded();
   4371         releaseGestureWakeLock();
   4372         runLaunchTransitionEndRunnable();
   4373         mLaunchTransitionFadingAway = false;
   4374         mScrimController.forceHideScrims(false /* hide */, false /* animated */);
   4375         updateMediaMetaData(true /* metaDataChanged */, true);
   4376     }
   4377 
   4378     public boolean isCollapsing() {
   4379         return mNotificationPanel.isCollapsing();
   4380     }
   4381 
   4382     public void addPostCollapseAction(Runnable r) {
   4383         mPostCollapseRunnables.add(r);
   4384     }
   4385 
   4386     public boolean isInLaunchTransition() {
   4387         return mNotificationPanel.isLaunchTransitionRunning()
   4388                 || mNotificationPanel.isLaunchTransitionFinished();
   4389     }
   4390 
   4391     /**
   4392      * Fades the content of the keyguard away after the launch transition is done.
   4393      *
   4394      * @param beforeFading the runnable to be run when the circle is fully expanded and the fading
   4395      *                     starts
   4396      * @param endRunnable the runnable to be run when the transition is done
   4397      */
   4398     public void fadeKeyguardAfterLaunchTransition(final Runnable beforeFading,
   4399             Runnable endRunnable) {
   4400         mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
   4401         mLaunchTransitionEndRunnable = endRunnable;
   4402         Runnable hideRunnable = new Runnable() {
   4403             @Override
   4404             public void run() {
   4405                 mLaunchTransitionFadingAway = true;
   4406                 if (beforeFading != null) {
   4407                     beforeFading.run();
   4408                 }
   4409                 mScrimController.forceHideScrims(true /* hide */, false /* animated */);
   4410                 updateMediaMetaData(false, true);
   4411                 mNotificationPanel.setAlpha(1);
   4412                 mStackScroller.setParentNotFullyVisible(true);
   4413                 mNotificationPanel.animate()
   4414                         .alpha(0)
   4415                         .setStartDelay(FADE_KEYGUARD_START_DELAY)
   4416                         .setDuration(FADE_KEYGUARD_DURATION)
   4417                         .withLayer()
   4418                         .withEndAction(new Runnable() {
   4419                             @Override
   4420                             public void run() {
   4421                                 onLaunchTransitionFadingEnded();
   4422                             }
   4423                         });
   4424                 mCommandQueue.appTransitionStarting(SystemClock.uptimeMillis(),
   4425                         LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true);
   4426             }
   4427         };
   4428         if (mNotificationPanel.isLaunchTransitionRunning()) {
   4429             mNotificationPanel.setLaunchTransitionEndRunnable(hideRunnable);
   4430         } else {
   4431             hideRunnable.run();
   4432         }
   4433     }
   4434 
   4435     /**
   4436      * Fades the content of the Keyguard while we are dozing and makes it invisible when finished
   4437      * fading.
   4438      */
   4439     public void fadeKeyguardWhilePulsing() {
   4440         mNotificationPanel.notifyStartFading();
   4441         mNotificationPanel.animate()
   4442                 .alpha(0f)
   4443                 .setStartDelay(0)
   4444                 .setDuration(FADE_KEYGUARD_DURATION_PULSING)
   4445                 .setInterpolator(ScrimController.KEYGUARD_FADE_OUT_INTERPOLATOR)
   4446                 .start();
   4447     }
   4448 
   4449     /**
   4450      * Plays the animation when an activity that was occluding Keyguard goes away.
   4451      */
   4452     public void animateKeyguardUnoccluding() {
   4453         mScrimController.animateKeyguardUnoccluding(500);
   4454         mNotificationPanel.setExpandedFraction(0f);
   4455         animateExpandNotificationsPanel();
   4456     }
   4457 
   4458     /**
   4459      * Starts the timeout when we try to start the affordances on Keyguard. We usually rely that
   4460      * Keyguard goes away via fadeKeyguardAfterLaunchTransition, however, that might not happen
   4461      * because the launched app crashed or something else went wrong.
   4462      */
   4463     public void startLaunchTransitionTimeout() {
   4464         mHandler.sendEmptyMessageDelayed(MSG_LAUNCH_TRANSITION_TIMEOUT,
   4465                 LAUNCH_TRANSITION_TIMEOUT_MS);
   4466     }
   4467 
   4468     private void onLaunchTransitionTimeout() {
   4469         Log.w(TAG, "Launch transition: Timeout!");
   4470         mNotificationPanel.onAffordanceLaunchEnded();
   4471         releaseGestureWakeLock();
   4472         mNotificationPanel.resetViews();
   4473     }
   4474 
   4475     private void runLaunchTransitionEndRunnable() {
   4476         if (mLaunchTransitionEndRunnable != null) {
   4477             Runnable r = mLaunchTransitionEndRunnable;
   4478 
   4479             // mLaunchTransitionEndRunnable might call showKeyguard, which would execute it again,
   4480             // which would lead to infinite recursion. Protect against it.
   4481             mLaunchTransitionEndRunnable = null;
   4482             r.run();
   4483         }
   4484     }
   4485 
   4486     /**
   4487      * @return true if we would like to stay in the shade, false if it should go away entirely
   4488      */
   4489     public boolean hideKeyguardImpl() {
   4490         mIsKeyguard = false;
   4491         Trace.beginSection("StatusBar#hideKeyguard");
   4492         boolean staying = mLeaveOpenOnKeyguardHide;
   4493         setBarState(StatusBarState.SHADE);
   4494         View viewToClick = null;
   4495         if (mLeaveOpenOnKeyguardHide) {
   4496             if (!mKeyguardRequested) {
   4497                 mLeaveOpenOnKeyguardHide = false;
   4498             }
   4499             long delay = calculateGoingToFullShadeDelay();
   4500             mNotificationPanel.animateToFullShade(delay);
   4501             if (mDraggedDownRow != null) {
   4502                 mDraggedDownRow.setUserLocked(false);
   4503                 mDraggedDownRow = null;
   4504             }
   4505             if (!mKeyguardRequested) {
   4506                 viewToClick = mPendingRemoteInputView;
   4507                 mPendingRemoteInputView = null;
   4508             }
   4509 
   4510             // Disable layout transitions in navbar for this transition because the load is just
   4511             // too heavy for the CPU and GPU on any device.
   4512             if (mNavigationBar != null) {
   4513                 mNavigationBar.disableAnimationsDuringHide(delay);
   4514             }
   4515         } else if (!mNotificationPanel.isCollapsing()) {
   4516             instantCollapseNotificationPanel();
   4517         }
   4518         updateKeyguardState(staying, false /* fromShadeLocked */);
   4519 
   4520         if (viewToClick != null && viewToClick.isAttachedToWindow()) {
   4521             viewToClick.callOnClick();
   4522         }
   4523 
   4524         // Keyguard state has changed, but QS is not listening anymore. Make sure to update the tile
   4525         // visibilities so next time we open the panel we know the correct height already.
   4526         if (mQSPanel != null) {
   4527             mQSPanel.refreshAllTiles();
   4528         }
   4529         mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
   4530         releaseGestureWakeLock();
   4531         mNotificationPanel.onAffordanceLaunchEnded();
   4532         mNotificationPanel.animate().cancel();
   4533         mNotificationPanel.setAlpha(1f);
   4534         Trace.endSection();
   4535         return staying;
   4536     }
   4537 
   4538     private void releaseGestureWakeLock() {
   4539         if (mGestureWakeLock.isHeld()) {
   4540             mGestureWakeLock.release();
   4541         }
   4542     }
   4543 
   4544     public long calculateGoingToFullShadeDelay() {
   4545         return mKeyguardFadingAwayDelay + mKeyguardFadingAwayDuration;
   4546     }
   4547 
   4548     /**
   4549      * Notifies the status bar that Keyguard is going away very soon.
   4550      */
   4551     public void keyguardGoingAway() {
   4552 
   4553         // Treat Keyguard exit animation as an app transition to achieve nice transition for status
   4554         // bar.
   4555         mKeyguardGoingAway = true;
   4556         mKeyguardMonitor.notifyKeyguardGoingAway(true);
   4557         mCommandQueue.appTransitionPending(true);
   4558     }
   4559 
   4560     /**
   4561      * Notifies the status bar the Keyguard is fading away with the specified timings.
   4562      *
   4563      * @param startTime the start time of the animations in uptime millis
   4564      * @param delay the precalculated animation delay in miliseconds
   4565      * @param fadeoutDuration the duration of the exit animation, in milliseconds
   4566      */
   4567     public void setKeyguardFadingAway(long startTime, long delay, long fadeoutDuration) {
   4568         mKeyguardFadingAway = true;
   4569         mKeyguardFadingAwayDelay = delay;
   4570         mKeyguardFadingAwayDuration = fadeoutDuration;
   4571         mWaitingForKeyguardExit = false;
   4572         mCommandQueue.appTransitionStarting(startTime + fadeoutDuration
   4573                         - LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION,
   4574                 LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true);
   4575         recomputeDisableFlags(fadeoutDuration > 0 /* animate */);
   4576         mCommandQueue.appTransitionStarting(
   4577                     startTime - LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION,
   4578                     LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true);
   4579         mKeyguardMonitor.notifyKeyguardFadingAway(delay, fadeoutDuration);
   4580     }
   4581 
   4582     public boolean isKeyguardFadingAway() {
   4583         return mKeyguardFadingAway;
   4584     }
   4585 
   4586     /**
   4587      * Notifies that the Keyguard fading away animation is done.
   4588      */
   4589     public void finishKeyguardFadingAway() {
   4590         mKeyguardFadingAway = false;
   4591         mKeyguardGoingAway = false;
   4592         mKeyguardMonitor.notifyKeyguardDoneFading();
   4593     }
   4594 
   4595     public void stopWaitingForKeyguardExit() {
   4596         mWaitingForKeyguardExit = false;
   4597     }
   4598 
   4599     private void updatePublicMode() {
   4600         final boolean showingKeyguard = mStatusBarKeyguardViewManager.isShowing();
   4601         final boolean devicePublic = showingKeyguard
   4602                 && mStatusBarKeyguardViewManager.isSecure(mCurrentUserId);
   4603 
   4604         // Look for public mode users. Users are considered public in either case of:
   4605         //   - device keyguard is shown in secure mode;
   4606         //   - profile is locked with a work challenge.
   4607         for (int i = mCurrentProfiles.size() - 1; i >= 0; i--) {
   4608             final int userId = mCurrentProfiles.valueAt(i).id;
   4609             boolean isProfilePublic = devicePublic;
   4610             if (!devicePublic && userId != mCurrentUserId) {
   4611                 // We can't rely on KeyguardManager#isDeviceLocked() for unified profile challenge
   4612                 // due to a race condition where this code could be called before
   4613                 // TrustManagerService updates its internal records, resulting in an incorrect
   4614                 // state being cached in mLockscreenPublicMode. (b/35951989)
   4615                 if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)
   4616                         && mStatusBarKeyguardViewManager.isSecure(userId)) {
   4617                     isProfilePublic = mKeyguardManager.isDeviceLocked(userId);
   4618                 }
   4619             }
   4620             setLockscreenPublicMode(isProfilePublic, userId);
   4621         }
   4622     }
   4623 
   4624     protected void updateKeyguardState(boolean goingToFullShade, boolean fromShadeLocked) {
   4625         Trace.beginSection("StatusBar#updateKeyguardState");
   4626         if (mState == StatusBarState.KEYGUARD) {
   4627             mKeyguardIndicationController.setVisible(true);
   4628             mNotificationPanel.resetViews();
   4629             if (mKeyguardUserSwitcher != null) {
   4630                 mKeyguardUserSwitcher.setKeyguard(true, fromShadeLocked);
   4631             }
   4632             if (mStatusBarView != null) mStatusBarView.removePendingHideExpandedRunnables();
   4633             if (mAmbientIndicationContainer != null) {
   4634                 mAmbientIndicationContainer.setVisibility(View.VISIBLE);
   4635             }
   4636         } else {
   4637             mKeyguardIndicationController.setVisible(false);
   4638             if (mKeyguardUserSwitcher != null) {
   4639                 mKeyguardUserSwitcher.setKeyguard(false,
   4640                         goingToFullShade ||
   4641                         mState == StatusBarState.SHADE_LOCKED ||
   4642                         fromShadeLocked);
   4643             }
   4644             if (mAmbientIndicationContainer != null) {
   4645                 mAmbientIndicationContainer.setVisibility(View.INVISIBLE);
   4646             }
   4647         }
   4648         if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
   4649             mScrimController.setKeyguardShowing(true);
   4650         } else {
   4651             mScrimController.setKeyguardShowing(false);
   4652         }
   4653         mNotificationPanel.setBarState(mState, mKeyguardFadingAway, goingToFullShade);
   4654         updateTheme();
   4655         updateDozingState();
   4656         updatePublicMode();
   4657         updateStackScrollerState(goingToFullShade, fromShadeLocked);
   4658         updateNotifications();
   4659         checkBarModes();
   4660         updateMediaMetaData(false, mState != StatusBarState.KEYGUARD);
   4661         mKeyguardMonitor.notifyKeyguardState(mStatusBarKeyguardViewManager.isShowing(),
   4662                 mUnlockMethodCache.isMethodSecure(),
   4663                 mStatusBarKeyguardViewManager.isOccluded());
   4664         Trace.endSection();
   4665     }
   4666 
   4667     /**
   4668      * Switches theme from light to dark and vice-versa.
   4669      */
   4670     protected void updateTheme() {
   4671         final boolean inflated = mStackScroller != null;
   4672 
   4673         // The system wallpaper defines if QS should be light or dark.
   4674         WallpaperColors systemColors = mColorExtractor
   4675                 .getWallpaperColors(WallpaperManager.FLAG_SYSTEM);
   4676         final boolean useDarkTheme = systemColors != null
   4677                 && (systemColors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_THEME) != 0;
   4678         if (isUsingDarkTheme() != useDarkTheme) {
   4679             try {
   4680                 mOverlayManager.setEnabled("com.android.systemui.theme.dark",
   4681                         useDarkTheme, mCurrentUserId);
   4682             } catch (RemoteException e) {
   4683                 Log.w(TAG, "Can't change theme", e);
   4684             }
   4685         }
   4686 
   4687         // Lock wallpaper defines the color of the majority of the views, hence we'll use it
   4688         // to set our default theme.
   4689         final boolean lockDarkText = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK, true
   4690                 /* ignoreVisibility */).supportsDarkText();
   4691         final int themeResId = lockDarkText ? R.style.Theme_SystemUI_Light : R.style.Theme_SystemUI;
   4692         if (mContext.getThemeResId() != themeResId) {
   4693             mContext.setTheme(themeResId);
   4694             if (inflated) {
   4695                 reinflateViews();
   4696             }
   4697         }
   4698 
   4699         if (inflated) {
   4700             int which;
   4701             if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
   4702                 which = WallpaperManager.FLAG_LOCK;
   4703             } else {
   4704                 which = WallpaperManager.FLAG_SYSTEM;
   4705             }
   4706             final boolean useDarkText = mColorExtractor.getColors(which,
   4707                     true /* ignoreVisibility */).supportsDarkText();
   4708             mStackScroller.updateDecorViews(useDarkText);
   4709 
   4710             // Make sure we have the correct navbar/statusbar colors.
   4711             mStatusBarWindowManager.setKeyguardDark(useDarkText);
   4712         }
   4713     }
   4714 
   4715     private void updateDozingState() {
   4716         Trace.traceCounter(Trace.TRACE_TAG_APP, "dozing", mDozing ? 1 : 0);
   4717         Trace.beginSection("StatusBar#updateDozingState");
   4718         boolean animate = !mDozing && mDozeServiceHost.shouldAnimateWakeup();
   4719         mNotificationPanel.setDozing(mDozing, animate);
   4720         mStackScroller.setDark(mDozing, animate, mWakeUpTouchLocation);
   4721         mScrimController.setDozing(mDozing);
   4722         mKeyguardIndicationController.setDozing(mDozing);
   4723         mNotificationPanel.setDark(mDozing, animate);
   4724         updateQsExpansionEnabled();
   4725         mDozeScrimController.setDozing(mDozing, animate);
   4726         updateRowStates();
   4727         Trace.endSection();
   4728     }
   4729 
   4730     public void updateStackScrollerState(boolean goingToFullShade, boolean fromShadeLocked) {
   4731         if (mStackScroller == null) return;
   4732         boolean onKeyguard = mState == StatusBarState.KEYGUARD;
   4733         boolean publicMode = isAnyProfilePublicMode();
   4734         mStackScroller.setHideSensitive(publicMode, goingToFullShade);
   4735         mStackScroller.setDimmed(onKeyguard, fromShadeLocked /* animate */);
   4736         mStackScroller.setExpandingEnabled(!onKeyguard);
   4737         ActivatableNotificationView activatedChild = mStackScroller.getActivatedChild();
   4738         mStackScroller.setActivatedChild(null);
   4739         if (activatedChild != null) {
   4740             activatedChild.makeInactive(false /* animate */);
   4741         }
   4742     }
   4743 
   4744     public void userActivity() {
   4745         if (mState == StatusBarState.KEYGUARD) {
   4746             mKeyguardViewMediatorCallback.userActivity();
   4747         }
   4748     }
   4749 
   4750     public boolean interceptMediaKey(KeyEvent event) {
   4751         return mState == StatusBarState.KEYGUARD
   4752                 && mStatusBarKeyguardViewManager.interceptMediaKey(event);
   4753     }
   4754 
   4755     protected boolean shouldUnlockOnMenuPressed() {
   4756         return mDeviceInteractive && mState != StatusBarState.SHADE
   4757             && mStatusBarKeyguardViewManager.shouldDismissOnMenuPressed();
   4758     }
   4759 
   4760     public boolean onMenuPressed() {
   4761         if (shouldUnlockOnMenuPressed()) {
   4762             animateCollapsePanels(
   4763                     CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL /* flags */, true /* force */);
   4764             return true;
   4765         }
   4766         return false;
   4767     }
   4768 
   4769     public void endAffordanceLaunch() {
   4770         releaseGestureWakeLock();
   4771         mNotificationPanel.onAffordanceLaunchEnded();
   4772     }
   4773 
   4774     public boolean onBackPressed() {
   4775         if (mStatusBarKeyguardViewManager.onBackPressed()) {
   4776             return true;
   4777         }
   4778         if (mNotificationPanel.isQsExpanded()) {
   4779             if (mNotificationPanel.isQsDetailShowing()) {
   4780                 mNotificationPanel.closeQsDetail();
   4781             } else {
   4782                 mNotificationPanel.animateCloseQs();
   4783             }
   4784             return true;
   4785         }
   4786         if (mState != StatusBarState.KEYGUARD && mState != StatusBarState.SHADE_LOCKED) {
   4787             animateCollapsePanels();
   4788             return true;
   4789         }
   4790         if (mKeyguardUserSwitcher != null && mKeyguardUserSwitcher.hideIfNotSimple(true)) {
   4791             return true;
   4792         }
   4793         return false;
   4794     }
   4795 
   4796     public boolean onSpacePressed() {
   4797         if (mDeviceInteractive && mState != StatusBarState.SHADE) {
   4798             animateCollapsePanels(
   4799                     CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL /* flags */, true /* force */);
   4800             return true;
   4801         }
   4802         return false;
   4803     }
   4804 
   4805     private void showBouncerIfKeyguard() {
   4806         if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
   4807             showBouncer();
   4808         }
   4809     }
   4810 
   4811     protected void showBouncer() {
   4812         mWaitingForKeyguardExit = mStatusBarKeyguardViewManager.isShowing();
   4813         mStatusBarKeyguardViewManager.dismiss();
   4814     }
   4815 
   4816     private void instantExpandNotificationsPanel() {
   4817         // Make our window larger and the panel expanded.
   4818         makeExpandedVisible(true);
   4819         mNotificationPanel.expand(false /* animate */);
   4820         recomputeDisableFlags(false /* animate */);
   4821     }
   4822 
   4823     private void instantCollapseNotificationPanel() {
   4824         mNotificationPanel.instantCollapse();
   4825     }
   4826 
   4827     @Override
   4828     public void onActivated(ActivatableNotificationView view) {
   4829         onActivated((View)view);
   4830         mStackScroller.setActivatedChild(view);
   4831     }
   4832 
   4833     public void onActivated(View view) {
   4834         mLockscreenGestureLogger.write(
   4835                 MetricsEvent.ACTION_LS_NOTE,
   4836                 0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */);
   4837         mKeyguardIndicationController.showTransientIndication(R.string.notification_tap_again);
   4838         ActivatableNotificationView previousView = mStackScroller.getActivatedChild();
   4839         if (previousView != null) {
   4840             previousView.makeInactive(true /* animate */);
   4841         }
   4842     }
   4843 
   4844     /**
   4845      * @param state The {@link StatusBarState} to set.
   4846      */
   4847     public void setBarState(int state) {
   4848         // If we're visible and switched to SHADE_LOCKED (the user dragged
   4849         // down on the lockscreen), clear notification LED, vibration,
   4850         // ringing.
   4851         // Other transitions are covered in handleVisibleToUserChanged().
   4852         if (state != mState && mVisible && (state == StatusBarState.SHADE_LOCKED
   4853                 || (state == StatusBarState.SHADE && isGoingToNotificationShade()))) {
   4854             clearNotificationEffects();
   4855         }
   4856         if (state == StatusBarState.KEYGUARD) {
   4857             removeRemoteInputEntriesKeptUntilCollapsed();
   4858             maybeEscalateHeadsUp();
   4859         }
   4860         mState = state;
   4861         mGroupManager.setStatusBarState(state);
   4862         mHeadsUpManager.setStatusBarState(state);
   4863         mFalsingManager.setStatusBarState(state);
   4864         mStatusBarWindowManager.setStatusBarState(state);
   4865         mStackScroller.setStatusBarState(state);
   4866         updateReportRejectedTouchVisibility();
   4867         updateDozing();
   4868         updateTheme();
   4869         touchAutoDim();
   4870         mNotificationShelf.setStatusBarState(state);
   4871     }
   4872 
   4873     @Override
   4874     public void onActivationReset(ActivatableNotificationView view) {
   4875         if (view == mStackScroller.getActivatedChild()) {
   4876             mStackScroller.setActivatedChild(null);
   4877             onActivationReset((View)view);
   4878         }
   4879     }
   4880 
   4881     public void onActivationReset(View view) {
   4882         mKeyguardIndicationController.hideTransientIndication();
   4883     }
   4884 
   4885     public void onTrackingStarted() {
   4886         runPostCollapseRunnables();
   4887     }
   4888 
   4889     public void onClosingFinished() {
   4890         runPostCollapseRunnables();
   4891         if (!isPanelFullyCollapsed()) {
   4892             // if we set it not to be focusable when collapsing, we have to undo it when we aborted
   4893             // the closing
   4894             mStatusBarWindowManager.setStatusBarFocusable(true);
   4895         }
   4896     }
   4897 
   4898     public void onUnlockHintStarted() {
   4899         mFalsingManager.onUnlockHintStarted();
   4900         mKeyguardIndicationController.showTransientIndication(R.string.keyguard_unlock);
   4901     }
   4902 
   4903     public void onHintFinished() {
   4904         // Delay the reset a bit so the user can read the text.
   4905         mKeyguardIndicationController.hideTransientIndicationDelayed(HINT_RESET_DELAY_MS);
   4906     }
   4907 
   4908     public void onCameraHintStarted() {
   4909         mFalsingManager.onCameraHintStarted();
   4910         mKeyguardIndicationController.showTransientIndication(R.string.camera_hint);
   4911     }
   4912 
   4913     public void onVoiceAssistHintStarted() {
   4914         mFalsingManager.onLeftAffordanceHintStarted();
   4915         mKeyguardIndicationController.showTransientIndication(R.string.voice_hint);
   4916     }
   4917 
   4918     public void onPhoneHintStarted() {
   4919         mFalsingManager.onLeftAffordanceHintStarted();
   4920         mKeyguardIndicationController.showTransientIndication(R.string.phone_hint);
   4921     }
   4922 
   4923     public void onTrackingStopped(boolean expand) {
   4924         if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
   4925             if (!expand && !mUnlockMethodCache.canSkipBouncer()) {
   4926                 showBouncerIfKeyguard();
   4927             }
   4928         }
   4929     }
   4930 
   4931     protected int getMaxKeyguardNotifications(boolean recompute) {
   4932         if (recompute) {
   4933             mMaxKeyguardNotifications = Math.max(1,
   4934                     mNotificationPanel.computeMaxKeyguardNotifications(
   4935                             mMaxAllowedKeyguardNotifications));
   4936             return mMaxKeyguardNotifications;
   4937         }
   4938         return mMaxKeyguardNotifications;
   4939     }
   4940 
   4941     public int getMaxKeyguardNotifications() {
   4942         return getMaxKeyguardNotifications(false /* recompute */);
   4943     }
   4944 
   4945     // TODO: Figure out way to remove these.
   4946     public NavigationBarView getNavigationBarView() {
   4947         return (mNavigationBar != null ? (NavigationBarView) mNavigationBar.getView() : null);
   4948     }
   4949 
   4950     public View getNavigationBarWindow() {
   4951         return mNavigationBarView;
   4952     }
   4953 
   4954     /**
   4955      * TODO: Remove this method. Views should not be passed forward. Will cause theme issues.
   4956      * @return bottom area view
   4957      */
   4958     public KeyguardBottomAreaView getKeyguardBottomAreaView() {
   4959         return mNotificationPanel.getKeyguardBottomAreaView();
   4960     }
   4961 
   4962     // ---------------------- DragDownHelper.OnDragDownListener ------------------------------------
   4963 
   4964 
   4965     /* Only ever called as a consequence of a lockscreen expansion gesture. */
   4966     @Override
   4967     public boolean onDraggedDown(View startingChild, int dragLengthY) {
   4968         if (mState == StatusBarState.KEYGUARD
   4969                 && hasActiveNotifications() && (!isDozing() || isPulsing())) {
   4970             mLockscreenGestureLogger.write(
   4971                     MetricsEvent.ACTION_LS_SHADE,
   4972                     (int) (dragLengthY / mDisplayMetrics.density),
   4973                     0 /* velocityDp - N/A */);
   4974 
   4975             // We have notifications, go to locked shade.
   4976             goToLockedShade(startingChild);
   4977             if (startingChild instanceof ExpandableNotificationRow) {
   4978                 ExpandableNotificationRow row = (ExpandableNotificationRow) startingChild;
   4979                 row.onExpandedByGesture(true /* drag down is always an open */);
   4980             }
   4981             return true;
   4982         } else {
   4983             // abort gesture.
   4984             return false;
   4985         }
   4986     }
   4987 
   4988     @Override
   4989     public void onDragDownReset() {
   4990         mStackScroller.setDimmed(true /* dimmed */, true /* animated */);
   4991         mStackScroller.resetScrollPosition();
   4992         mStackScroller.resetCheckSnoozeLeavebehind();
   4993     }
   4994 
   4995     @Override
   4996     public void onCrossedThreshold(boolean above) {
   4997         mStackScroller.setDimmed(!above /* dimmed */, true /* animate */);
   4998     }
   4999 
   5000     @Override
   5001     public void onTouchSlopExceeded() {
   5002         mStackScroller.removeLongPressCallback();
   5003         mStackScroller.checkSnoozeLeavebehind();
   5004     }
   5005 
   5006     @Override
   5007     public void setEmptyDragAmount(float amount) {
   5008         mNotificationPanel.setEmptyDragAmount(amount);
   5009     }
   5010 
   5011     @Override
   5012     public boolean isFalsingCheckNeeded() {
   5013         return mState == StatusBarState.KEYGUARD;
   5014     }
   5015 
   5016     /**
   5017      * If secure with redaction: Show bouncer, go to unlocked shade.
   5018      *
   5019      * <p>If secure without redaction or no security: Go to {@link StatusBarState#SHADE_LOCKED}.</p>
   5020      *
   5021      * @param expandView The view to expand after going to the shade.
   5022      */
   5023     public void goToLockedShade(View expandView) {
   5024         int userId = mCurrentUserId;
   5025         ExpandableNotificationRow row = null;
   5026         if (expandView instanceof ExpandableNotificationRow) {
   5027             row = (ExpandableNotificationRow) expandView;
   5028             row.setUserExpanded(true /* userExpanded */, true /* allowChildExpansion */);
   5029             // Indicate that the group expansion is changing at this time -- this way the group
   5030             // and children backgrounds / divider animations will look correct.
   5031             row.setGroupExpansionChanging(true);
   5032             if (row.getStatusBarNotification() != null) {
   5033                 userId = row.getStatusBarNotification().getUserId();
   5034             }
   5035         }
   5036         boolean fullShadeNeedsBouncer = !userAllowsPrivateNotificationsInPublic(mCurrentUserId)
   5037                 || !mShowLockscreenNotifications || mFalsingManager.shouldEnforceBouncer();
   5038         if (isLockscreenPublicMode(userId) && fullShadeNeedsBouncer) {
   5039             mLeaveOpenOnKeyguardHide = true;
   5040             showBouncerIfKeyguard();
   5041             mDraggedDownRow = row;
   5042             mPendingRemoteInputView = null;
   5043         } else {
   5044             mNotificationPanel.animateToFullShade(0 /* delay */);
   5045             setBarState(StatusBarState.SHADE_LOCKED);
   5046             updateKeyguardState(false /* goingToFullShade */, false /* fromShadeLocked */);
   5047         }
   5048     }
   5049 
   5050     public void onLockedNotificationImportanceChange(OnDismissAction dismissAction) {
   5051         mLeaveOpenOnKeyguardHide = true;
   5052         dismissKeyguardThenExecute(dismissAction, true /* afterKeyguardGone */);
   5053     }
   5054 
   5055     protected void onLockedRemoteInput(ExpandableNotificationRow row, View clicked) {
   5056         mLeaveOpenOnKeyguardHide = true;
   5057         showBouncer();
   5058         mPendingRemoteInputView = clicked;
   5059     }
   5060 
   5061     protected void onMakeExpandedVisibleForRemoteInput(ExpandableNotificationRow row,
   5062             View clickedView) {
   5063         if (isKeyguardShowing()) {
   5064             onLockedRemoteInput(row, clickedView);
   5065         } else {
   5066             row.setUserExpanded(true);
   5067             row.getPrivateLayout().setOnExpandedVisibleListener(clickedView::performClick);
   5068         }
   5069     }
   5070 
   5071     protected boolean startWorkChallengeIfNecessary(int userId, IntentSender intendSender,
   5072             String notificationKey) {
   5073         // Clear pending remote view, as we do not want to trigger pending remote input view when
   5074         // it's called by other code
   5075         mPendingWorkRemoteInputView = null;
   5076         // Begin old BaseStatusBar.startWorkChallengeIfNecessary.
   5077         final Intent newIntent = mKeyguardManager.createConfirmDeviceCredentialIntent(null,
   5078                 null, userId);
   5079         if (newIntent == null) {
   5080             return false;
   5081         }
   5082         final Intent callBackIntent = new Intent(NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION);
   5083         callBackIntent.putExtra(Intent.EXTRA_INTENT, intendSender);
   5084         callBackIntent.putExtra(Intent.EXTRA_INDEX, notificationKey);
   5085         callBackIntent.setPackage(mContext.getPackageName());
   5086 
   5087         PendingIntent callBackPendingIntent = PendingIntent.getBroadcast(
   5088                 mContext,
   5089                 0,
   5090                 callBackIntent,
   5091                 PendingIntent.FLAG_CANCEL_CURRENT |
   5092                         PendingIntent.FLAG_ONE_SHOT |
   5093                         PendingIntent.FLAG_IMMUTABLE);
   5094         newIntent.putExtra(
   5095                 Intent.EXTRA_INTENT,
   5096                 callBackPendingIntent.getIntentSender());
   5097         try {
   5098             ActivityManager.getService().startConfirmDeviceCredentialIntent(newIntent,
   5099                     null /*options*/);
   5100         } catch (RemoteException ex) {
   5101             // ignore
   5102         }
   5103         return true;
   5104         // End old BaseStatusBar.startWorkChallengeIfNecessary.
   5105     }
   5106 
   5107     protected void onLockedWorkRemoteInput(int userId, ExpandableNotificationRow row,
   5108             View clicked) {
   5109         // Collapse notification and show work challenge
   5110         animateCollapsePanels();
   5111         startWorkChallengeIfNecessary(userId, null, null);
   5112         // Add pending remote input view after starting work challenge, as starting work challenge
   5113         // will clear all previous pending review view
   5114         mPendingWorkRemoteInputView = clicked;
   5115     }
   5116 
   5117     private boolean isAnyProfilePublicMode() {
   5118         for (int i = mCurrentProfiles.size() - 1; i >= 0; i--) {
   5119             if (isLockscreenPublicMode(mCurrentProfiles.valueAt(i).id)) {
   5120                 return true;
   5121             }
   5122         }
   5123         return false;
   5124     }
   5125 
   5126     protected void onWorkChallengeChanged() {
   5127         updatePublicMode();
   5128         updateNotifications();
   5129         if (mPendingWorkRemoteInputView != null && !isAnyProfilePublicMode()) {
   5130             // Expand notification panel and the notification row, then click on remote input view
   5131             final Runnable clickPendingViewRunnable = new Runnable() {
   5132                 @Override
   5133                 public void run() {
   5134                     final View pendingWorkRemoteInputView = mPendingWorkRemoteInputView;
   5135                     if (pendingWorkRemoteInputView == null) {
   5136                         return;
   5137                     }
   5138 
   5139                     // Climb up the hierarchy until we get to the container for this row.
   5140                     ViewParent p = pendingWorkRemoteInputView.getParent();
   5141                     while (!(p instanceof ExpandableNotificationRow)) {
   5142                         if (p == null) {
   5143                             return;
   5144                         }
   5145                         p = p.getParent();
   5146                     }
   5147 
   5148                     final ExpandableNotificationRow row = (ExpandableNotificationRow) p;
   5149                     ViewParent viewParent = row.getParent();
   5150                     if (viewParent instanceof NotificationStackScrollLayout) {
   5151                         final NotificationStackScrollLayout scrollLayout =
   5152                                 (NotificationStackScrollLayout) viewParent;
   5153                         row.makeActionsVisibile();
   5154                         row.post(new Runnable() {
   5155                             @Override
   5156                             public void run() {
   5157                                 final Runnable finishScrollingCallback = new Runnable() {
   5158                                     @Override
   5159                                     public void run() {
   5160                                         mPendingWorkRemoteInputView.callOnClick();
   5161                                         mPendingWorkRemoteInputView = null;
   5162                                         scrollLayout.setFinishScrollingCallback(null);
   5163                                     }
   5164                                 };
   5165                                 if (scrollLayout.scrollTo(row)) {
   5166                                     // It scrolls! So call it when it's finished.
   5167                                     scrollLayout.setFinishScrollingCallback(
   5168                                             finishScrollingCallback);
   5169                                 } else {
   5170                                     // It does not scroll, so call it now!
   5171                                     finishScrollingCallback.run();
   5172                                 }
   5173                             }
   5174                         });
   5175                     }
   5176                 }
   5177             };
   5178             mNotificationPanel.getViewTreeObserver().addOnGlobalLayoutListener(
   5179                     new ViewTreeObserver.OnGlobalLayoutListener() {
   5180                         @Override
   5181                         public void onGlobalLayout() {
   5182                             if (mNotificationPanel.mStatusBar.getStatusBarWindow()
   5183                                     .getHeight() != mNotificationPanel.mStatusBar
   5184                                             .getStatusBarHeight()) {
   5185                                 mNotificationPanel.getViewTreeObserver()
   5186                                         .removeOnGlobalLayoutListener(this);
   5187                                 mNotificationPanel.post(clickPendingViewRunnable);
   5188                             }
   5189                         }
   5190                     });
   5191             instantExpandNotificationsPanel();
   5192         }
   5193     }
   5194 
   5195     @Override
   5196     public void onExpandClicked(Entry clickedEntry, boolean nowExpanded) {
   5197         mHeadsUpManager.setExpanded(clickedEntry, nowExpanded);
   5198         if (mState == StatusBarState.KEYGUARD && nowExpanded) {
   5199             goToLockedShade(clickedEntry.row);
   5200         }
   5201     }
   5202 
   5203     /**
   5204      * Goes back to the keyguard after hanging around in {@link StatusBarState#SHADE_LOCKED}.
   5205      */
   5206     public void goToKeyguard() {
   5207         if (mState == StatusBarState.SHADE_LOCKED) {
   5208             mStackScroller.onGoToKeyguard();
   5209             setBarState(StatusBarState.KEYGUARD);
   5210             updateKeyguardState(false /* goingToFullShade */, true /* fromShadeLocked*/);
   5211         }
   5212     }
   5213 
   5214     public long getKeyguardFadingAwayDelay() {
   5215         return mKeyguardFadingAwayDelay;
   5216     }
   5217 
   5218     public long getKeyguardFadingAwayDuration() {
   5219         return mKeyguardFadingAwayDuration;
   5220     }
   5221 
   5222     public void setBouncerShowing(boolean bouncerShowing) {
   5223         mBouncerShowing = bouncerShowing;
   5224         if (mStatusBarView != null) mStatusBarView.setBouncerShowing(bouncerShowing);
   5225         updateHideIconsForBouncer(true /* animate */);
   5226         recomputeDisableFlags(true /* animate */);
   5227     }
   5228 
   5229     public void cancelCurrentTouch() {
   5230         if (mNotificationPanel.isTracking()) {
   5231             mStatusBarWindow.cancelCurrentTouch();
   5232             if (mState == StatusBarState.SHADE) {
   5233                 animateCollapsePanels();
   5234             }
   5235         }
   5236     }
   5237 
   5238     WakefulnessLifecycle.Observer mWakefulnessObserver = new WakefulnessLifecycle.Observer() {
   5239         @Override
   5240         public void onFinishedGoingToSleep() {
   5241             mNotificationPanel.onAffordanceLaunchEnded();
   5242             releaseGestureWakeLock();
   5243             mLaunchCameraOnScreenTurningOn = false;
   5244             mDeviceInteractive = false;
   5245             mWakeUpComingFromTouch = false;
   5246             mWakeUpTouchLocation = null;
   5247             mStackScroller.setAnimationsEnabled(false);
   5248             mVisualStabilityManager.setScreenOn(false);
   5249             updateVisibleToUser();
   5250 
   5251             // We need to disable touch events because these might
   5252             // collapse the panel after we expanded it, and thus we would end up with a blank
   5253             // Keyguard.
   5254             mNotificationPanel.setTouchDisabled(true);
   5255             mStatusBarWindow.cancelCurrentTouch();
   5256             if (mLaunchCameraOnFinishedGoingToSleep) {
   5257                 mLaunchCameraOnFinishedGoingToSleep = false;
   5258 
   5259                 // This gets executed before we will show Keyguard, so post it in order that the state
   5260                 // is correct.
   5261                 mHandler.post(new Runnable() {
   5262                     @Override
   5263                     public void run() {
   5264                         onCameraLaunchGestureDetected(mLastCameraLaunchSource);
   5265                     }
   5266                 });
   5267             }
   5268             updateIsKeyguard();
   5269         }
   5270 
   5271         @Override
   5272         public void onStartedGoingToSleep() {
   5273             notifyHeadsUpGoingToSleep();
   5274             dismissVolumeDialog();
   5275         }
   5276 
   5277         @Override
   5278         public void onStartedWakingUp() {
   5279             mDeviceInteractive = true;
   5280             mStackScroller.setAnimationsEnabled(true);
   5281             mVisualStabilityManager.setScreenOn(true);
   5282             mNotificationPanel.setTouchDisabled(false);
   5283 
   5284             maybePrepareWakeUpFromAod();
   5285 
   5286             mDozeServiceHost.stopDozing();
   5287             updateVisibleToUser();
   5288             updateIsKeyguard();
   5289         }
   5290     };
   5291 
   5292     ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() {
   5293         @Override
   5294         public void onScreenTurningOn() {
   5295             mFalsingManager.onScreenTurningOn();
   5296             mNotificationPanel.onScreenTurningOn();
   5297 
   5298             maybePrepareWakeUpFromAod();
   5299 
   5300             if (mLaunchCameraOnScreenTurningOn) {
   5301                 mNotificationPanel.launchCamera(false, mLastCameraLaunchSource);
   5302                 mLaunchCameraOnScreenTurningOn = false;
   5303             }
   5304         }
   5305 
   5306         @Override
   5307         public void onScreenTurnedOn() {
   5308             mScrimController.wakeUpFromAod();
   5309             mDozeScrimController.onScreenTurnedOn();
   5310         }
   5311 
   5312         @Override
   5313         public void onScreenTurnedOff() {
   5314             mFalsingManager.onScreenOff();
   5315             // If we pulse in from AOD, we turn the screen off first. However, updatingIsKeyguard
   5316             // in that case destroys the HeadsUpManager state, so don't do it in that case.
   5317             if (!isPulsing()) {
   5318                 updateIsKeyguard();
   5319             }
   5320         }
   5321     };
   5322 
   5323     public int getWakefulnessState() {
   5324         return mWakefulnessLifecycle.getWakefulness();
   5325     }
   5326 
   5327     private void maybePrepareWakeUpFromAod() {
   5328         int wakefulness = mWakefulnessLifecycle.getWakefulness();
   5329         if (mDozing && wakefulness == WAKEFULNESS_WAKING && !isPulsing()) {
   5330             mScrimController.prepareWakeUpFromAod();
   5331         }
   5332     }
   5333 
   5334     private void vibrateForCameraGesture() {
   5335         // Make sure to pass -1 for repeat so VibratorService doesn't stop us when going to sleep.
   5336         mVibrator.vibrate(mCameraLaunchGestureVibePattern, -1 /* repeat */);
   5337     }
   5338 
   5339     /**
   5340      * @return true if the screen is currently fully off, i.e. has finished turning off and has
   5341      *         since not started turning on.
   5342      */
   5343     public boolean isScreenFullyOff() {
   5344         return mScreenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_OFF;
   5345     }
   5346 
   5347     @Override
   5348     public void showScreenPinningRequest(int taskId) {
   5349         if (mKeyguardMonitor.isShowing()) {
   5350             // Don't allow apps to trigger this from keyguard.
   5351             return;
   5352         }
   5353         // Show screen pinning request, since this comes from an app, show 'no thanks', button.
   5354         showScreenPinningRequest(taskId, true);
   5355     }
   5356 
   5357     public void showScreenPinningRequest(int taskId, boolean allowCancel) {
   5358         mScreenPinningRequest.showPrompt(taskId, allowCancel);
   5359     }
   5360 
   5361     public boolean hasActiveNotifications() {
   5362         return !mNotificationData.getActiveNotifications().isEmpty();
   5363     }
   5364 
   5365     public void wakeUpIfDozing(long time, View where) {
   5366         if (mDozing) {
   5367             PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
   5368             pm.wakeUp(time, "com.android.systemui:NODOZE");
   5369             mWakeUpComingFromTouch = true;
   5370             where.getLocationInWindow(mTmpInt2);
   5371             mWakeUpTouchLocation = new PointF(mTmpInt2[0] + where.getWidth() / 2,
   5372                     mTmpInt2[1] + where.getHeight() / 2);
   5373             mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested();
   5374             mFalsingManager.onScreenOnFromTouch();
   5375         }
   5376     }
   5377 
   5378     @Override
   5379     public void appTransitionCancelled() {
   5380         EventBus.getDefault().send(new AppTransitionFinishedEvent());
   5381     }
   5382 
   5383     @Override
   5384     public void appTransitionFinished() {
   5385         EventBus.getDefault().send(new AppTransitionFinishedEvent());
   5386     }
   5387 
   5388     @Override
   5389     public void onCameraLaunchGestureDetected(int source) {
   5390         mLastCameraLaunchSource = source;
   5391         if (isGoingToSleep()) {
   5392             if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Finish going to sleep before launching camera");
   5393             mLaunchCameraOnFinishedGoingToSleep = true;
   5394             return;
   5395         }
   5396         if (!mNotificationPanel.canCameraGestureBeLaunched(
   5397                 mStatusBarKeyguardViewManager.isShowing() && mExpandedVisible)) {
   5398             if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Can't launch camera right now, mExpandedVisible: " +
   5399                     mExpandedVisible);
   5400             return;
   5401         }
   5402         if (!mDeviceInteractive) {
   5403             PowerManager pm = mContext.getSystemService(PowerManager.class);
   5404             pm.wakeUp(SystemClock.uptimeMillis(), "com.android.systemui:CAMERA_GESTURE");
   5405             mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested();
   5406         }
   5407         vibrateForCameraGesture();
   5408         if (!mStatusBarKeyguardViewManager.isShowing()) {
   5409             startActivityDismissingKeyguard(KeyguardBottomAreaView.INSECURE_CAMERA_INTENT,
   5410                     false /* onlyProvisioned */, true /* dismissShade */,
   5411                     true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */);
   5412         } else {
   5413             if (!mDeviceInteractive) {
   5414                 // Avoid flickering of the scrim when we instant launch the camera and the bouncer
   5415                 // comes on.
   5416                 mScrimController.dontAnimateBouncerChangesUntilNextFrame();
   5417                 mGestureWakeLock.acquire(LAUNCH_TRANSITION_TIMEOUT_MS + 1000L);
   5418             }
   5419             if (isScreenTurningOnOrOn()) {
   5420                 if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Launching camera");
   5421                 mNotificationPanel.launchCamera(mDeviceInteractive /* animate */, source);
   5422             } else {
   5423                 // We need to defer the camera launch until the screen comes on, since otherwise
   5424                 // we will dismiss us too early since we are waiting on an activity to be drawn and
   5425                 // incorrectly get notified because of the screen on event (which resumes and pauses
   5426                 // some activities)
   5427                 if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Deferring until screen turns on");
   5428                 mLaunchCameraOnScreenTurningOn = true;
   5429             }
   5430         }
   5431     }
   5432 
   5433     boolean isCameraAllowedByAdmin() {
   5434         if (mDevicePolicyManager.getCameraDisabled(null, mCurrentUserId)) {
   5435             return false;
   5436         } else if (isKeyguardShowing() && isKeyguardSecure()) {
   5437             // Check if the admin has disabled the camera specifically for the keyguard
   5438             return (mDevicePolicyManager.getKeyguardDisabledFeatures(null, mCurrentUserId)
   5439                     & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) == 0;
   5440         }
   5441 
   5442         return true;
   5443     }
   5444 
   5445     private boolean isGoingToSleep() {
   5446         return mWakefulnessLifecycle.getWakefulness()
   5447                 == WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP;
   5448     }
   5449 
   5450     private boolean isScreenTurningOnOrOn() {
   5451         return mScreenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_TURNING_ON
   5452                 || mScreenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_ON;
   5453     }
   5454 
   5455     public void notifyFpAuthModeChanged() {
   5456         updateDozing();
   5457     }
   5458 
   5459     private void updateDozing() {
   5460         Trace.beginSection("StatusBar#updateDozing");
   5461         // When in wake-and-unlock while pulsing, keep dozing state until fully unlocked.
   5462         mDozing = mDozingRequested && mState == StatusBarState.KEYGUARD
   5463                 || mFingerprintUnlockController.getMode()
   5464                         == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING;
   5465         // When in wake-and-unlock we may not have received a change to mState
   5466         // but we still should not be dozing, manually set to false.
   5467         if (mFingerprintUnlockController.getMode() ==
   5468                 FingerprintUnlockController.MODE_WAKE_AND_UNLOCK) {
   5469             mDozing = false;
   5470         }
   5471         mStatusBarWindowManager.setDozing(mDozing);
   5472         mStatusBarKeyguardViewManager.setDozing(mDozing);
   5473         if (mAmbientIndicationContainer instanceof DozeReceiver) {
   5474             ((DozeReceiver) mAmbientIndicationContainer).setDozing(mDozing);
   5475         }
   5476         updateDozingState();
   5477         Trace.endSection();
   5478     }
   5479 
   5480     public boolean isKeyguardShowing() {
   5481         if (mStatusBarKeyguardViewManager == null) {
   5482             Slog.i(TAG, "isKeyguardShowing() called before startKeyguard(), returning true");
   5483             return true;
   5484         }
   5485         return mStatusBarKeyguardViewManager.isShowing();
   5486     }
   5487 
   5488     private final class DozeServiceHost implements DozeHost {
   5489         private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
   5490         private boolean mAnimateWakeup;
   5491         private boolean mIgnoreTouchWhilePulsing;
   5492 
   5493         @Override
   5494         public String toString() {
   5495             return "PSB.DozeServiceHost[mCallbacks=" + mCallbacks.size() + "]";
   5496         }
   5497 
   5498         public void firePowerSaveChanged(boolean active) {
   5499             for (Callback callback : mCallbacks) {
   5500                 callback.onPowerSaveChanged(active);
   5501             }
   5502         }
   5503 
   5504         public void fireNotificationHeadsUp() {
   5505             for (Callback callback : mCallbacks) {
   5506                 callback.onNotificationHeadsUp();
   5507             }
   5508         }
   5509 
   5510         @Override
   5511         public void addCallback(@NonNull Callback callback) {
   5512             mCallbacks.add(callback);
   5513         }
   5514 
   5515         @Override
   5516         public void removeCallback(@NonNull Callback callback) {
   5517             mCallbacks.remove(callback);
   5518         }
   5519 
   5520         @Override
   5521         public void startDozing() {
   5522             if (!mDozingRequested) {
   5523                 mDozingRequested = true;
   5524                 DozeLog.traceDozing(mContext, mDozing);
   5525                 updateDozing();
   5526                 updateIsKeyguard();
   5527             }
   5528         }
   5529 
   5530         @Override
   5531         public void pulseWhileDozing(@NonNull PulseCallback callback, int reason) {
   5532             if (reason == DozeLog.PULSE_REASON_SENSOR_LONG_PRESS) {
   5533                 mPowerManager.wakeUp(SystemClock.uptimeMillis(), "com.android.systemui:NODOZE");
   5534                 startAssist(new Bundle());
   5535                 return;
   5536             }
   5537 
   5538             mDozeScrimController.pulse(new PulseCallback() {
   5539 
   5540                 @Override
   5541                 public void onPulseStarted() {
   5542                     callback.onPulseStarted();
   5543                     Collection<HeadsUpManager.HeadsUpEntry> pulsingEntries =
   5544                             mHeadsUpManager.getAllEntries();
   5545                     if (!pulsingEntries.isEmpty()) {
   5546                         // Only pulse the stack scroller if there's actually something to show.
   5547                         // Otherwise just show the always-on screen.
   5548                         setPulsing(pulsingEntries);
   5549                     }
   5550                 }
   5551 
   5552                 @Override
   5553                 public void onPulseFinished() {
   5554                     callback.onPulseFinished();
   5555                     setPulsing(null);
   5556                 }
   5557 
   5558                 private void setPulsing(Collection<HeadsUpManager.HeadsUpEntry> pulsing) {
   5559                     mStackScroller.setPulsing(pulsing);
   5560                     mNotificationPanel.setPulsing(pulsing != null);
   5561                     mVisualStabilityManager.setPulsing(pulsing != null);
   5562                     mIgnoreTouchWhilePulsing = false;
   5563                 }
   5564             }, reason);
   5565         }
   5566 
   5567         @Override
   5568         public void stopDozing() {
   5569             if (mDozingRequested) {
   5570                 mDozingRequested = false;
   5571                 DozeLog.traceDozing(mContext, mDozing);
   5572                 updateDozing();
   5573             }
   5574         }
   5575 
   5576         @Override
   5577         public void onIgnoreTouchWhilePulsing(boolean ignore) {
   5578             if (ignore != mIgnoreTouchWhilePulsing) {
   5579                 DozeLog.tracePulseTouchDisabledByProx(mContext, ignore);
   5580             }
   5581             mIgnoreTouchWhilePulsing = ignore;
   5582             if (isDozing() && ignore) {
   5583                 mStatusBarWindow.cancelCurrentTouch();
   5584             }
   5585         }
   5586 
   5587         @Override
   5588         public void dozeTimeTick() {
   5589             mNotificationPanel.refreshTime();
   5590         }
   5591 
   5592         @Override
   5593         public boolean isPowerSaveActive() {
   5594             return mBatteryController.isPowerSave();
   5595         }
   5596 
   5597         @Override
   5598         public boolean isPulsingBlocked() {
   5599             return mFingerprintUnlockController.getMode()
   5600                     == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK;
   5601         }
   5602 
   5603         @Override
   5604         public boolean isProvisioned() {
   5605             return mDeviceProvisionedController.isDeviceProvisioned()
   5606                     && mDeviceProvisionedController.isCurrentUserSetup();
   5607         }
   5608 
   5609         @Override
   5610         public boolean isBlockingDoze() {
   5611             if (mFingerprintUnlockController.hasPendingAuthentication()) {
   5612                 Log.i(TAG, "Blocking AOD because fingerprint has authenticated");
   5613                 return true;
   5614             }
   5615             return false;
   5616         }
   5617 
   5618         @Override
   5619         public void startPendingIntentDismissingKeyguard(PendingIntent intent) {
   5620             StatusBar.this.startPendingIntentDismissingKeyguard(intent);
   5621         }
   5622 
   5623         @Override
   5624         public void abortPulsing() {
   5625             mDozeScrimController.abortPulsing();
   5626         }
   5627 
   5628         @Override
   5629         public void extendPulse() {
   5630             mDozeScrimController.extendPulse();
   5631         }
   5632 
   5633         @Override
   5634         public void setAnimateWakeup(boolean animateWakeup) {
   5635             if (mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_AWAKE
   5636                     || mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_WAKING) {
   5637                 // Too late to change the wakeup animation.
   5638                 return;
   5639             }
   5640             mAnimateWakeup = animateWakeup;
   5641         }
   5642 
   5643         @Override
   5644         public void onDoubleTap(float screenX, float screenY) {
   5645             if (screenX > 0 && screenY > 0 && mAmbientIndicationContainer != null
   5646                 && mAmbientIndicationContainer.getVisibility() == View.VISIBLE) {
   5647                 mAmbientIndicationContainer.getLocationOnScreen(mTmpInt2);
   5648                 float viewX = screenX - mTmpInt2[0];
   5649                 float viewY = screenY - mTmpInt2[1];
   5650                 if (0 <= viewX && viewX <= mAmbientIndicationContainer.getWidth()
   5651                         && 0 <= viewY && viewY <= mAmbientIndicationContainer.getHeight()) {
   5652                     dispatchDoubleTap(viewX, viewY);
   5653                 }
   5654             }
   5655         }
   5656 
   5657         @Override
   5658         public void setDozeScreenBrightness(int value) {
   5659             mStatusBarWindowManager.setDozeScreenBrightness(value);
   5660         }
   5661 
   5662         @Override
   5663         public void setAodDimmingScrim(float scrimOpacity) {
   5664             mDozeScrimController.setAodDimmingScrim(scrimOpacity);
   5665         }
   5666 
   5667         public void dispatchDoubleTap(float viewX, float viewY) {
   5668             dispatchTap(mAmbientIndicationContainer, viewX, viewY);
   5669             dispatchTap(mAmbientIndicationContainer, viewX, viewY);
   5670         }
   5671 
   5672         private void dispatchTap(View view, float x, float y) {
   5673             long now = SystemClock.elapsedRealtime();
   5674             dispatchTouchEvent(view, x, y, now, MotionEvent.ACTION_DOWN);
   5675             dispatchTouchEvent(view, x, y, now, MotionEvent.ACTION_UP);
   5676         }
   5677 
   5678         private void dispatchTouchEvent(View view, float x, float y, long now, int action) {
   5679             MotionEvent ev = MotionEvent.obtain(now, now, action, x, y, 0 /* meta */);
   5680             view.dispatchTouchEvent(ev);
   5681             ev.recycle();
   5682         }
   5683 
   5684         private boolean shouldAnimateWakeup() {
   5685             return mAnimateWakeup;
   5686         }
   5687     }
   5688 
   5689     public boolean shouldIgnoreTouch() {
   5690         return isDozing() && mDozeServiceHost.mIgnoreTouchWhilePulsing;
   5691     }
   5692 
   5693     // Begin Extra BaseStatusBar methods.
   5694 
   5695     protected CommandQueue mCommandQueue;
   5696     protected IStatusBarService mBarService;
   5697 
   5698     // all notifications
   5699     protected NotificationData mNotificationData;
   5700     protected NotificationStackScrollLayout mStackScroller;
   5701 
   5702     protected NotificationGroupManager mGroupManager = new NotificationGroupManager();
   5703 
   5704     protected RemoteInputController mRemoteInputController;
   5705 
   5706     // for heads up notifications
   5707     protected HeadsUpManager mHeadsUpManager;
   5708 
   5709     private AboveShelfObserver mAboveShelfObserver;
   5710 
   5711     // handling reordering
   5712     protected VisualStabilityManager mVisualStabilityManager = new VisualStabilityManager();
   5713 
   5714     protected int mCurrentUserId = 0;
   5715     final protected SparseArray<UserInfo> mCurrentProfiles = new SparseArray<UserInfo>();
   5716 
   5717     protected int mLayoutDirection = -1; // invalid
   5718     protected AccessibilityManager mAccessibilityManager;
   5719 
   5720     protected boolean mDeviceInteractive;
   5721 
   5722     protected boolean mVisible;
   5723     protected ArraySet<Entry> mHeadsUpEntriesToRemoveOnSwitch = new ArraySet<>();
   5724     protected ArraySet<Entry> mRemoteInputEntriesToRemoveOnCollapse = new ArraySet<>();
   5725 
   5726     /**
   5727      * Notifications with keys in this set are not actually around anymore. We kept them around
   5728      * when they were canceled in response to a remote input interaction. This allows us to show
   5729      * what you replied and allows you to continue typing into it.
   5730      */
   5731     protected ArraySet<String> mKeysKeptForRemoteInput = new ArraySet<>();
   5732 
   5733     // mScreenOnFromKeyguard && mVisible.
   5734     private boolean mVisibleToUser;
   5735 
   5736     private Locale mLocale;
   5737 
   5738     protected boolean mUseHeadsUp = false;
   5739     protected boolean mHeadsUpTicker = false;
   5740     protected boolean mDisableNotificationAlerts = false;
   5741 
   5742     protected DevicePolicyManager mDevicePolicyManager;
   5743     protected PowerManager mPowerManager;
   5744     protected StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
   5745 
   5746     // public mode, private notifications, etc
   5747     private final SparseBooleanArray mLockscreenPublicMode = new SparseBooleanArray();
   5748     private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray();
   5749     private final SparseBooleanArray mUsersAllowingNotifications = new SparseBooleanArray();
   5750 
   5751     private UserManager mUserManager;
   5752 
   5753     protected KeyguardManager mKeyguardManager;
   5754     private LockPatternUtils mLockPatternUtils;
   5755     private DeviceProvisionedController mDeviceProvisionedController
   5756             = Dependency.get(DeviceProvisionedController.class);
   5757     protected SystemServicesProxy mSystemServicesProxy;
   5758 
   5759     // UI-specific methods
   5760 
   5761     protected WindowManager mWindowManager;
   5762     protected IWindowManager mWindowManagerService;
   5763 
   5764     protected Display mDisplay;
   5765 
   5766     protected RecentsComponent mRecents;
   5767 
   5768     protected int mZenMode;
   5769 
   5770     // which notification is currently being longpress-examined by the user
   5771     private NotificationGuts mNotificationGutsExposed;
   5772     private MenuItem mGutsMenuItem;
   5773 
   5774     private KeyboardShortcuts mKeyboardShortcuts;
   5775 
   5776     protected NotificationShelf mNotificationShelf;
   5777     protected DismissView mDismissView;
   5778     protected EmptyShadeView mEmptyShadeView;
   5779 
   5780     private NotificationClicker mNotificationClicker = new NotificationClicker();
   5781 
   5782     protected AssistManager mAssistManager;
   5783 
   5784     protected boolean mVrMode;
   5785 
   5786     private Set<String> mNonBlockablePkgs;
   5787 
   5788     public boolean isDeviceInteractive() {
   5789         return mDeviceInteractive;
   5790     }
   5791 
   5792     @Override  // NotificationData.Environment
   5793     public boolean isDeviceProvisioned() {
   5794         return mDeviceProvisionedController.isDeviceProvisioned();
   5795     }
   5796 
   5797     private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
   5798         @Override
   5799         public void onVrStateChanged(boolean enabled) {
   5800             mVrMode = enabled;
   5801         }
   5802     };
   5803 
   5804     public boolean isDeviceInVrMode() {
   5805         return mVrMode;
   5806     }
   5807 
   5808     private final DeviceProvisionedListener mDeviceProvisionedListener =
   5809             new DeviceProvisionedListener() {
   5810         @Override
   5811         public void onDeviceProvisionedChanged() {
   5812             updateNotifications();
   5813         }
   5814     };
   5815 
   5816     protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
   5817         @Override
   5818         public void onChange(boolean selfChange) {
   5819             final int mode = Settings.Global.getInt(mContext.getContentResolver(),
   5820                     Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
   5821             setZenMode(mode);
   5822 
   5823             updateLockscreenNotificationSetting();
   5824         }
   5825     };
   5826 
   5827     private final ContentObserver mLockscreenSettingsObserver = new ContentObserver(mHandler) {
   5828         @Override
   5829         public void onChange(boolean selfChange) {
   5830             // We don't know which user changed LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS or
   5831             // LOCK_SCREEN_SHOW_NOTIFICATIONS, so we just dump our cache ...
   5832             mUsersAllowingPrivateNotifications.clear();
   5833             mUsersAllowingNotifications.clear();
   5834             // ... and refresh all the notifications
   5835             updateLockscreenNotificationSetting();
   5836             updateNotifications();
   5837         }
   5838     };
   5839 
   5840     private RemoteViews.OnClickHandler mOnClickHandler = new RemoteViews.OnClickHandler() {
   5841 
   5842         @Override
   5843         public boolean onClickHandler(
   5844                 final View view, final PendingIntent pendingIntent, final Intent fillInIntent) {
   5845             wakeUpIfDozing(SystemClock.uptimeMillis(), view);
   5846 
   5847 
   5848             if (handleRemoteInput(view, pendingIntent, fillInIntent)) {
   5849                 return true;
   5850             }
   5851 
   5852             if (DEBUG) {
   5853                 Log.v(TAG, "Notification click handler invoked for intent: " + pendingIntent);
   5854             }
   5855             logActionClick(view);
   5856             // The intent we are sending is for the application, which
   5857             // won't have permission to immediately start an activity after
   5858             // the user switches to home.  We know it is safe to do at this
   5859             // point, so make sure new activity switches are now allowed.
   5860             try {
   5861                 ActivityManager.getService().resumeAppSwitches();
   5862             } catch (RemoteException e) {
   5863             }
   5864             final boolean isActivity = pendingIntent.isActivity();
   5865             if (isActivity) {
   5866                 final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
   5867                 final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity(
   5868                         mContext, pendingIntent.getIntent(), mCurrentUserId);
   5869                 dismissKeyguardThenExecute(new OnDismissAction() {
   5870                     @Override
   5871                     public boolean onDismiss() {
   5872                         try {
   5873                             ActivityManager.getService().resumeAppSwitches();
   5874                         } catch (RemoteException e) {
   5875                         }
   5876 
   5877                         boolean handled = superOnClickHandler(view, pendingIntent, fillInIntent);
   5878 
   5879                         // close the shade if it was open
   5880                         if (handled && !mNotificationPanel.isFullyCollapsed()) {
   5881                             animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
   5882                                     true /* force */);
   5883                             visibilityChanged(false);
   5884                             mAssistManager.hideAssist();
   5885 
   5886                             // Wait for activity start.
   5887                             return true;
   5888                         } else {
   5889                             return false;
   5890                         }
   5891 
   5892                     }
   5893                 }, afterKeyguardGone);
   5894                 return true;
   5895             } else {
   5896                 return superOnClickHandler(view, pendingIntent, fillInIntent);
   5897             }
   5898         }
   5899 
   5900         private void logActionClick(View view) {
   5901             ViewParent parent = view.getParent();
   5902             String key = getNotificationKeyForParent(parent);
   5903             if (key == null) {
   5904                 Log.w(TAG, "Couldn't determine notification for click.");
   5905                 return;
   5906             }
   5907             int index = -1;
   5908             // If this is a default template, determine the index of the button.
   5909             if (view.getId() == com.android.internal.R.id.action0 &&
   5910                     parent != null && parent instanceof ViewGroup) {
   5911                 ViewGroup actionGroup = (ViewGroup) parent;
   5912                 index = actionGroup.indexOfChild(view);
   5913             }
   5914             try {
   5915                 mBarService.onNotificationActionClick(key, index);
   5916             } catch (RemoteException e) {
   5917                 // Ignore
   5918             }
   5919         }
   5920 
   5921         private String getNotificationKeyForParent(ViewParent parent) {
   5922             while (parent != null) {
   5923                 if (parent instanceof ExpandableNotificationRow) {
   5924                     return ((ExpandableNotificationRow) parent).getStatusBarNotification().getKey();
   5925                 }
   5926                 parent = parent.getParent();
   5927             }
   5928             return null;
   5929         }
   5930 
   5931         private boolean superOnClickHandler(View view, PendingIntent pendingIntent,
   5932                 Intent fillInIntent) {
   5933             return super.onClickHandler(view, pendingIntent, fillInIntent,
   5934                     StackId.FULLSCREEN_WORKSPACE_STACK_ID);
   5935         }
   5936 
   5937         private boolean handleRemoteInput(View view, PendingIntent pendingIntent, Intent fillInIntent) {
   5938             Object tag = view.getTag(com.android.internal.R.id.remote_input_tag);
   5939             RemoteInput[] inputs = null;
   5940             if (tag instanceof RemoteInput[]) {
   5941                 inputs = (RemoteInput[]) tag;
   5942             }
   5943 
   5944             if (inputs == null) {
   5945                 return false;
   5946             }
   5947 
   5948             RemoteInput input = null;
   5949 
   5950             for (RemoteInput i : inputs) {
   5951                 if (i.getAllowFreeFormInput()) {
   5952                     input = i;
   5953                 }
   5954             }
   5955 
   5956             if (input == null) {
   5957                 return false;
   5958             }
   5959 
   5960             ViewParent p = view.getParent();
   5961             RemoteInputView riv = null;
   5962             while (p != null) {
   5963                 if (p instanceof View) {
   5964                     View pv = (View) p;
   5965                     if (pv.isRootNamespace()) {
   5966                         riv = findRemoteInputView(pv);
   5967                         break;
   5968                     }
   5969                 }
   5970                 p = p.getParent();
   5971             }
   5972             ExpandableNotificationRow row = null;
   5973             while (p != null) {
   5974                 if (p instanceof ExpandableNotificationRow) {
   5975                     row = (ExpandableNotificationRow) p;
   5976                     break;
   5977                 }
   5978                 p = p.getParent();
   5979             }
   5980 
   5981             if (row == null) {
   5982                 return false;
   5983             }
   5984 
   5985             row.setUserExpanded(true);
   5986 
   5987             if (!mAllowLockscreenRemoteInput) {
   5988                 final int userId = pendingIntent.getCreatorUserHandle().getIdentifier();
   5989                 if (isLockscreenPublicMode(userId)) {
   5990                     onLockedRemoteInput(row, view);
   5991                     return true;
   5992                 }
   5993                 if (mUserManager.getUserInfo(userId).isManagedProfile()
   5994                         && mKeyguardManager.isDeviceLocked(userId)) {
   5995                     onLockedWorkRemoteInput(userId, row, view);
   5996                     return true;
   5997                 }
   5998             }
   5999 
   6000             if (riv == null) {
   6001                 riv = findRemoteInputView(row.getPrivateLayout().getExpandedChild());
   6002                 if (riv == null) {
   6003                     return false;
   6004                 }
   6005                 if (!row.getPrivateLayout().getExpandedChild().isShown()) {
   6006                     onMakeExpandedVisibleForRemoteInput(row, view);
   6007                     return true;
   6008                 }
   6009             }
   6010 
   6011             int width = view.getWidth();
   6012             if (view instanceof TextView) {
   6013                 // Center the reveal on the text which might be off-center from the TextView
   6014                 TextView tv = (TextView) view;
   6015                 if (tv.getLayout() != null) {
   6016                     int innerWidth = (int) tv.getLayout().getLineWidth(0);
   6017                     innerWidth += tv.getCompoundPaddingLeft() + tv.getCompoundPaddingRight();
   6018                     width = Math.min(width, innerWidth);
   6019                 }
   6020             }
   6021             int cx = view.getLeft() + width / 2;
   6022             int cy = view.getTop() + view.getHeight() / 2;
   6023             int w = riv.getWidth();
   6024             int h = riv.getHeight();
   6025             int r = Math.max(
   6026                     Math.max(cx + cy, cx + (h - cy)),
   6027                     Math.max((w - cx) + cy, (w - cx) + (h - cy)));
   6028 
   6029             riv.setRevealParameters(cx, cy, r);
   6030             riv.setPendingIntent(pendingIntent);
   6031             riv.setRemoteInput(inputs, input);
   6032             riv.focusAnimated();
   6033 
   6034             return true;
   6035         }
   6036 
   6037         private RemoteInputView findRemoteInputView(View v) {
   6038             if (v == null) {
   6039                 return null;
   6040             }
   6041             return (RemoteInputView) v.findViewWithTag(RemoteInputView.VIEW_TAG);
   6042         }
   6043     };
   6044 
   6045     private final BroadcastReceiver mBaseBroadcastReceiver = new BroadcastReceiver() {
   6046         @Override
   6047         public void onReceive(Context context, Intent intent) {
   6048             String action = intent.getAction();
   6049             if (Intent.ACTION_USER_SWITCHED.equals(action)) {
   6050                 mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
   6051                 updateCurrentProfilesCache();
   6052                 if (true) Log.v(TAG, "userId " + mCurrentUserId + " is in the house");
   6053 
   6054                 updateLockscreenNotificationSetting();
   6055 
   6056                 userSwitched(mCurrentUserId);
   6057             } else if (Intent.ACTION_USER_ADDED.equals(action)) {
   6058                 updateCurrentProfilesCache();
   6059             } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
   6060                 List<ActivityManager.RecentTaskInfo> recentTask = null;
   6061                 try {
   6062                     recentTask = ActivityManager.getService().getRecentTasks(1,
   6063                             ActivityManager.RECENT_WITH_EXCLUDED
   6064                             | ActivityManager.RECENT_INCLUDE_PROFILES,
   6065                             mCurrentUserId).getList();
   6066                 } catch (RemoteException e) {
   6067                     // Abandon hope activity manager not running.
   6068                 }
   6069                 if (recentTask != null && recentTask.size() > 0) {
   6070                     UserInfo user = mUserManager.getUserInfo(recentTask.get(0).userId);
   6071                     if (user != null && user.isManagedProfile()) {
   6072                         Toast toast = Toast.makeText(mContext,
   6073                                 R.string.managed_profile_foreground_toast,
   6074                                 Toast.LENGTH_SHORT);
   6075                         TextView text = (TextView) toast.getView().findViewById(
   6076                                 android.R.id.message);
   6077                         text.setCompoundDrawablesRelativeWithIntrinsicBounds(
   6078                                 R.drawable.stat_sys_managed_profile_status, 0, 0, 0);
   6079                         int paddingPx = mContext.getResources().getDimensionPixelSize(
   6080                                 R.dimen.managed_profile_toast_padding);
   6081                         text.setCompoundDrawablePadding(paddingPx);
   6082                         toast.show();
   6083                     }
   6084                 }
   6085             } else if (BANNER_ACTION_CANCEL.equals(action) || BANNER_ACTION_SETUP.equals(action)) {
   6086                 NotificationManager noMan = (NotificationManager)
   6087                         mContext.getSystemService(Context.NOTIFICATION_SERVICE);
   6088                 noMan.cancel(SystemMessage.NOTE_HIDDEN_NOTIFICATIONS);
   6089 
   6090                 Settings.Secure.putInt(mContext.getContentResolver(),
   6091                         Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0);
   6092                 if (BANNER_ACTION_SETUP.equals(action)) {
   6093                     animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
   6094                             true /* force */);
   6095                     mContext.startActivity(new Intent(Settings.ACTION_APP_NOTIFICATION_REDACTION)
   6096                             .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
   6097 
   6098                     );
   6099                 }
   6100             } else if (NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION.equals(action)) {
   6101                 final IntentSender intentSender = intent.getParcelableExtra(Intent.EXTRA_INTENT);
   6102                 final String notificationKey = intent.getStringExtra(Intent.EXTRA_INDEX);
   6103                 if (intentSender != null) {
   6104                     try {
   6105                         mContext.startIntentSender(intentSender, null, 0, 0, 0);
   6106                     } catch (IntentSender.SendIntentException e) {
   6107                         /* ignore */
   6108                     }
   6109                 }
   6110                 if (notificationKey != null) {
   6111                     try {
   6112                         mBarService.onNotificationClick(notificationKey);
   6113                     } catch (RemoteException e) {
   6114                         /* ignore */
   6115                     }
   6116                 }
   6117             }
   6118         }
   6119     };
   6120 
   6121     private final BroadcastReceiver mAllUsersReceiver = new BroadcastReceiver() {
   6122         @Override
   6123         public void onReceive(Context context, Intent intent) {
   6124             final String action = intent.getAction();
   6125             final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
   6126 
   6127             if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(action) &&
   6128                     isCurrentProfile(getSendingUserId())) {
   6129                 mUsersAllowingPrivateNotifications.clear();
   6130                 updateLockscreenNotificationSetting();
   6131                 updateNotifications();
   6132             } else if (Intent.ACTION_DEVICE_LOCKED_CHANGED.equals(action)) {
   6133                 if (userId != mCurrentUserId && isCurrentProfile(userId)) {
   6134                     onWorkChallengeChanged();
   6135                 }
   6136             }
   6137         }
   6138     };
   6139 
   6140     private final NotificationListenerWithPlugins mNotificationListener =
   6141             new NotificationListenerWithPlugins() {
   6142         @Override
   6143         public void onListenerConnected() {
   6144             if (DEBUG) Log.d(TAG, "onListenerConnected");
   6145             onPluginConnected();
   6146             final StatusBarNotification[] notifications = getActiveNotifications();
   6147             if (notifications == null) {
   6148                 Log.w(TAG, "onListenerConnected unable to get active notifications.");
   6149                 return;
   6150             }
   6151             final RankingMap currentRanking = getCurrentRanking();
   6152             mHandler.post(new Runnable() {
   6153                 @Override
   6154                 public void run() {
   6155                     for (StatusBarNotification sbn : notifications) {
   6156                         try {
   6157                             addNotification(sbn, currentRanking);
   6158                         } catch (InflationException e) {
   6159                             handleInflationException(sbn, e);
   6160                         }
   6161                     }
   6162                 }
   6163             });
   6164         }
   6165 
   6166         @Override
   6167         public void onNotificationPosted(final StatusBarNotification sbn,
   6168                 final RankingMap rankingMap) {
   6169             if (DEBUG) Log.d(TAG, "onNotificationPosted: " + sbn);
   6170             if (sbn != null && !onPluginNotificationPosted(sbn, rankingMap)) {
   6171                 mHandler.post(new Runnable() {
   6172                     @Override
   6173                     public void run() {
   6174                         processForRemoteInput(sbn.getNotification());
   6175                         String key = sbn.getKey();
   6176                         mKeysKeptForRemoteInput.remove(key);
   6177                         boolean isUpdate = mNotificationData.get(key) != null;
   6178                         // In case we don't allow child notifications, we ignore children of
   6179                         // notifications that have a summary, since we're not going to show them
   6180                         // anyway. This is true also when the summary is canceled,
   6181                         // because children are automatically canceled by NoMan in that case.
   6182                         if (!ENABLE_CHILD_NOTIFICATIONS
   6183                             && mGroupManager.isChildInGroupWithSummary(sbn)) {
   6184                             if (DEBUG) {
   6185                                 Log.d(TAG, "Ignoring group child due to existing summary: " + sbn);
   6186                             }
   6187 
   6188                             // Remove existing notification to avoid stale data.
   6189                             if (isUpdate) {
   6190                                 removeNotification(key, rankingMap);
   6191                             } else {
   6192                                 mNotificationData.updateRanking(rankingMap);
   6193                             }
   6194                             return;
   6195                         }
   6196                         try {
   6197                             if (isUpdate) {
   6198                                 updateNotification(sbn, rankingMap);
   6199                             } else {
   6200                                 addNotification(sbn, rankingMap);
   6201                             }
   6202                         } catch (InflationException e) {
   6203                             handleInflationException(sbn, e);
   6204                         }
   6205                     }
   6206                 });
   6207             }
   6208         }
   6209 
   6210         @Override
   6211         public void onNotificationRemoved(StatusBarNotification sbn,
   6212                 final RankingMap rankingMap) {
   6213             if (DEBUG) Log.d(TAG, "onNotificationRemoved: " + sbn);
   6214             if (sbn != null && !onPluginNotificationRemoved(sbn, rankingMap)) {
   6215                 final String key = sbn.getKey();
   6216                 mHandler.post(() -> removeNotification(key, rankingMap));
   6217             }
   6218         }
   6219 
   6220         @Override
   6221         public void onNotificationRankingUpdate(final RankingMap rankingMap) {
   6222             if (DEBUG) Log.d(TAG, "onRankingUpdate");
   6223             if (rankingMap != null) {
   6224                 RankingMap r = onPluginRankingUpdate(rankingMap);
   6225                 mHandler.post(() -> updateNotificationRanking(r));
   6226             }
   6227         }
   6228 
   6229     };
   6230 
   6231     private void updateCurrentProfilesCache() {
   6232         synchronized (mCurrentProfiles) {
   6233             mCurrentProfiles.clear();
   6234             if (mUserManager != null) {
   6235                 for (UserInfo user : mUserManager.getProfiles(mCurrentUserId)) {
   6236                     mCurrentProfiles.put(user.id, user);
   6237                 }
   6238             }
   6239         }
   6240     }
   6241 
   6242     protected void notifyUserAboutHiddenNotifications() {
   6243         if (0 != Settings.Secure.getInt(mContext.getContentResolver(),
   6244                 Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 1)) {
   6245             Log.d(TAG, "user hasn't seen notification about hidden notifications");
   6246             if (!mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())) {
   6247                 Log.d(TAG, "insecure lockscreen, skipping notification");
   6248                 Settings.Secure.putInt(mContext.getContentResolver(),
   6249                         Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0);
   6250                 return;
   6251             }
   6252             Log.d(TAG, "disabling lockecreen notifications and alerting the user");
   6253             // disable lockscreen notifications until user acts on the banner.
   6254             Settings.Secure.putInt(mContext.getContentResolver(),
   6255                     Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0);
   6256             Settings.Secure.putInt(mContext.getContentResolver(),
   6257                     Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0);
   6258 
   6259             final String packageName = mContext.getPackageName();
   6260             PendingIntent cancelIntent = PendingIntent.getBroadcast(mContext, 0,
   6261                     new Intent(BANNER_ACTION_CANCEL).setPackage(packageName),
   6262                     PendingIntent.FLAG_CANCEL_CURRENT);
   6263             PendingIntent setupIntent = PendingIntent.getBroadcast(mContext, 0,
   6264                     new Intent(BANNER_ACTION_SETUP).setPackage(packageName),
   6265                     PendingIntent.FLAG_CANCEL_CURRENT);
   6266 
   6267             final int colorRes = com.android.internal.R.color.system_notification_accent_color;
   6268             Notification.Builder note =
   6269                     new Notification.Builder(mContext, NotificationChannels.GENERAL)
   6270                             .setSmallIcon(R.drawable.ic_android)
   6271                             .setContentTitle(mContext.getString(
   6272                                     R.string.hidden_notifications_title))
   6273                             .setContentText(mContext.getString(R.string.hidden_notifications_text))
   6274                             .setOngoing(true)
   6275                             .setColor(mContext.getColor(colorRes))
   6276                             .setContentIntent(setupIntent)
   6277                             .addAction(R.drawable.ic_close,
   6278                                     mContext.getString(R.string.hidden_notifications_cancel),
   6279                                     cancelIntent)
   6280                             .addAction(R.drawable.ic_settings,
   6281                                     mContext.getString(R.string.hidden_notifications_setup),
   6282                                     setupIntent);
   6283             overrideNotificationAppName(mContext, note);
   6284 
   6285             NotificationManager noMan =
   6286                     (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
   6287             noMan.notify(SystemMessage.NOTE_HIDDEN_NOTIFICATIONS, note.build());
   6288         }
   6289     }
   6290 
   6291     @Override  // NotificationData.Environment
   6292     public boolean isNotificationForCurrentProfiles(StatusBarNotification n) {
   6293         final int thisUserId = mCurrentUserId;
   6294         final int notificationUserId = n.getUserId();
   6295         if (DEBUG && MULTIUSER_DEBUG) {
   6296             Log.v(TAG, String.format("%s: current userid: %d, notification userid: %d",
   6297                     n, thisUserId, notificationUserId));
   6298         }
   6299         return isCurrentProfile(notificationUserId);
   6300     }
   6301 
   6302     protected void setNotificationShown(StatusBarNotification n) {
   6303         setNotificationsShown(new String[]{n.getKey()});
   6304     }
   6305 
   6306     protected void setNotificationsShown(String[] keys) {
   6307         try {
   6308             mNotificationListener.setNotificationsShown(keys);
   6309         } catch (RuntimeException e) {
   6310             Log.d(TAG, "failed setNotificationsShown: ", e);
   6311         }
   6312     }
   6313 
   6314     protected boolean isCurrentProfile(int userId) {
   6315         synchronized (mCurrentProfiles) {
   6316             return userId == UserHandle.USER_ALL || mCurrentProfiles.get(userId) != null;
   6317         }
   6318     }
   6319 
   6320     @Override
   6321     public NotificationGroupManager getGroupManager() {
   6322         return mGroupManager;
   6323     }
   6324 
   6325     public boolean isMediaNotification(NotificationData.Entry entry) {
   6326         // TODO: confirm that there's a valid media key
   6327         return entry.getExpandedContentView() != null &&
   6328                entry.getExpandedContentView()
   6329                        .findViewById(com.android.internal.R.id.media_actions) != null;
   6330     }
   6331 
   6332     // The button in the guts that links to the system notification settings for that app
   6333     private void startAppNotificationSettingsActivity(String packageName, final int appUid,
   6334             final NotificationChannel channel) {
   6335         final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
   6336         intent.putExtra(Settings.EXTRA_APP_PACKAGE, packageName);
   6337         intent.putExtra(Settings.EXTRA_APP_UID, appUid);
   6338         if (channel != null) {
   6339             intent.putExtra(EXTRA_FRAGMENT_ARG_KEY, channel.getId());
   6340         }
   6341         startNotificationGutsIntent(intent, appUid);
   6342     }
   6343 
   6344     private void startNotificationGutsIntent(final Intent intent, final int appUid) {
   6345         dismissKeyguardThenExecute(new OnDismissAction() {
   6346             @Override
   6347             public boolean onDismiss() {
   6348                 AsyncTask.execute(new Runnable() {
   6349                     @Override
   6350                     public void run() {
   6351                         TaskStackBuilder.create(mContext)
   6352                                 .addNextIntentWithParentStack(intent)
   6353                                 .startActivities(getActivityOptions(),
   6354                                         new UserHandle(UserHandle.getUserId(appUid)));
   6355                     }
   6356                 });
   6357                 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */);
   6358                 return true;
   6359             }
   6360         }, false /* afterKeyguardGone */);
   6361     }
   6362 
   6363     public void setNotificationSnoozed(StatusBarNotification sbn, SnoozeOption snoozeOption) {
   6364         if (snoozeOption.getSnoozeCriterion() != null) {
   6365             mNotificationListener.snoozeNotification(sbn.getKey(),
   6366                     snoozeOption.getSnoozeCriterion().getId());
   6367         } else {
   6368             mNotificationListener.snoozeNotification(sbn.getKey(),
   6369                     snoozeOption.getMinutesToSnoozeFor() * 60 * 1000);
   6370         }
   6371     }
   6372 
   6373     private void bindGuts(final ExpandableNotificationRow row, MenuItem item) {
   6374         row.inflateGuts();
   6375         row.setGutsView(item);
   6376         final StatusBarNotification sbn = row.getStatusBarNotification();
   6377         row.setTag(sbn.getPackageName());
   6378         final NotificationGuts guts = row.getGuts();
   6379         guts.setClosedListener((NotificationGuts g) -> {
   6380             if (!g.willBeRemoved() && !row.isRemoved()) {
   6381                 mStackScroller.onHeightChanged(row, !isPanelFullyCollapsed() /* needsAnimation */);
   6382             }
   6383             if (mNotificationGutsExposed == g) {
   6384                 mNotificationGutsExposed = null;
   6385                 mGutsMenuItem = null;
   6386             }
   6387             String key = sbn.getKey();
   6388             if (key.equals(mKeyToRemoveOnGutsClosed)) {
   6389                 mKeyToRemoveOnGutsClosed = null;
   6390                 removeNotification(key, mLatestRankingMap);
   6391             }
   6392         });
   6393 
   6394         View gutsView = item.getGutsView();
   6395         if (gutsView instanceof NotificationSnooze) {
   6396             NotificationSnooze snoozeGuts = (NotificationSnooze) gutsView;
   6397             snoozeGuts.setSnoozeListener(mStackScroller.getSwipeActionHelper());
   6398             snoozeGuts.setStatusBarNotification(sbn);
   6399             snoozeGuts.setSnoozeOptions(row.getEntry().snoozeCriteria);
   6400             guts.setHeightChangedListener((NotificationGuts g) -> {
   6401                 mStackScroller.onHeightChanged(row, row.isShown() /* needsAnimation */);
   6402             });
   6403         }
   6404 
   6405         if (gutsView instanceof NotificationInfo) {
   6406             final UserHandle userHandle = sbn.getUser();
   6407             PackageManager pmUser = getPackageManagerForUser(mContext,
   6408                     userHandle.getIdentifier());
   6409             final INotificationManager iNotificationManager = INotificationManager.Stub.asInterface(
   6410                     ServiceManager.getService(Context.NOTIFICATION_SERVICE));
   6411             final String pkg = sbn.getPackageName();
   6412             NotificationInfo info = (NotificationInfo) gutsView;
   6413             // Settings link is only valid for notifications that specify a user, unless this is the
   6414             // system user.
   6415             NotificationInfo.OnSettingsClickListener onSettingsClick = null;
   6416             if (!userHandle.equals(UserHandle.ALL) || mCurrentUserId == UserHandle.USER_SYSTEM) {
   6417                 onSettingsClick = (View v, NotificationChannel channel, int appUid) -> {
   6418                     mMetricsLogger.action(MetricsEvent.ACTION_NOTE_INFO);
   6419                     guts.resetFalsingCheck();
   6420                     startAppNotificationSettingsActivity(pkg, appUid, channel);
   6421                 };
   6422             }
   6423             final NotificationInfo.OnAppSettingsClickListener onAppSettingsClick = (View v,
   6424                     Intent intent) -> {
   6425                 mMetricsLogger.action(MetricsEvent.ACTION_APP_NOTE_SETTINGS);
   6426                 guts.resetFalsingCheck();
   6427                 startNotificationGutsIntent(intent, sbn.getUid());
   6428             };
   6429             final View.OnClickListener onDoneClick = (View v) -> {
   6430                 saveAndCloseNotificationMenu(info, row, guts, v);
   6431             };
   6432             final NotificationInfo.CheckSaveListener checkSaveListener =
   6433                     (Runnable saveImportance) -> {
   6434                 // If the user has security enabled, show challenge if the setting is changed.
   6435                 if (isLockscreenPublicMode(userHandle.getIdentifier())
   6436                         && (mState == StatusBarState.KEYGUARD
   6437                                 || mState == StatusBarState.SHADE_LOCKED)) {
   6438                     onLockedNotificationImportanceChange(() -> {
   6439                         saveImportance.run();
   6440                         return true;
   6441                     });
   6442                 } else {
   6443                     saveImportance.run();
   6444                 }
   6445             };
   6446 
   6447             ArraySet<NotificationChannel> channels = new ArraySet<NotificationChannel>();
   6448             channels.add(row.getEntry().channel);
   6449             if (row.isSummaryWithChildren()) {
   6450                 // If this is a summary, then add in the children notification channels for the
   6451                 // same user and pkg.
   6452                 final List<ExpandableNotificationRow> childrenRows = row.getNotificationChildren();
   6453                 final int numChildren = childrenRows.size();
   6454                 for (int i = 0; i < numChildren; i++) {
   6455                     final ExpandableNotificationRow childRow = childrenRows.get(i);
   6456                     final NotificationChannel childChannel = childRow.getEntry().channel;
   6457                     final StatusBarNotification childSbn = childRow.getStatusBarNotification();
   6458                     if (childSbn.getUser().equals(userHandle) &&
   6459                             childSbn.getPackageName().equals(pkg)) {
   6460                         channels.add(childChannel);
   6461                     }
   6462                 }
   6463             }
   6464             try {
   6465                 info.bindNotification(pmUser, iNotificationManager, pkg, new ArrayList(channels),
   6466                         row.getEntry().channel.getImportance(), sbn, onSettingsClick,
   6467                         onAppSettingsClick, onDoneClick, checkSaveListener,
   6468                         mNonBlockablePkgs);
   6469             } catch (RemoteException e) {
   6470                 Log.e(TAG, e.toString());
   6471             }
   6472         }
   6473     }
   6474 
   6475     private void saveAndCloseNotificationMenu(NotificationInfo info,
   6476             ExpandableNotificationRow row, NotificationGuts guts, View done) {
   6477         guts.resetFalsingCheck();
   6478         int[] rowLocation = new int[2];
   6479         int[] doneLocation = new int[2];
   6480         row.getLocationOnScreen(rowLocation);
   6481         done.getLocationOnScreen(doneLocation);
   6482 
   6483         final int centerX = done.getWidth() / 2;
   6484         final int centerY = done.getHeight() / 2;
   6485         final int x = doneLocation[0] - rowLocation[0] + centerX;
   6486         final int y = doneLocation[1] - rowLocation[1] + centerY;
   6487         closeAndSaveGuts(false /* removeLeavebehind */, false /* force */,
   6488                 true /* removeControls */, x, y, true /* resetMenu */);
   6489     }
   6490 
   6491     protected SwipeHelper.LongPressListener getNotificationLongClicker() {
   6492         return new SwipeHelper.LongPressListener() {
   6493             @Override
   6494             public boolean onLongPress(View v, final int x, final int y,
   6495                     MenuItem item) {
   6496                 if (!(v instanceof ExpandableNotificationRow)) {
   6497                     return false;
   6498                 }
   6499                 if (v.getWindowToken() == null) {
   6500                     Log.e(TAG, "Trying to show notification guts, but not attached to window");
   6501                     return false;
   6502                 }
   6503 
   6504                 final ExpandableNotificationRow row = (ExpandableNotificationRow) v;
   6505                 if (row.isDark()) {
   6506                     return false;
   6507                 }
   6508                 v.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
   6509                 if (row.areGutsExposed()) {
   6510                     closeAndSaveGuts(false /* removeLeavebehind */, false /* force */,
   6511                             true /* removeControls */, -1 /* x */, -1 /* y */,
   6512                             true /* resetMenu */);
   6513                     return false;
   6514                 }
   6515                 bindGuts(row, item);
   6516                 NotificationGuts guts = row.getGuts();
   6517 
   6518                 // Assume we are a status_bar_notification_row
   6519                 if (guts == null) {
   6520                     // This view has no guts. Examples are the more card or the dismiss all view
   6521                     return false;
   6522                 }
   6523 
   6524                 mMetricsLogger.action(MetricsEvent.ACTION_NOTE_CONTROLS);
   6525 
   6526                 // ensure that it's laid but not visible until actually laid out
   6527                 guts.setVisibility(View.INVISIBLE);
   6528                 // Post to ensure the the guts are properly laid out.
   6529                 guts.post(new Runnable() {
   6530                     @Override
   6531                     public void run() {
   6532                         if (row.getWindowToken() == null) {
   6533                             Log.e(TAG, "Trying to show notification guts, but not attached to "
   6534                                     + "window");
   6535                             return;
   6536                         }
   6537                         closeAndSaveGuts(true /* removeLeavebehind */, true /* force */,
   6538                                 true /* removeControls */, -1 /* x */, -1 /* y */,
   6539                                 false /* resetMenu */);
   6540                         guts.setVisibility(View.VISIBLE);
   6541                         final double horz = Math.max(guts.getWidth() - x, x);
   6542                         final double vert = Math.max(guts.getHeight() - y, y);
   6543                         final float r = (float) Math.hypot(horz, vert);
   6544                         final Animator a
   6545                                 = ViewAnimationUtils.createCircularReveal(guts, x, y, 0, r);
   6546                         a.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
   6547                         a.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
   6548                         a.addListener(new AnimatorListenerAdapter() {
   6549                             @Override
   6550                             public void onAnimationEnd(Animator animation) {
   6551                                 super.onAnimationEnd(animation);
   6552                                 // Move the notification view back over the menu
   6553                                 row.resetTranslation();
   6554                             }
   6555                         });
   6556                         a.start();
   6557                         final boolean needsFalsingProtection =
   6558                                 (mState == StatusBarState.KEYGUARD &&
   6559                                 !mAccessibilityManager.isTouchExplorationEnabled());
   6560                         guts.setExposed(true /* exposed */, needsFalsingProtection);
   6561                         row.closeRemoteInput();
   6562                         mStackScroller.onHeightChanged(row, true /* needsAnimation */);
   6563                         mNotificationGutsExposed = guts;
   6564                         mGutsMenuItem = item;
   6565                     }
   6566                 });
   6567                 return true;
   6568             }
   6569         };
   6570     }
   6571 
   6572     /**
   6573      * Returns the exposed NotificationGuts or null if none are exposed.
   6574      */
   6575     public NotificationGuts getExposedGuts() {
   6576         return mNotificationGutsExposed;
   6577     }
   6578 
   6579     /**
   6580      * Closes guts or notification menus that might be visible and saves any changes.
   6581      *
   6582      * @param removeLeavebehinds true if leavebehinds (e.g. snooze) should be closed.
   6583      * @param force true if guts should be closed regardless of state (used for snooze only).
   6584      * @param removeControls true if controls (e.g. info) should be closed.
   6585      * @param x if closed based on touch location, this is the x touch location.
   6586      * @param y if closed based on touch location, this is the y touch location.
   6587      * @param resetMenu if any notification menus that might be revealed should be closed.
   6588      */
   6589     public void closeAndSaveGuts(boolean removeLeavebehinds, boolean force, boolean removeControls,
   6590             int x, int y, boolean resetMenu) {
   6591         if (mNotificationGutsExposed != null) {
   6592             mNotificationGutsExposed.closeControls(removeLeavebehinds, removeControls, x, y, force);
   6593         }
   6594         if (resetMenu) {
   6595             mStackScroller.resetExposedMenuView(false /* animate */, true /* force */);
   6596         }
   6597     }
   6598 
   6599     @Override
   6600     public void toggleSplitScreen() {
   6601         toggleSplitScreenMode(-1 /* metricsDockAction */, -1 /* metricsUndockAction */);
   6602     }
   6603 
   6604     @Override
   6605     public void preloadRecentApps() {
   6606         int msg = MSG_PRELOAD_RECENT_APPS;
   6607         mHandler.removeMessages(msg);
   6608         mHandler.sendEmptyMessage(msg);
   6609     }
   6610 
   6611     @Override
   6612     public void cancelPreloadRecentApps() {
   6613         int msg = MSG_CANCEL_PRELOAD_RECENT_APPS;
   6614         mHandler.removeMessages(msg);
   6615         mHandler.sendEmptyMessage(msg);
   6616     }
   6617 
   6618     @Override
   6619     public void dismissKeyboardShortcutsMenu() {
   6620         int msg = MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU;
   6621         mHandler.removeMessages(msg);
   6622         mHandler.sendEmptyMessage(msg);
   6623     }
   6624 
   6625     @Override
   6626     public void toggleKeyboardShortcutsMenu(int deviceId) {
   6627         int msg = MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU;
   6628         mHandler.removeMessages(msg);
   6629         mHandler.obtainMessage(msg, deviceId, 0).sendToTarget();
   6630     }
   6631 
   6632     @Override
   6633     public void setTopAppHidesStatusBar(boolean topAppHidesStatusBar) {
   6634         mTopHidesStatusBar = topAppHidesStatusBar;
   6635         if (!topAppHidesStatusBar && mWereIconsJustHidden) {
   6636             // Immediately update the icon hidden state, since that should only apply if we're
   6637             // staying fullscreen.
   6638             mWereIconsJustHidden = false;
   6639             recomputeDisableFlags(true);
   6640         }
   6641         updateHideIconsForBouncer(true /* animate */);
   6642     }
   6643 
   6644     protected void sendCloseSystemWindows(String reason) {
   6645         try {
   6646             ActivityManager.getService().closeSystemDialogs(reason);
   6647         } catch (RemoteException e) {
   6648         }
   6649     }
   6650 
   6651     protected void toggleKeyboardShortcuts(int deviceId) {
   6652         KeyboardShortcuts.toggle(mContext, deviceId);
   6653     }
   6654 
   6655     protected void dismissKeyboardShortcuts() {
   6656         KeyboardShortcuts.dismiss();
   6657     }
   6658 
   6659     /**
   6660      * Save the current "public" (locked and secure) state of the lockscreen.
   6661      */
   6662     public void setLockscreenPublicMode(boolean publicMode, int userId) {
   6663         mLockscreenPublicMode.put(userId, publicMode);
   6664     }
   6665 
   6666     public boolean isLockscreenPublicMode(int userId) {
   6667         if (userId == UserHandle.USER_ALL) {
   6668             return mLockscreenPublicMode.get(mCurrentUserId, false);
   6669         }
   6670         return mLockscreenPublicMode.get(userId, false);
   6671     }
   6672 
   6673     /**
   6674      * Has the given user chosen to allow notifications to be shown even when the lockscreen is in
   6675      * "public" (secure & locked) mode?
   6676      */
   6677     public boolean userAllowsNotificationsInPublic(int userHandle) {
   6678         if (userHandle == UserHandle.USER_ALL) {
   6679             return true;
   6680         }
   6681 
   6682         if (mUsersAllowingNotifications.indexOfKey(userHandle) < 0) {
   6683             final boolean allowed = 0 != Settings.Secure.getIntForUser(
   6684                     mContext.getContentResolver(),
   6685                     Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0, userHandle);
   6686             mUsersAllowingNotifications.append(userHandle, allowed);
   6687             return allowed;
   6688         }
   6689 
   6690         return mUsersAllowingNotifications.get(userHandle);
   6691     }
   6692 
   6693     /**
   6694      * Has the given user chosen to allow their private (full) notifications to be shown even
   6695      * when the lockscreen is in "public" (secure & locked) mode?
   6696      */
   6697     public boolean userAllowsPrivateNotificationsInPublic(int userHandle) {
   6698         if (userHandle == UserHandle.USER_ALL) {
   6699             return true;
   6700         }
   6701 
   6702         if (mUsersAllowingPrivateNotifications.indexOfKey(userHandle) < 0) {
   6703             final boolean allowedByUser = 0 != Settings.Secure.getIntForUser(
   6704                     mContext.getContentResolver(),
   6705                     Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0, userHandle);
   6706             final boolean allowedByDpm = adminAllowsUnredactedNotifications(userHandle);
   6707             final boolean allowed = allowedByUser && allowedByDpm;
   6708             mUsersAllowingPrivateNotifications.append(userHandle, allowed);
   6709             return allowed;
   6710         }
   6711 
   6712         return mUsersAllowingPrivateNotifications.get(userHandle);
   6713     }
   6714 
   6715     private boolean adminAllowsUnredactedNotifications(int userHandle) {
   6716         if (userHandle == UserHandle.USER_ALL) {
   6717             return true;
   6718         }
   6719         final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures(null /* admin */,
   6720                     userHandle);
   6721         return (dpmFlags & DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS) == 0;
   6722     }
   6723 
   6724     /**
   6725      * Returns true if we're on a secure lockscreen and the user wants to hide notification data.
   6726      * If so, notifications should be hidden.
   6727      */
   6728     @Override  // NotificationData.Environment
   6729     public boolean shouldHideNotifications(int userId) {
   6730         return isLockscreenPublicMode(userId) && !userAllowsNotificationsInPublic(userId)
   6731                 || (userId != mCurrentUserId && shouldHideNotifications(mCurrentUserId));
   6732     }
   6733 
   6734     /**
   6735      * Returns true if we're on a secure lockscreen and the user wants to hide notifications via
   6736      * package-specific override.
   6737      */
   6738     @Override // NotificationDate.Environment
   6739     public boolean shouldHideNotifications(String key) {
   6740         return isLockscreenPublicMode(mCurrentUserId)
   6741                 && mNotificationData.getVisibilityOverride(key) == Notification.VISIBILITY_SECRET;
   6742     }
   6743 
   6744     /**
   6745      * Returns true if we're on a secure lockscreen.
   6746      */
   6747     @Override  // NotificationData.Environment
   6748     public boolean isSecurelyLocked(int userId) {
   6749         return isLockscreenPublicMode(userId);
   6750     }
   6751 
   6752     public void onNotificationClear(StatusBarNotification notification) {
   6753         try {
   6754             mBarService.onNotificationClear(
   6755                     notification.getPackageName(),
   6756                     notification.getTag(),
   6757                     notification.getId(),
   6758                     notification.getUserId());
   6759         } catch (android.os.RemoteException ex) {
   6760             // oh well
   6761         }
   6762     }
   6763 
   6764     /**
   6765      * Called when the notification panel layouts
   6766      */
   6767     public void onPanelLaidOut() {
   6768         updateKeyguardMaxNotifications();
   6769     }
   6770 
   6771     public void updateKeyguardMaxNotifications() {
   6772         if (mState == StatusBarState.KEYGUARD) {
   6773             // Since the number of notifications is determined based on the height of the view, we
   6774             // need to update them.
   6775             int maxBefore = getMaxKeyguardNotifications(false /* recompute */);
   6776             int maxNotifications = getMaxKeyguardNotifications(true /* recompute */);
   6777             if (maxBefore != maxNotifications) {
   6778                 updateRowStates();
   6779             }
   6780         }
   6781     }
   6782 
   6783     protected void inflateViews(Entry entry, ViewGroup parent) {
   6784         PackageManager pmUser = getPackageManagerForUser(mContext,
   6785                 entry.notification.getUser().getIdentifier());
   6786 
   6787         final StatusBarNotification sbn = entry.notification;
   6788         if (entry.row != null) {
   6789             entry.reset();
   6790             updateNotification(entry, pmUser, sbn, entry.row);
   6791         } else {
   6792             new RowInflaterTask().inflate(mContext, parent, entry,
   6793                     row -> {
   6794                         bindRow(entry, pmUser, sbn, row);
   6795                         updateNotification(entry, pmUser, sbn, row);
   6796                     });
   6797         }
   6798 
   6799     }
   6800 
   6801     private void bindRow(Entry entry, PackageManager pmUser,
   6802             StatusBarNotification sbn, ExpandableNotificationRow row) {
   6803         row.setExpansionLogger(this, entry.notification.getKey());
   6804         row.setGroupManager(mGroupManager);
   6805         row.setHeadsUpManager(mHeadsUpManager);
   6806         row.setAboveShelfChangedListener(mAboveShelfObserver);
   6807         row.setRemoteInputController(mRemoteInputController);
   6808         row.setOnExpandClickListener(this);
   6809         row.setRemoteViewClickHandler(mOnClickHandler);
   6810         row.setInflationCallback(this);
   6811         row.setSecureStateProvider(this::isKeyguardCurrentlySecure);
   6812 
   6813         // Get the app name.
   6814         // Note that Notification.Builder#bindHeaderAppName has similar logic
   6815         // but since this field is used in the guts, it must be accurate.
   6816         // Therefore we will only show the application label, or, failing that, the
   6817         // package name. No substitutions.
   6818         final String pkg = sbn.getPackageName();
   6819         String appname = pkg;
   6820         try {
   6821             final ApplicationInfo info = pmUser.getApplicationInfo(pkg,
   6822                     PackageManager.MATCH_UNINSTALLED_PACKAGES
   6823                             | PackageManager.MATCH_DISABLED_COMPONENTS);
   6824             if (info != null) {
   6825                 appname = String.valueOf(pmUser.getApplicationLabel(info));
   6826             }
   6827         } catch (NameNotFoundException e) {
   6828             // Do nothing
   6829         }
   6830         row.setAppName(appname);
   6831         row.setOnDismissRunnable(() ->
   6832                 performRemoveNotification(row.getStatusBarNotification()));
   6833         row.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
   6834         if (ENABLE_REMOTE_INPUT) {
   6835             row.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
   6836         }
   6837     }
   6838 
   6839     private void updateNotification(Entry entry, PackageManager pmUser,
   6840             StatusBarNotification sbn, ExpandableNotificationRow row) {
   6841         row.setNeedsRedaction(needsRedaction(entry));
   6842         boolean isLowPriority = mNotificationData.isAmbient(sbn.getKey());
   6843         boolean isUpdate = mNotificationData.get(entry.key) != null;
   6844         boolean wasLowPriority = row.isLowPriority();
   6845         row.setIsLowPriority(isLowPriority);
   6846         row.setLowPriorityStateUpdated(isUpdate && (wasLowPriority != isLowPriority));
   6847         // bind the click event to the content area
   6848         mNotificationClicker.register(row, sbn);
   6849 
   6850         // Extract target SDK version.
   6851         try {
   6852             ApplicationInfo info = pmUser.getApplicationInfo(sbn.getPackageName(), 0);
   6853             entry.targetSdk = info.targetSdkVersion;
   6854         } catch (NameNotFoundException ex) {
   6855             Log.e(TAG, "Failed looking up ApplicationInfo for " + sbn.getPackageName(), ex);
   6856         }
   6857         row.setLegacy(entry.targetSdk >= Build.VERSION_CODES.GINGERBREAD
   6858                 && entry.targetSdk < Build.VERSION_CODES.LOLLIPOP);
   6859         entry.setIconTag(R.id.icon_is_pre_L, entry.targetSdk < Build.VERSION_CODES.LOLLIPOP);
   6860         entry.autoRedacted = entry.notification.getNotification().publicVersion == null;
   6861 
   6862         entry.row = row;
   6863         entry.row.setOnActivatedListener(this);
   6864 
   6865         boolean useIncreasedCollapsedHeight = mMessagingUtil.isImportantMessaging(sbn,
   6866                 mNotificationData.getImportance(sbn.getKey()));
   6867         boolean useIncreasedHeadsUp = useIncreasedCollapsedHeight && mPanelExpanded;
   6868         row.setUseIncreasedCollapsedHeight(useIncreasedCollapsedHeight);
   6869         row.setUseIncreasedHeadsUpHeight(useIncreasedHeadsUp);
   6870         row.updateNotification(entry);
   6871     }
   6872 
   6873     /**
   6874      * Adds RemoteInput actions from the WearableExtender; to be removed once more apps support this
   6875      * via first-class API.
   6876      *
   6877      * TODO: Remove once enough apps specify remote inputs on their own.
   6878      */
   6879     private void processForRemoteInput(Notification n) {
   6880         if (!ENABLE_REMOTE_INPUT) return;
   6881 
   6882         if (n.extras != null && n.extras.containsKey("android.wearable.EXTENSIONS") &&
   6883                 (n.actions == null || n.actions.length == 0)) {
   6884             Notification.Action viableAction = null;
   6885             Notification.WearableExtender we = new Notification.WearableExtender(n);
   6886 
   6887             List<Notification.Action> actions = we.getActions();
   6888             final int numActions = actions.size();
   6889 
   6890             for (int i = 0; i < numActions; i++) {
   6891                 Notification.Action action = actions.get(i);
   6892                 if (action == null) {
   6893                     continue;
   6894                 }
   6895                 RemoteInput[] remoteInputs = action.getRemoteInputs();
   6896                 if (remoteInputs == null) {
   6897                     continue;
   6898                 }
   6899                 for (RemoteInput ri : remoteInputs) {
   6900                     if (ri.getAllowFreeFormInput()) {
   6901                         viableAction = action;
   6902                         break;
   6903                     }
   6904                 }
   6905                 if (viableAction != null) {
   6906                     break;
   6907                 }
   6908             }
   6909 
   6910             if (viableAction != null) {
   6911                 Notification.Builder rebuilder = Notification.Builder.recoverBuilder(mContext, n);
   6912                 rebuilder.setActions(viableAction);
   6913                 rebuilder.build(); // will rewrite n
   6914             }
   6915         }
   6916     }
   6917 
   6918     public void startPendingIntentDismissingKeyguard(final PendingIntent intent) {
   6919         if (!isDeviceProvisioned()) return;
   6920 
   6921         final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
   6922         final boolean afterKeyguardGone = intent.isActivity()
   6923                 && PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
   6924                 mCurrentUserId);
   6925         dismissKeyguardThenExecute(new OnDismissAction() {
   6926             @Override
   6927             public boolean onDismiss() {
   6928                 new Thread() {
   6929                     @Override
   6930                     public void run() {
   6931                         try {
   6932                             // The intent we are sending is for the application, which
   6933                             // won't have permission to immediately start an activity after
   6934                             // the user switches to home.  We know it is safe to do at this
   6935                             // point, so make sure new activity switches are now allowed.
   6936                             ActivityManager.getService().resumeAppSwitches();
   6937                         } catch (RemoteException e) {
   6938                         }
   6939                         try {
   6940                             intent.send(null, 0, null, null, null, null, getActivityOptions());
   6941                         } catch (PendingIntent.CanceledException e) {
   6942                             // the stack trace isn't very helpful here.
   6943                             // Just log the exception message.
   6944                             Log.w(TAG, "Sending intent failed: " + e);
   6945 
   6946                             // TODO: Dismiss Keyguard.
   6947                         }
   6948                         if (intent.isActivity()) {
   6949                             mAssistManager.hideAssist();
   6950                         }
   6951                     }
   6952                 }.start();
   6953 
   6954                 if (!mNotificationPanel.isFullyCollapsed()) {
   6955                     // close the shade if it was open
   6956                     animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
   6957                             true /* force */, true /* delayed */);
   6958                     visibilityChanged(false);
   6959 
   6960                     return true;
   6961                 } else {
   6962                     return false;
   6963                 }
   6964             }
   6965         }, afterKeyguardGone);
   6966     }
   6967 
   6968 
   6969     private final class NotificationClicker implements View.OnClickListener {
   6970 
   6971         @Override
   6972         public void onClick(final View v) {
   6973             if (!(v instanceof ExpandableNotificationRow)) {
   6974                 Log.e(TAG, "NotificationClicker called on a view that is not a notification row.");
   6975                 return;
   6976             }
   6977 
   6978             wakeUpIfDozing(SystemClock.uptimeMillis(), v);
   6979 
   6980             final ExpandableNotificationRow row = (ExpandableNotificationRow) v;
   6981             final StatusBarNotification sbn = row.getStatusBarNotification();
   6982             if (sbn == null) {
   6983                 Log.e(TAG, "NotificationClicker called on an unclickable notification,");
   6984                 return;
   6985             }
   6986 
   6987             // Check if the notification is displaying the menu, if so slide notification back
   6988             if (row.getProvider() != null && row.getProvider().isMenuVisible()) {
   6989                 row.animateTranslateNotification(0);
   6990                 return;
   6991             }
   6992 
   6993             Notification notification = sbn.getNotification();
   6994             final PendingIntent intent = notification.contentIntent != null
   6995                     ? notification.contentIntent
   6996                     : notification.fullScreenIntent;
   6997             final String notificationKey = sbn.getKey();
   6998 
   6999             // Mark notification for one frame.
   7000             row.setJustClicked(true);
   7001             DejankUtils.postAfterTraversal(new Runnable() {
   7002                 @Override
   7003                 public void run() {
   7004                     row.setJustClicked(false);
   7005                 }
   7006             });
   7007 
   7008             final boolean afterKeyguardGone = intent.isActivity()
   7009                     && PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
   7010                             mCurrentUserId);
   7011             dismissKeyguardThenExecute(new OnDismissAction() {
   7012                 @Override
   7013                 public boolean onDismiss() {
   7014                     if (mHeadsUpManager != null && mHeadsUpManager.isHeadsUp(notificationKey)) {
   7015                         // Release the HUN notification to the shade.
   7016 
   7017                         if (isPanelFullyCollapsed()) {
   7018                             HeadsUpManager.setIsClickedNotification(row, true);
   7019                         }
   7020                         //
   7021                         // In most cases, when FLAG_AUTO_CANCEL is set, the notification will
   7022                         // become canceled shortly by NoMan, but we can't assume that.
   7023                         mHeadsUpManager.releaseImmediately(notificationKey);
   7024                     }
   7025                     StatusBarNotification parentToCancel = null;
   7026                     if (shouldAutoCancel(sbn) && mGroupManager.isOnlyChildInGroup(sbn)) {
   7027                         StatusBarNotification summarySbn = mGroupManager.getLogicalGroupSummary(sbn)
   7028                                         .getStatusBarNotification();
   7029                         if (shouldAutoCancel(summarySbn)) {
   7030                             parentToCancel = summarySbn;
   7031                         }
   7032                     }
   7033                     final StatusBarNotification parentToCancelFinal = parentToCancel;
   7034                     final Runnable runnable = new Runnable() {
   7035                         @Override
   7036                         public void run() {
   7037                             try {
   7038                                 // The intent we are sending is for the application, which
   7039                                 // won't have permission to immediately start an activity after
   7040                                 // the user switches to home.  We know it is safe to do at this
   7041                                 // point, so make sure new activity switches are now allowed.
   7042                                 ActivityManager.getService().resumeAppSwitches();
   7043                             } catch (RemoteException e) {
   7044                             }
   7045                             if (intent != null) {
   7046                                 // If we are launching a work activity and require to launch
   7047                                 // separate work challenge, we defer the activity action and cancel
   7048                                 // notification until work challenge is unlocked.
   7049                                 if (intent.isActivity()) {
   7050                                     final int userId = intent.getCreatorUserHandle()
   7051                                             .getIdentifier();
   7052                                     if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)
   7053                                             && mKeyguardManager.isDeviceLocked(userId)) {
   7054                                         // TODO(b/28935539): should allow certain activities to
   7055                                         // bypass work challenge
   7056                                         if (startWorkChallengeIfNecessary(userId,
   7057                                                 intent.getIntentSender(), notificationKey)) {
   7058                                             // Show work challenge, do not run PendingIntent and
   7059                                             // remove notification
   7060                                             return;
   7061                                         }
   7062                                     }
   7063                                 }
   7064                                 try {
   7065                                     intent.send(null, 0, null, null, null, null,
   7066                                             getActivityOptions());
   7067                                 } catch (PendingIntent.CanceledException e) {
   7068                                     // the stack trace isn't very helpful here.
   7069                                     // Just log the exception message.
   7070                                     Log.w(TAG, "Sending contentIntent failed: " + e);
   7071 
   7072                                     // TODO: Dismiss Keyguard.
   7073                                 }
   7074                                 if (intent.isActivity()) {
   7075                                     mAssistManager.hideAssist();
   7076                                 }
   7077                             }
   7078 
   7079                             try {
   7080                                 mBarService.onNotificationClick(notificationKey);
   7081                             } catch (RemoteException ex) {
   7082                                 // system process is dead if we're here.
   7083                             }
   7084                             if (parentToCancelFinal != null) {
   7085                                 // We have to post it to the UI thread for synchronization
   7086                                 mHandler.post(new Runnable() {
   7087                                     @Override
   7088                                     public void run() {
   7089                                         Runnable removeRunnable = new Runnable() {
   7090                                             @Override
   7091                                             public void run() {
   7092                                                 performRemoveNotification(parentToCancelFinal);
   7093                                             }
   7094                                         };
   7095                                         if (isCollapsing()) {
   7096                                             // To avoid lags we're only performing the remove
   7097                                             // after the shade was collapsed
   7098                                             addPostCollapseAction(removeRunnable);
   7099                                         } else {
   7100                                             removeRunnable.run();
   7101                                         }
   7102                                     }
   7103                                 });
   7104                             }
   7105                         }
   7106                     };
   7107 
   7108                     if (mStatusBarKeyguardViewManager.isShowing()
   7109                             && mStatusBarKeyguardViewManager.isOccluded()) {
   7110                         mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(runnable);
   7111                     } else {
   7112                         new Thread(runnable).start();
   7113                     }
   7114 
   7115                     if (!mNotificationPanel.isFullyCollapsed()) {
   7116                         // close the shade if it was open
   7117                         animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
   7118                                 true /* force */, true /* delayed */);
   7119                         visibilityChanged(false);
   7120 
   7121                         return true;
   7122                     } else {
   7123                         return false;
   7124                     }
   7125                 }
   7126             }, afterKeyguardGone);
   7127         }
   7128 
   7129         private boolean shouldAutoCancel(StatusBarNotification sbn) {
   7130             int flags = sbn.getNotification().flags;
   7131             if ((flags & Notification.FLAG_AUTO_CANCEL) != Notification.FLAG_AUTO_CANCEL) {
   7132                 return false;
   7133             }
   7134             if ((flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
   7135                 return false;
   7136             }
   7137             return true;
   7138         }
   7139 
   7140         public void register(ExpandableNotificationRow row, StatusBarNotification sbn) {
   7141             Notification notification = sbn.getNotification();
   7142             if (notification.contentIntent != null || notification.fullScreenIntent != null) {
   7143                 row.setOnClickListener(this);
   7144             } else {
   7145                 row.setOnClickListener(null);
   7146             }
   7147         }
   7148     }
   7149 
   7150     protected Bundle getActivityOptions() {
   7151         // Anything launched from the notification shade should always go into the
   7152         // fullscreen stack.
   7153         ActivityOptions options = ActivityOptions.makeBasic();
   7154         options.setLaunchStackId(StackId.FULLSCREEN_WORKSPACE_STACK_ID);
   7155         return options.toBundle();
   7156     }
   7157 
   7158     protected void visibilityChanged(boolean visible) {
   7159         if (mVisible != visible) {
   7160             mVisible = visible;
   7161             if (!visible) {
   7162                 closeAndSaveGuts(true /* removeLeavebehind */, true /* force */,
   7163                         true /* removeControls */, -1 /* x */, -1 /* y */, true /* resetMenu */);
   7164             }
   7165         }
   7166         updateVisibleToUser();
   7167     }
   7168 
   7169     protected void updateVisibleToUser() {
   7170         boolean oldVisibleToUser = mVisibleToUser;
   7171         mVisibleToUser = mVisible && mDeviceInteractive;
   7172 
   7173         if (oldVisibleToUser != mVisibleToUser) {
   7174             handleVisibleToUserChanged(mVisibleToUser);
   7175         }
   7176     }
   7177 
   7178     /**
   7179      * Clear Buzz/Beep/Blink.
   7180      */
   7181     public void clearNotificationEffects() {
   7182         try {
   7183             mBarService.clearNotificationEffects();
   7184         } catch (RemoteException e) {
   7185             // Won't fail unless the world has ended.
   7186         }
   7187     }
   7188 
   7189     /**
   7190      * Cancel this notification and tell the StatusBarManagerService / NotificationManagerService
   7191      * about the failure.
   7192      *
   7193      * WARNING: this will call back into us.  Don't hold any locks.
   7194      */
   7195     void handleNotificationError(StatusBarNotification n, String message) {
   7196         removeNotification(n.getKey(), null);
   7197         try {
   7198             mBarService.onNotificationError(n.getPackageName(), n.getTag(), n.getId(), n.getUid(),
   7199                     n.getInitialPid(), message, n.getUserId());
   7200         } catch (RemoteException ex) {
   7201             // The end is nigh.
   7202         }
   7203     }
   7204 
   7205     protected StatusBarNotification removeNotificationViews(String key, RankingMap ranking) {
   7206         NotificationData.Entry entry = mNotificationData.remove(key, ranking);
   7207         if (entry == null) {
   7208             Log.w(TAG, "removeNotification for unknown key: " + key);
   7209             return null;
   7210         }
   7211         updateNotifications();
   7212         Dependency.get(LeakDetector.class).trackGarbage(entry);
   7213         return entry.notification;
   7214     }
   7215 
   7216     protected NotificationData.Entry createNotificationViews(StatusBarNotification sbn)
   7217             throws InflationException {
   7218         if (DEBUG) {
   7219             Log.d(TAG, "createNotificationViews(notification=" + sbn);
   7220         }
   7221         NotificationData.Entry entry = new NotificationData.Entry(sbn);
   7222         Dependency.get(LeakDetector.class).trackInstance(entry);
   7223         entry.createIcons(mContext, sbn);
   7224         // Construct the expanded view.
   7225         inflateViews(entry, mStackScroller);
   7226         return entry;
   7227     }
   7228 
   7229     protected void addNotificationViews(Entry entry) {
   7230         if (entry == null) {
   7231             return;
   7232         }
   7233         // Add the expanded view and icon.
   7234         mNotificationData.add(entry);
   7235         updateNotifications();
   7236     }
   7237 
   7238     /**
   7239      * Updates expanded, dimmed and locked states of notification rows.
   7240      */
   7241     protected void updateRowStates() {
   7242         final int N = mStackScroller.getChildCount();
   7243 
   7244         int visibleNotifications = 0;
   7245         boolean onKeyguard = mState == StatusBarState.KEYGUARD;
   7246         int maxNotifications = -1;
   7247         if (onKeyguard) {
   7248             maxNotifications = getMaxKeyguardNotifications(true /* recompute */);
   7249         }
   7250         mStackScroller.setMaxDisplayedNotifications(maxNotifications);
   7251         Stack<ExpandableNotificationRow> stack = new Stack<>();
   7252         for (int i = N - 1; i >= 0; i--) {
   7253             View child = mStackScroller.getChildAt(i);
   7254             if (!(child instanceof ExpandableNotificationRow)) {
   7255                 continue;
   7256             }
   7257             stack.push((ExpandableNotificationRow) child);
   7258         }
   7259         while(!stack.isEmpty()) {
   7260             ExpandableNotificationRow row = stack.pop();
   7261             NotificationData.Entry entry = row.getEntry();
   7262             boolean isChildNotification =
   7263                     mGroupManager.isChildInGroupWithSummary(entry.notification);
   7264 
   7265             row.setOnKeyguard(onKeyguard);
   7266 
   7267             if (!onKeyguard) {
   7268                 // If mAlwaysExpandNonGroupedNotification is false, then only expand the
   7269                 // very first notification and if it's not a child of grouped notifications.
   7270                 row.setSystemExpanded(mAlwaysExpandNonGroupedNotification
   7271                         || (visibleNotifications == 0 && !isChildNotification
   7272                         && !row.isLowPriority()));
   7273             }
   7274 
   7275             entry.row.setShowAmbient(isDozing());
   7276             int userId = entry.notification.getUserId();
   7277             boolean suppressedSummary = mGroupManager.isSummaryOfSuppressedGroup(
   7278                     entry.notification) && !entry.row.isRemoved();
   7279             boolean showOnKeyguard = shouldShowOnKeyguard(entry.notification);
   7280             if (suppressedSummary
   7281                     || (isLockscreenPublicMode(userId) && !mShowLockscreenNotifications)
   7282                     || (onKeyguard && !showOnKeyguard)) {
   7283                 entry.row.setVisibility(View.GONE);
   7284             } else {
   7285                 boolean wasGone = entry.row.getVisibility() == View.GONE;
   7286                 if (wasGone) {
   7287                     entry.row.setVisibility(View.VISIBLE);
   7288                 }
   7289                 if (!isChildNotification && !entry.row.isRemoved()) {
   7290                     if (wasGone) {
   7291                         // notify the scroller of a child addition
   7292                         mStackScroller.generateAddAnimation(entry.row,
   7293                                 !showOnKeyguard /* fromMoreCard */);
   7294                     }
   7295                     visibleNotifications++;
   7296                 }
   7297             }
   7298             if (row.isSummaryWithChildren()) {
   7299                 List<ExpandableNotificationRow> notificationChildren =
   7300                         row.getNotificationChildren();
   7301                 int size = notificationChildren.size();
   7302                 for (int i = size - 1; i >= 0; i--) {
   7303                     stack.push(notificationChildren.get(i));
   7304                 }
   7305             }
   7306         }
   7307         mNotificationPanel.setNoVisibleNotifications(visibleNotifications == 0);
   7308 
   7309         // The following views will be moved to the end of mStackScroller. This counter represents
   7310         // the offset from the last child. Initialized to 1 for the very last position. It is post-
   7311         // incremented in the following "changeViewPosition" calls so that its value is correct for
   7312         // subsequent calls.
   7313         int offsetFromEnd = 1;
   7314         if (mDismissView != null) {
   7315             mStackScroller.changeViewPosition(mDismissView,
   7316                     mStackScroller.getChildCount() - offsetFromEnd++);
   7317         }
   7318 
   7319         mStackScroller.changeViewPosition(mEmptyShadeView,
   7320                 mStackScroller.getChildCount() - offsetFromEnd++);
   7321 
   7322         // No post-increment for this call because it is the last one. Make sure to add one if
   7323         // another "changeViewPosition" call is ever added.
   7324         mStackScroller.changeViewPosition(mNotificationShelf,
   7325                 mStackScroller.getChildCount() - offsetFromEnd);
   7326 
   7327         // Scrim opacity varies based on notification count
   7328         mScrimController.setNotificationCount(mStackScroller.getNotGoneChildCount());
   7329     }
   7330 
   7331     public boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
   7332         return mShowLockscreenNotifications && !mNotificationData.isAmbient(sbn.getKey());
   7333     }
   7334 
   7335     // extended in StatusBar
   7336     protected void setShowLockscreenNotifications(boolean show) {
   7337         mShowLockscreenNotifications = show;
   7338     }
   7339 
   7340     protected void setLockScreenAllowRemoteInput(boolean allowLockscreenRemoteInput) {
   7341         mAllowLockscreenRemoteInput = allowLockscreenRemoteInput;
   7342     }
   7343 
   7344     private void updateLockscreenNotificationSetting() {
   7345         final boolean show = Settings.Secure.getIntForUser(mContext.getContentResolver(),
   7346                 Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
   7347                 1,
   7348                 mCurrentUserId) != 0;
   7349         final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures(
   7350                 null /* admin */, mCurrentUserId);
   7351         final boolean allowedByDpm = (dpmFlags
   7352                 & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS) == 0;
   7353 
   7354         setShowLockscreenNotifications(show && allowedByDpm);
   7355 
   7356         if (ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT) {
   7357             final boolean remoteInput = Settings.Secure.getIntForUser(mContext.getContentResolver(),
   7358                     Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT,
   7359                     0,
   7360                     mCurrentUserId) != 0;
   7361             final boolean remoteInputDpm =
   7362                     (dpmFlags & DevicePolicyManager.KEYGUARD_DISABLE_REMOTE_INPUT) == 0;
   7363 
   7364             setLockScreenAllowRemoteInput(remoteInput && remoteInputDpm);
   7365         } else {
   7366             setLockScreenAllowRemoteInput(false);
   7367         }
   7368     }
   7369 
   7370     public void updateNotification(StatusBarNotification notification, RankingMap ranking)
   7371             throws InflationException {
   7372         if (DEBUG) Log.d(TAG, "updateNotification(" + notification + ")");
   7373 
   7374         final String key = notification.getKey();
   7375         abortExistingInflation(key);
   7376         Entry entry = mNotificationData.get(key);
   7377         if (entry == null) {
   7378             return;
   7379         }
   7380         mHeadsUpEntriesToRemoveOnSwitch.remove(entry);
   7381         mRemoteInputEntriesToRemoveOnCollapse.remove(entry);
   7382         if (key.equals(mKeyToRemoveOnGutsClosed)) {
   7383             mKeyToRemoveOnGutsClosed = null;
   7384             Log.w(TAG, "Notification that was kept for guts was updated. " + key);
   7385         }
   7386 
   7387         Notification n = notification.getNotification();
   7388         mNotificationData.updateRanking(ranking);
   7389 
   7390         final StatusBarNotification oldNotification = entry.notification;
   7391         entry.notification = notification;
   7392         mGroupManager.onEntryUpdated(entry, oldNotification);
   7393 
   7394         entry.updateIcons(mContext, notification);
   7395         inflateViews(entry, mStackScroller);
   7396 
   7397         mForegroundServiceController.updateNotification(notification,
   7398                 mNotificationData.getImportance(key));
   7399 
   7400         boolean shouldPeek = shouldPeek(entry, notification);
   7401         boolean alertAgain = alertAgain(entry, n);
   7402 
   7403         updateHeadsUp(key, entry, shouldPeek, alertAgain);
   7404         updateNotifications();
   7405 
   7406         if (!notification.isClearable()) {
   7407             // The user may have performed a dismiss action on the notification, since it's
   7408             // not clearable we should snap it back.
   7409             mStackScroller.snapViewIfNeeded(entry.row);
   7410         }
   7411 
   7412         if (DEBUG) {
   7413             // Is this for you?
   7414             boolean isForCurrentUser = isNotificationForCurrentProfiles(notification);
   7415             Log.d(TAG, "notification is " + (isForCurrentUser ? "" : "not ") + "for you");
   7416         }
   7417 
   7418         setAreThereNotifications();
   7419     }
   7420 
   7421     protected void notifyHeadsUpGoingToSleep() {
   7422         maybeEscalateHeadsUp();
   7423     }
   7424 
   7425     private boolean alertAgain(Entry oldEntry, Notification newNotification) {
   7426         return oldEntry == null || !oldEntry.hasInterrupted()
   7427                 || (newNotification.flags & Notification.FLAG_ONLY_ALERT_ONCE) == 0;
   7428     }
   7429 
   7430     protected boolean shouldPeek(Entry entry) {
   7431         return shouldPeek(entry, entry.notification);
   7432     }
   7433 
   7434     protected boolean shouldPeek(Entry entry, StatusBarNotification sbn) {
   7435         if (!mUseHeadsUp || isDeviceInVrMode()) {
   7436             if (DEBUG) Log.d(TAG, "No peeking: no huns or vr mode");
   7437             return false;
   7438         }
   7439 
   7440         if (mNotificationData.shouldFilterOut(sbn)) {
   7441             if (DEBUG) Log.d(TAG, "No peeking: filtered notification: " + sbn.getKey());
   7442             return false;
   7443         }
   7444 
   7445         boolean inUse = mPowerManager.isScreenOn() && !mSystemServicesProxy.isDreaming();
   7446 
   7447         if (!inUse && !isDozing()) {
   7448             if (DEBUG) {
   7449                 Log.d(TAG, "No peeking: not in use: " + sbn.getKey());
   7450             }
   7451             return false;
   7452         }
   7453 
   7454         if (!isDozing() && mNotificationData.shouldSuppressScreenOn(sbn.getKey())) {
   7455             if (DEBUG) Log.d(TAG, "No peeking: suppressed by DND: " + sbn.getKey());
   7456             return false;
   7457         }
   7458 
   7459         if (isDozing() && mNotificationData.shouldSuppressScreenOff(sbn.getKey())) {
   7460             if (DEBUG) Log.d(TAG, "No peeking: suppressed by DND: " + sbn.getKey());
   7461             return false;
   7462         }
   7463 
   7464         if (entry.hasJustLaunchedFullScreenIntent()) {
   7465             if (DEBUG) Log.d(TAG, "No peeking: recent fullscreen: " + sbn.getKey());
   7466             return false;
   7467         }
   7468 
   7469         if (isSnoozedPackage(sbn)) {
   7470             if (DEBUG) Log.d(TAG, "No peeking: snoozed package: " + sbn.getKey());
   7471             return false;
   7472         }
   7473 
   7474         // Allow peeking for DEFAULT notifications only if we're on Ambient Display.
   7475         int importanceLevel = isDozing() ? NotificationManager.IMPORTANCE_DEFAULT
   7476                 : NotificationManager.IMPORTANCE_HIGH;
   7477         if (mNotificationData.getImportance(sbn.getKey()) < importanceLevel) {
   7478             if (DEBUG) Log.d(TAG, "No peeking: unimportant notification: " + sbn.getKey());
   7479             return false;
   7480         }
   7481 
   7482         if (sbn.getNotification().fullScreenIntent != null) {
   7483             if (mAccessibilityManager.isTouchExplorationEnabled()) {
   7484                 if (DEBUG) Log.d(TAG, "No peeking: accessible fullscreen: " + sbn.getKey());
   7485                 return false;
   7486             } else if (mDozing) {
   7487                 // We never want heads up when we are dozing.
   7488                 return false;
   7489             } else {
   7490                 // we only allow head-up on the lockscreen if it doesn't have a fullscreen intent
   7491                 return !mStatusBarKeyguardViewManager.isShowing()
   7492                         || mStatusBarKeyguardViewManager.isOccluded();
   7493             }
   7494         }
   7495 
   7496         // Don't peek notifications that are suppressed due to group alert behavior
   7497         if (sbn.isGroup() && sbn.getNotification().suppressAlertingDueToGrouping()) {
   7498             if (DEBUG) Log.d(TAG, "No peeking: suppressed due to group alert behavior");
   7499             return false;
   7500         }
   7501 
   7502         return true;
   7503     }
   7504 
   7505     /**
   7506      * @return Whether the security bouncer from Keyguard is showing.
   7507      */
   7508     public boolean isBouncerShowing() {
   7509         return mBouncerShowing;
   7510     }
   7511 
   7512     /**
   7513      * @return a PackageManger for userId or if userId is < 0 (USER_ALL etc) then
   7514      *         return PackageManager for mContext
   7515      */
   7516     public static PackageManager getPackageManagerForUser(Context context, int userId) {
   7517         Context contextForUser = context;
   7518         // UserHandle defines special userId as negative values, e.g. USER_ALL
   7519         if (userId >= 0) {
   7520             try {
   7521                 // Create a context for the correct user so if a package isn't installed
   7522                 // for user 0 we can still load information about the package.
   7523                 contextForUser =
   7524                         context.createPackageContextAsUser(context.getPackageName(),
   7525                         Context.CONTEXT_RESTRICTED,
   7526                         new UserHandle(userId));
   7527             } catch (NameNotFoundException e) {
   7528                 // Shouldn't fail to find the package name for system ui.
   7529             }
   7530         }
   7531         return contextForUser.getPackageManager();
   7532     }
   7533 
   7534     @Override
   7535     public void logNotificationExpansion(String key, boolean userAction, boolean expanded) {
   7536         mUiOffloadThread.submit(() -> {
   7537             try {
   7538                 mBarService.onNotificationExpansionChanged(key, userAction, expanded);
   7539             } catch (RemoteException e) {
   7540                 // Ignore.
   7541             }
   7542         });
   7543     }
   7544 
   7545     public boolean isKeyguardSecure() {
   7546         if (mStatusBarKeyguardViewManager == null) {
   7547             // startKeyguard() hasn't been called yet, so we don't know.
   7548             // Make sure anything that needs to know isKeyguardSecure() checks and re-checks this
   7549             // value onVisibilityChanged().
   7550             Slog.w(TAG, "isKeyguardSecure() called before startKeyguard(), returning false",
   7551                     new Throwable());
   7552             return false;
   7553         }
   7554         return mStatusBarKeyguardViewManager.isSecure();
   7555     }
   7556 
   7557     @Override
   7558     public void showAssistDisclosure() {
   7559         if (mAssistManager != null) {
   7560             mAssistManager.showDisclosure();
   7561         }
   7562     }
   7563 
   7564     public NotificationPanelView getPanel() {
   7565         return mNotificationPanel;
   7566     }
   7567 
   7568     @Override
   7569     public void startAssist(Bundle args) {
   7570         if (mAssistManager != null) {
   7571             mAssistManager.startAssist(args);
   7572         }
   7573     }
   7574     // End Extra BaseStatusBarMethods.
   7575 
   7576     private final Runnable mAutoDim = () -> {
   7577         if (mNavigationBar != null) {
   7578             mNavigationBar.getBarTransitions().setAutoDim(true);
   7579         }
   7580     };
   7581 }
   7582