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