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