• 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 
20 import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT;
21 import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN;
22 import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
23 import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
24 import static android.app.StatusBarManager.windowStateToString;
25 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
26 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
27 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
28 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
29 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSLUCENT;
30 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
31 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_WARNING;
32 
33 import android.animation.Animator;
34 import android.animation.AnimatorListenerAdapter;
35 import android.annotation.NonNull;
36 import android.app.ActivityManager;
37 import android.app.ActivityManagerNative;
38 import android.app.ActivityOptions;
39 import android.app.admin.DevicePolicyManager;
40 import android.app.IActivityManager;
41 import android.app.Notification;
42 import android.app.PendingIntent;
43 import android.app.StatusBarManager;
44 import android.content.BroadcastReceiver;
45 import android.content.ComponentCallbacks2;
46 import android.content.ComponentName;
47 import android.content.Context;
48 import android.content.Intent;
49 import android.content.IntentFilter;
50 import android.content.IntentSender;
51 import android.content.pm.IPackageManager;
52 import android.content.pm.PackageManager;
53 import android.content.pm.UserInfo;
54 import android.content.res.Configuration;
55 import android.content.res.Resources;
56 import android.database.ContentObserver;
57 import android.graphics.Bitmap;
58 import android.graphics.Canvas;
59 import android.graphics.ColorFilter;
60 import android.graphics.PixelFormat;
61 import android.graphics.Point;
62 import android.graphics.PointF;
63 import android.graphics.PorterDuff;
64 import android.graphics.PorterDuffXfermode;
65 import android.graphics.Rect;
66 import android.graphics.drawable.BitmapDrawable;
67 import android.graphics.drawable.ColorDrawable;
68 import android.graphics.drawable.Drawable;
69 import android.inputmethodservice.InputMethodService;
70 import android.media.AudioAttributes;
71 import android.media.MediaMetadata;
72 import android.media.session.MediaController;
73 import android.media.session.MediaSession;
74 import android.media.session.MediaSessionManager;
75 import android.media.session.PlaybackState;
76 import android.net.Uri;
77 import android.os.AsyncTask;
78 import android.os.Bundle;
79 import android.os.Handler;
80 import android.os.HandlerThread;
81 import android.os.IBinder;
82 import android.os.Message;
83 import android.os.PowerManager;
84 import android.os.Process;
85 import android.os.RemoteException;
86 import android.os.ServiceManager;
87 import android.os.SystemClock;
88 import android.os.Trace;
89 import android.os.SystemProperties;
90 import android.os.UserHandle;
91 import android.os.UserManager;
92 import android.os.Vibrator;
93 import android.provider.Settings;
94 import android.service.notification.NotificationListenerService;
95 import android.service.notification.NotificationListenerService.RankingMap;
96 import android.service.notification.StatusBarNotification;
97 import android.telecom.TelecomManager;
98 import android.util.ArraySet;
99 import android.util.DisplayMetrics;
100 import android.util.EventLog;
101 import android.util.Log;
102 import android.view.Display;
103 import android.view.IRotationWatcher;
104 import android.view.KeyEvent;
105 import android.view.LayoutInflater;
106 import android.view.MotionEvent;
107 import android.view.ThreadedRenderer;
108 import android.view.View;
109 import android.view.ViewGroup;
110 import android.view.ViewGroup.LayoutParams;
111 import android.view.ViewParent;
112 import android.view.ViewStub;
113 import android.view.ViewTreeObserver;
114 import android.view.WindowManager;
115 import android.view.WindowManagerGlobal;
116 import android.view.accessibility.AccessibilityEvent;
117 import android.view.animation.AccelerateInterpolator;
118 import android.view.animation.Interpolator;
119 import android.widget.ImageView;
120 import android.widget.TextView;
121 
122 import com.android.internal.logging.MetricsLogger;
123 import com.android.internal.logging.MetricsProto.MetricsEvent;
124 import com.android.internal.statusbar.NotificationVisibility;
125 import com.android.internal.statusbar.StatusBarIcon;
126 import com.android.keyguard.KeyguardHostView.OnDismissAction;
127 import com.android.keyguard.KeyguardUpdateMonitor;
128 import com.android.keyguard.KeyguardUpdateMonitorCallback;
129 import com.android.keyguard.ViewMediatorCallback;
130 import com.android.systemui.AutoReinflateContainer;
131 import com.android.systemui.AutoReinflateContainer.InflateListener;
132 import com.android.systemui.BatteryMeterView;
133 import com.android.systemui.DemoMode;
134 import com.android.systemui.EventLogConstants;
135 import com.android.systemui.EventLogTags;
136 import com.android.systemui.Interpolators;
137 import com.android.systemui.Prefs;
138 import com.android.systemui.R;
139 import com.android.systemui.SystemUIFactory;
140 import com.android.systemui.classifier.FalsingLog;
141 import com.android.systemui.classifier.FalsingManager;
142 import com.android.systemui.doze.DozeHost;
143 import com.android.systemui.doze.DozeLog;
144 import com.android.systemui.keyguard.KeyguardViewMediator;
145 import com.android.systemui.qs.QSContainer;
146 import com.android.systemui.qs.QSPanel;
147 import com.android.systemui.recents.ScreenPinningRequest;
148 import com.android.systemui.recents.events.EventBus;
149 import com.android.systemui.recents.events.activity.AppTransitionFinishedEvent;
150 import com.android.systemui.recents.events.activity.UndockingTaskEvent;
151 import com.android.systemui.stackdivider.Divider;
152 import com.android.systemui.stackdivider.WindowManagerProxy;
153 import com.android.systemui.statusbar.ActivatableNotificationView;
154 import com.android.systemui.statusbar.BackDropView;
155 import com.android.systemui.statusbar.BaseStatusBar;
156 import com.android.systemui.statusbar.CommandQueue;
157 import com.android.systemui.statusbar.DismissView;
158 import com.android.systemui.statusbar.DragDownHelper;
159 import com.android.systemui.statusbar.EmptyShadeView;
160 import com.android.systemui.statusbar.ExpandableNotificationRow;
161 import com.android.systemui.statusbar.GestureRecorder;
162 import com.android.systemui.statusbar.KeyboardShortcuts;
163 import com.android.systemui.statusbar.KeyguardIndicationController;
164 import com.android.systemui.statusbar.NotificationData;
165 import com.android.systemui.statusbar.NotificationData.Entry;
166 import com.android.systemui.statusbar.NotificationOverflowContainer;
167 import com.android.systemui.statusbar.RemoteInputController;
168 import com.android.systemui.statusbar.ScrimView;
169 import com.android.systemui.statusbar.SignalClusterView;
170 import com.android.systemui.statusbar.StatusBarState;
171 import com.android.systemui.statusbar.notification.VisualStabilityManager;
172 import com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChangedListener;
173 import com.android.systemui.statusbar.policy.AccessibilityController;
174 import com.android.systemui.statusbar.policy.BatteryController;
175 import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
176 import com.android.systemui.statusbar.policy.BatteryControllerImpl;
177 import com.android.systemui.statusbar.policy.BluetoothControllerImpl;
178 import com.android.systemui.statusbar.policy.BrightnessMirrorController;
179 import com.android.systemui.statusbar.policy.CastControllerImpl;
180 import com.android.systemui.statusbar.policy.EncryptionHelper;
181 import com.android.systemui.statusbar.policy.FlashlightController;
182 import com.android.systemui.statusbar.policy.HeadsUpManager;
183 import com.android.systemui.statusbar.policy.HotspotControllerImpl;
184 import com.android.systemui.statusbar.policy.KeyButtonView;
185 import com.android.systemui.statusbar.policy.KeyguardMonitor;
186 import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
187 import com.android.systemui.statusbar.policy.LocationControllerImpl;
188 import com.android.systemui.statusbar.policy.NetworkController;
189 import com.android.systemui.statusbar.policy.NetworkControllerImpl;
190 import com.android.systemui.statusbar.policy.NextAlarmController;
191 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
192 import com.android.systemui.statusbar.policy.PreviewInflater;
193 import com.android.systemui.statusbar.policy.RotationLockControllerImpl;
194 import com.android.systemui.statusbar.policy.SecurityControllerImpl;
195 import com.android.systemui.statusbar.policy.UserInfoController;
196 import com.android.systemui.statusbar.policy.UserSwitcherController;
197 import com.android.systemui.statusbar.policy.ZenModeController;
198 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
199 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout
200         .OnChildLocationsChangedListener;
201 import com.android.systemui.statusbar.stack.StackStateAnimator;
202 import com.android.systemui.volume.VolumeComponent;
203 
204 import java.io.FileDescriptor;
205 import java.io.PrintWriter;
206 import java.io.StringWriter;
207 import java.util.ArrayList;
208 import java.util.Collection;
209 import java.util.Collections;
210 import java.util.HashMap;
211 import java.util.List;
212 import java.util.Map;
213 
214 public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
215         DragDownHelper.DragDownCallback, ActivityStarter, OnUnlockMethodChangedListener,
216         OnHeadsUpChangedListener, VisualStabilityManager.Callback {
217     static final String TAG = "PhoneStatusBar";
218     public static final boolean DEBUG = BaseStatusBar.DEBUG;
219     public static final boolean SPEW = false;
220     public static final boolean DUMPTRUCK = true; // extra dumpsys info
221     public static final boolean DEBUG_GESTURES = false;
222     public static final boolean DEBUG_MEDIA = false;
223     public static final boolean DEBUG_MEDIA_FAKE_ARTWORK = false;
224 
225     public static final boolean DEBUG_WINDOW_STATE = false;
226 
227     // additional instrumentation for testing purposes; intended to be left on during development
228     public static final boolean CHATTY = DEBUG;
229 
230     public static final boolean SHOW_LOCKSCREEN_MEDIA_ARTWORK = true;
231 
232     public static final String ACTION_FAKE_ARTWORK = "fake_artwork";
233 
234     private static final int MSG_OPEN_NOTIFICATION_PANEL = 1000;
235     private static final int MSG_CLOSE_PANELS = 1001;
236     private static final int MSG_OPEN_SETTINGS_PANEL = 1002;
237     private static final int MSG_LAUNCH_TRANSITION_TIMEOUT = 1003;
238     // 1020-1040 reserved for BaseStatusBar
239 
240     // Time after we abort the launch transition.
241     private static final long LAUNCH_TRANSITION_TIMEOUT_MS = 5000;
242 
243     private static final boolean CLOSE_PANEL_WHEN_EMPTIED = true;
244 
245     private static final int STATUS_OR_NAV_TRANSIENT =
246             View.STATUS_BAR_TRANSIENT | View.NAVIGATION_BAR_TRANSIENT;
247     private static final long AUTOHIDE_TIMEOUT_MS = 3000;
248 
249     /** The minimum delay in ms between reports of notification visibility. */
250     private static final int VISIBILITY_REPORT_MIN_DELAY_MS = 500;
251 
252     /**
253      * The delay to reset the hint text when the hint animation is finished running.
254      */
255     private static final int HINT_RESET_DELAY_MS = 1200;
256 
257     private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
258             .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
259             .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
260             .build();
261 
262     public static final int FADE_KEYGUARD_START_DELAY = 100;
263     public static final int FADE_KEYGUARD_DURATION = 300;
264     public static final int FADE_KEYGUARD_DURATION_PULSING = 96;
265 
266     /** Allow some time inbetween the long press for back and recents. */
267     private static final int LOCK_TO_APP_GESTURE_TOLERENCE = 200;
268 
269     /** If true, the system is in the half-boot-to-decryption-screen state.
270      * Prudently disable QS and notifications.  */
271     private static final boolean ONLY_CORE_APPS;
272 
273     /** If true, the lockscreen will show a distinct wallpaper */
274     private static final boolean ENABLE_LOCKSCREEN_WALLPAPER = true;
275 
276     /* If true, the device supports freeform window management.
277      * This affects the status bar UI. */
278     private static final boolean FREEFORM_WINDOW_MANAGEMENT;
279 
280     /**
281      * How long to wait before auto-dismissing a notification that was kept for remote input, and
282      * has now sent a remote input. We auto-dismiss, because the app may not see a reason to cancel
283      * these given that they technically don't exist anymore. We wait a bit in case the app issues
284      * an update.
285      */
286     private static final int REMOTE_INPUT_KEPT_ENTRY_AUTO_CANCEL_DELAY = 200;
287 
288     /**
289      * Never let the alpha become zero for surfaces that draw with SRC - otherwise the RenderNode
290      * won't draw anything and uninitialized memory will show through
291      * if mScrimSrcModeEnabled. Note that 0.001 is rounded down to 0 in
292      * libhwui.
293      */
294     private static final float SRC_MIN_ALPHA = 0.002f;
295 
296     static {
297         boolean onlyCoreApps;
298         boolean freeformWindowManagement;
299         try {
300             IPackageManager packageManager =
301                     IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
302             onlyCoreApps = packageManager.isOnlyCoreApps();
303             freeformWindowManagement = packageManager.hasSystemFeature(
304                     PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT, 0);
305         } catch (RemoteException e) {
306             onlyCoreApps = false;
307             freeformWindowManagement = false;
308         }
309         ONLY_CORE_APPS = onlyCoreApps;
310         FREEFORM_WINDOW_MANAGEMENT = freeformWindowManagement;
311     }
312 
313     PhoneStatusBarPolicy mIconPolicy;
314 
315     // These are no longer handled by the policy, because we need custom strategies for them
316     BluetoothControllerImpl mBluetoothController;
317     SecurityControllerImpl mSecurityController;
318     protected BatteryController mBatteryController;
319     LocationControllerImpl mLocationController;
320     NetworkControllerImpl mNetworkController;
321     HotspotControllerImpl mHotspotController;
322     RotationLockControllerImpl mRotationLockController;
323     UserInfoController mUserInfoController;
324     protected ZenModeController mZenModeController;
325     CastControllerImpl mCastController;
326     VolumeComponent mVolumeComponent;
327     KeyguardUserSwitcher mKeyguardUserSwitcher;
328     FlashlightController mFlashlightController;
329     protected UserSwitcherController mUserSwitcherController;
330     NextAlarmController mNextAlarmController;
331     protected KeyguardMonitor mKeyguardMonitor;
332     BrightnessMirrorController mBrightnessMirrorController;
333     AccessibilityController mAccessibilityController;
334     FingerprintUnlockController mFingerprintUnlockController;
335     LightStatusBarController mLightStatusBarController;
336     protected LockscreenWallpaper mLockscreenWallpaper;
337 
338     int mNaturalBarHeight = -1;
339 
340     Display mDisplay;
341     Point mCurrentDisplaySize = new Point();
342 
343     protected StatusBarWindowView mStatusBarWindow;
344     protected PhoneStatusBarView mStatusBarView;
345     private int mStatusBarWindowState = WINDOW_STATE_SHOWING;
346     protected StatusBarWindowManager mStatusBarWindowManager;
347     private UnlockMethodCache mUnlockMethodCache;
348     private DozeServiceHost mDozeServiceHost;
349     private boolean mWakeUpComingFromTouch;
350     private PointF mWakeUpTouchLocation;
351     private boolean mScreenTurningOn;
352 
353     int mPixelFormat;
354     Object mQueueLock = new Object();
355 
356     protected StatusBarIconController mIconController;
357 
358     // expanded notifications
359     protected NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
360     View mExpandedContents;
361     TextView mNotificationPanelDebugText;
362 
363     // settings
364     private QSPanel mQSPanel;
365 
366     // top bar
367     BaseStatusBarHeader mHeader;
368     protected KeyguardStatusBarView mKeyguardStatusBar;
369     View mKeyguardStatusView;
370     KeyguardBottomAreaView mKeyguardBottomArea;
371     boolean mLeaveOpenOnKeyguardHide;
372     KeyguardIndicationController mKeyguardIndicationController;
373 
374     // Keyguard is going away soon.
375     private boolean mKeyguardGoingAway;
376     // Keyguard is actually fading away now.
377     private boolean mKeyguardFadingAway;
378     private long mKeyguardFadingAwayDelay;
379     private long mKeyguardFadingAwayDuration;
380 
381     // RemoteInputView to be activated after unlock
382     private View mPendingRemoteInputView;
383     private View mPendingWorkRemoteInputView;
384 
385     private View mReportRejectedTouch;
386 
387     int mMaxAllowedKeyguardNotifications;
388 
389     boolean mExpandedVisible;
390 
391     private int mNavigationBarWindowState = WINDOW_STATE_SHOWING;
392 
393     // the tracker view
394     int mTrackingPosition; // the position of the top of the tracking view.
395 
396     // Tracking finger for opening/closing.
397     boolean mTracking;
398 
399     int[] mAbsPos = new int[2];
400     ArrayList<Runnable> mPostCollapseRunnables = new ArrayList<>();
401 
402     // for disabling the status bar
403     int mDisabled1 = 0;
404     int mDisabled2 = 0;
405 
406     // tracking calls to View.setSystemUiVisibility()
407     int mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE;
408     private final Rect mLastFullscreenStackBounds = new Rect();
409     private final Rect mLastDockedStackBounds = new Rect();
410 
411     // last value sent to window manager
412     private int mLastDispatchedSystemUiVisibility = ~View.SYSTEM_UI_FLAG_VISIBLE;
413 
414     DisplayMetrics mDisplayMetrics = new DisplayMetrics();
415 
416     // XXX: gesture research
417     private final GestureRecorder mGestureRec = DEBUG_GESTURES
418         ? new GestureRecorder("/sdcard/statusbar_gestures.dat")
419         : null;
420 
421     private ScreenPinningRequest mScreenPinningRequest;
422 
423     private int mNavigationIconHints = 0;
424     private HandlerThread mHandlerThread;
425 
426     // ensure quick settings is disabled until the current user makes it through the setup wizard
427     private boolean mUserSetup = false;
428     private ContentObserver mUserSetupObserver = new ContentObserver(new Handler()) {
429         @Override
430         public void onChange(boolean selfChange) {
431             final boolean userSetup = 0 != Settings.Secure.getIntForUser(
432                     mContext.getContentResolver(),
433                     Settings.Secure.USER_SETUP_COMPLETE,
434                     0 /*default */,
435                     mCurrentUserId);
436             if (MULTIUSER_DEBUG) Log.d(TAG, String.format("User setup changed: " +
437                     "selfChange=%s userSetup=%s mUserSetup=%s",
438                     selfChange, userSetup, mUserSetup));
439 
440             if (userSetup != mUserSetup) {
441                 mUserSetup = userSetup;
442                 if (!mUserSetup && mStatusBarView != null)
443                     animateCollapseQuickSettings();
444                 if (mKeyguardBottomArea != null) {
445                     mKeyguardBottomArea.setUserSetupComplete(mUserSetup);
446                 }
447                 if (mNetworkController != null) {
448                     mNetworkController.setUserSetupComplete(mUserSetup);
449                 }
450             }
451             if (mIconPolicy != null) {
452                 mIconPolicy.setCurrentUserSetup(mUserSetup);
453             }
454         }
455     };
456 
457     final private ContentObserver mHeadsUpObserver = new ContentObserver(mHandler) {
458         @Override
459         public void onChange(boolean selfChange) {
460             boolean wasUsing = mUseHeadsUp;
461             mUseHeadsUp = ENABLE_HEADS_UP && !mDisableNotificationAlerts
462                     && Settings.Global.HEADS_UP_OFF != Settings.Global.getInt(
463                     mContext.getContentResolver(), Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED,
464                     Settings.Global.HEADS_UP_OFF);
465             mHeadsUpTicker = mUseHeadsUp && 0 != Settings.Global.getInt(
466                     mContext.getContentResolver(), SETTING_HEADS_UP_TICKER, 0);
467             Log.d(TAG, "heads up is " + (mUseHeadsUp ? "enabled" : "disabled"));
468             if (wasUsing != mUseHeadsUp) {
469                 if (!mUseHeadsUp) {
470                     Log.d(TAG, "dismissing any existing heads up notification on disable event");
471                     mHeadsUpManager.releaseAllImmediately();
472                 }
473             }
474         }
475     };
476 
477     private int mInteractingWindows;
478     private boolean mAutohideSuspended;
479     private int mStatusBarMode;
480     private int mNavigationBarMode;
481     private int mMaxKeyguardNotifications;
482 
483     private ViewMediatorCallback mKeyguardViewMediatorCallback;
484     protected ScrimController mScrimController;
485     protected DozeScrimController mDozeScrimController;
486 
487     private final Runnable mAutohide = new Runnable() {
488         @Override
489         public void run() {
490             int requested = mSystemUiVisibility & ~STATUS_OR_NAV_TRANSIENT;
491             if (mSystemUiVisibility != requested) {
492                 notifyUiVisibilityChanged(requested);
493             }
494         }};
495 
496     private boolean mWaitingForKeyguardExit;
497     private boolean mDozing;
498     private boolean mDozingRequested;
499     protected boolean mScrimSrcModeEnabled;
500 
501     public static final Interpolator ALPHA_IN = Interpolators.ALPHA_IN;
502     public static final Interpolator ALPHA_OUT = Interpolators.ALPHA_OUT;
503 
504     private BackDropView mBackdrop;
505     private ImageView mBackdropFront, mBackdropBack;
506     private PorterDuffXfermode mSrcXferMode = new PorterDuffXfermode(PorterDuff.Mode.SRC);
507     private PorterDuffXfermode mSrcOverXferMode = new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER);
508 
509     private MediaSessionManager mMediaSessionManager;
510     private MediaController mMediaController;
511     private String mMediaNotificationKey;
512     private MediaMetadata mMediaMetadata;
513     private MediaController.Callback mMediaListener
514             = new MediaController.Callback() {
515         @Override
516         public void onPlaybackStateChanged(PlaybackState state) {
517             super.onPlaybackStateChanged(state);
518             if (DEBUG_MEDIA) Log.v(TAG, "DEBUG_MEDIA: onPlaybackStateChanged: " + state);
519             if (state != null) {
520                 if (!isPlaybackActive(state.getState())) {
521                     clearCurrentMediaNotification();
522                     updateMediaMetaData(true, true);
523                 }
524             }
525         }
526 
527         @Override
528         public void onMetadataChanged(MediaMetadata metadata) {
529             super.onMetadataChanged(metadata);
530             if (DEBUG_MEDIA) Log.v(TAG, "DEBUG_MEDIA: onMetadataChanged: " + metadata);
531             mMediaMetadata = metadata;
532             updateMediaMetaData(true, true);
533         }
534     };
535 
536     private final OnChildLocationsChangedListener mOnChildLocationsChangedListener =
537             new OnChildLocationsChangedListener() {
538         @Override
539         public void onChildLocationsChanged(NotificationStackScrollLayout stackScrollLayout) {
540             userActivity();
541         }
542     };
543 
544     private int mDisabledUnmodified1;
545     private int mDisabledUnmodified2;
546 
547     /** Keys of notifications currently visible to the user. */
548     private final ArraySet<NotificationVisibility> mCurrentlyVisibleNotifications =
549             new ArraySet<>();
550     private long mLastVisibilityReportUptimeMs;
551 
552     private final ShadeUpdates mShadeUpdates = new ShadeUpdates();
553 
554     private Runnable mLaunchTransitionEndRunnable;
555     private boolean mLaunchTransitionFadingAway;
556     private ExpandableNotificationRow mDraggedDownRow;
557     private boolean mLaunchCameraOnScreenTurningOn;
558     private boolean mLaunchCameraOnFinishedGoingToSleep;
559     private int mLastCameraLaunchSource;
560     private PowerManager.WakeLock mGestureWakeLock;
561     private Vibrator mVibrator;
562 
563     // Fingerprint (as computed by getLoggingFingerprint() of the last logged state.
564     private int mLastLoggedStateFingerprint;
565 
566     /**
567      * If set, the device has started going to sleep but isn't fully non-interactive yet.
568      */
569     protected boolean mStartedGoingToSleep;
570 
571     private final OnChildLocationsChangedListener mNotificationLocationsChangedListener =
572             new OnChildLocationsChangedListener() {
573                 @Override
574                 public void onChildLocationsChanged(
575                         NotificationStackScrollLayout stackScrollLayout) {
576                     if (mHandler.hasCallbacks(mVisibilityReporter)) {
577                         // Visibilities will be reported when the existing
578                         // callback is executed.
579                         return;
580                     }
581                     // Calculate when we're allowed to run the visibility
582                     // reporter. Note that this timestamp might already have
583                     // passed. That's OK, the callback will just be executed
584                     // ASAP.
585                     long nextReportUptimeMs =
586                             mLastVisibilityReportUptimeMs + VISIBILITY_REPORT_MIN_DELAY_MS;
587                     mHandler.postAtTime(mVisibilityReporter, nextReportUptimeMs);
588                 }
589             };
590 
591     // Tracks notifications currently visible in mNotificationStackScroller and
592     // emits visibility events via NoMan on changes.
593     private final Runnable mVisibilityReporter = new Runnable() {
594         private final ArraySet<NotificationVisibility> mTmpNewlyVisibleNotifications =
595                 new ArraySet<>();
596         private final ArraySet<NotificationVisibility> mTmpCurrentlyVisibleNotifications =
597                 new ArraySet<>();
598         private final ArraySet<NotificationVisibility> mTmpNoLongerVisibleNotifications =
599                 new ArraySet<>();
600 
601         @Override
602         public void run() {
603             mLastVisibilityReportUptimeMs = SystemClock.uptimeMillis();
604             final String mediaKey = getCurrentMediaNotificationKey();
605 
606             // 1. Loop over mNotificationData entries:
607             //   A. Keep list of visible notifications.
608             //   B. Keep list of previously hidden, now visible notifications.
609             // 2. Compute no-longer visible notifications by removing currently
610             //    visible notifications from the set of previously visible
611             //    notifications.
612             // 3. Report newly visible and no-longer visible notifications.
613             // 4. Keep currently visible notifications for next report.
614             ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
615             int N = activeNotifications.size();
616             for (int i = 0; i < N; i++) {
617                 Entry entry = activeNotifications.get(i);
618                 String key = entry.notification.getKey();
619                 boolean isVisible = mStackScroller.isInVisibleLocation(entry.row);
620                 NotificationVisibility visObj = NotificationVisibility.obtain(key, i, isVisible);
621                 boolean previouslyVisible = mCurrentlyVisibleNotifications.contains(visObj);
622                 if (isVisible) {
623                     // Build new set of visible notifications.
624                     mTmpCurrentlyVisibleNotifications.add(visObj);
625                     if (!previouslyVisible) {
626                         mTmpNewlyVisibleNotifications.add(visObj);
627                     }
628                 } else {
629                     // release object
630                     visObj.recycle();
631                 }
632             }
633             mTmpNoLongerVisibleNotifications.addAll(mCurrentlyVisibleNotifications);
634             mTmpNoLongerVisibleNotifications.removeAll(mTmpCurrentlyVisibleNotifications);
635 
636             logNotificationVisibilityChanges(
637                     mTmpNewlyVisibleNotifications, mTmpNoLongerVisibleNotifications);
638 
639             recycleAllVisibilityObjects(mCurrentlyVisibleNotifications);
640             mCurrentlyVisibleNotifications.addAll(mTmpCurrentlyVisibleNotifications);
641 
642             recycleAllVisibilityObjects(mTmpNoLongerVisibleNotifications);
643             mTmpCurrentlyVisibleNotifications.clear();
644             mTmpNewlyVisibleNotifications.clear();
645             mTmpNoLongerVisibleNotifications.clear();
646         }
647     };
648 
recycleAllVisibilityObjects(ArraySet<NotificationVisibility> array)649     private void recycleAllVisibilityObjects(ArraySet<NotificationVisibility> array) {
650         final int N = array.size();
651         for (int i = 0 ; i < N; i++) {
652             array.valueAt(i).recycle();
653         }
654         array.clear();
655     }
656 
657     private final View.OnClickListener mOverflowClickListener = new View.OnClickListener() {
658         @Override
659         public void onClick(View v) {
660             goToLockedShade(null);
661         }
662     };
663     private HashMap<ExpandableNotificationRow, List<ExpandableNotificationRow>> mTmpChildOrderMap
664             = new HashMap<>();
665     private RankingMap mLatestRankingMap;
666     private boolean mNoAnimationOnNextBarModeChange;
667     private FalsingManager mFalsingManager;
668     private long mLastLockToAppLongPress;
669 
670     private KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() {
671         @Override
672         public void onDreamingStateChanged(boolean dreaming) {
673             if (dreaming) {
674                 maybeEscalateHeadsUp();
675             }
676         }
677     };
678 
679     @Override
start()680     public void start() {
681         mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
682                 .getDefaultDisplay();
683         updateDisplaySize();
684         mScrimSrcModeEnabled = mContext.getResources().getBoolean(
685                 R.bool.config_status_bar_scrim_behind_use_src);
686 
687         super.start(); // calls createAndAddWindows()
688 
689         mMediaSessionManager
690                 = (MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE);
691         // TODO: use MediaSessionManager.SessionListener to hook us up to future updates
692         // in session state
693 
694         addNavigationBar();
695 
696         // Lastly, call to the icon policy to install/update all the icons.
697         mIconPolicy = new PhoneStatusBarPolicy(mContext, mIconController, mCastController,
698                 mHotspotController, mUserInfoController, mBluetoothController,
699                 mRotationLockController, mNetworkController.getDataSaverController());
700         mIconPolicy.setCurrentUserSetup(mUserSetup);
701         mSettingsObserver.onChange(false); // set up
702 
703         mHeadsUpObserver.onChange(true); // set up
704         if (ENABLE_HEADS_UP) {
705             mContext.getContentResolver().registerContentObserver(
706                     Settings.Global.getUriFor(Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED), true,
707                     mHeadsUpObserver);
708             mContext.getContentResolver().registerContentObserver(
709                     Settings.Global.getUriFor(SETTING_HEADS_UP_TICKER), true,
710                     mHeadsUpObserver);
711         }
712         mUnlockMethodCache = UnlockMethodCache.getInstance(mContext);
713         mUnlockMethodCache.addListener(this);
714         startKeyguard();
715 
716         KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateCallback);
717         mDozeServiceHost = new DozeServiceHost();
718         putComponent(DozeHost.class, mDozeServiceHost);
719         putComponent(PhoneStatusBar.class, this);
720 
721         setControllerUsers();
722 
723         notifyUserAboutHiddenNotifications();
724 
725         mScreenPinningRequest = new ScreenPinningRequest(mContext);
726         mFalsingManager = FalsingManager.getInstance(mContext);
727     }
728 
createIconController()729     protected void createIconController() {
730         mIconController = new StatusBarIconController(
731                 mContext, mStatusBarView, mKeyguardStatusBar, this);
732     }
733 
734     // ================================================================================
735     // Constructing the view
736     // ================================================================================
makeStatusBarView()737     protected PhoneStatusBarView makeStatusBarView() {
738         final Context context = mContext;
739 
740         updateDisplaySize(); // populates mDisplayMetrics
741         updateResources();
742 
743         inflateStatusBarWindow(context);
744         mStatusBarWindow.setService(this);
745         mStatusBarWindow.setOnTouchListener(new View.OnTouchListener() {
746             @Override
747             public boolean onTouch(View v, MotionEvent event) {
748                 checkUserAutohide(v, event);
749                 checkRemoteInputOutside(event);
750                 if (event.getAction() == MotionEvent.ACTION_DOWN) {
751                     if (mExpandedVisible) {
752                         animateCollapsePanels();
753                     }
754                 }
755                 return mStatusBarWindow.onTouchEvent(event);
756             }
757         });
758 
759         mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById(
760                 R.id.notification_panel);
761         mNotificationPanel.setStatusBar(this);
762         mNotificationPanel.setGroupManager(mGroupManager);
763 
764         mStatusBarView = (PhoneStatusBarView) mStatusBarWindow.findViewById(R.id.status_bar);
765         mStatusBarView.setBar(this);
766         mStatusBarView.setPanel(mNotificationPanel);
767 
768         if (!ActivityManager.isHighEndGfx()) {
769             mStatusBarWindow.setBackground(null);
770             mNotificationPanel.setBackground(new FastColorDrawable(context.getColor(
771                     R.color.notification_panel_solid_background)));
772         }
773 
774         mHeadsUpManager = new HeadsUpManager(context, mStatusBarWindow, mGroupManager);
775         mHeadsUpManager.setBar(this);
776         mHeadsUpManager.addListener(this);
777         mHeadsUpManager.addListener(mNotificationPanel);
778         mHeadsUpManager.addListener(mGroupManager);
779         mHeadsUpManager.addListener(mVisualStabilityManager);
780         mNotificationPanel.setHeadsUpManager(mHeadsUpManager);
781         mNotificationData.setHeadsUpManager(mHeadsUpManager);
782         mGroupManager.setHeadsUpManager(mHeadsUpManager);
783         mHeadsUpManager.setVisualStabilityManager(mVisualStabilityManager);
784 
785         if (MULTIUSER_DEBUG) {
786             mNotificationPanelDebugText = (TextView) mNotificationPanel.findViewById(
787                     R.id.header_debug_info);
788             mNotificationPanelDebugText.setVisibility(View.VISIBLE);
789         }
790 
791         try {
792             boolean showNav = mWindowManagerService.hasNavigationBar();
793             if (DEBUG) Log.v(TAG, "hasNavigationBar=" + showNav);
794             if (showNav) {
795                 createNavigationBarView(context);
796             }
797         } catch (RemoteException ex) {
798             // no window manager? good luck with that
799         }
800 
801         mAssistManager = SystemUIFactory.getInstance().createAssistManager(this, context);
802 
803         // figure out which pixel-format to use for the status bar.
804         mPixelFormat = PixelFormat.OPAQUE;
805 
806         mStackScroller = (NotificationStackScrollLayout) mStatusBarWindow.findViewById(
807                 R.id.notification_stack_scroller);
808         mStackScroller.setLongPressListener(getNotificationLongClicker());
809         mStackScroller.setPhoneStatusBar(this);
810         mStackScroller.setGroupManager(mGroupManager);
811         mStackScroller.setHeadsUpManager(mHeadsUpManager);
812         mGroupManager.setOnGroupChangeListener(mStackScroller);
813         mVisualStabilityManager.setVisibilityLocationProvider(mStackScroller);
814 
815         inflateOverflowContainer();
816         inflateEmptyShadeView();
817         inflateDismissView();
818         mExpandedContents = mStackScroller;
819 
820         mBackdrop = (BackDropView) mStatusBarWindow.findViewById(R.id.backdrop);
821         mBackdropFront = (ImageView) mBackdrop.findViewById(R.id.backdrop_front);
822         mBackdropBack = (ImageView) mBackdrop.findViewById(R.id.backdrop_back);
823 
824         if (ENABLE_LOCKSCREEN_WALLPAPER) {
825             mLockscreenWallpaper = new LockscreenWallpaper(mContext, this, mHandler);
826         }
827 
828         ScrimView scrimBehind = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_behind);
829         ScrimView scrimInFront = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_in_front);
830         View headsUpScrim = mStatusBarWindow.findViewById(R.id.heads_up_scrim);
831         mScrimController = SystemUIFactory.getInstance().createScrimController(
832                 scrimBehind, scrimInFront, headsUpScrim, mLockscreenWallpaper);
833         if (mScrimSrcModeEnabled) {
834             Runnable runnable = new Runnable() {
835                 @Override
836                 public void run() {
837                     boolean asSrc = mBackdrop.getVisibility() != View.VISIBLE;
838                     mScrimController.setDrawBehindAsSrc(asSrc);
839                     mStackScroller.setDrawBackgroundAsSrc(asSrc);
840                 }
841             };
842             mBackdrop.setOnVisibilityChangedRunnable(runnable);
843             runnable.run();
844         }
845         mHeadsUpManager.addListener(mScrimController);
846         mStackScroller.setScrimController(mScrimController);
847         mStatusBarView.setScrimController(mScrimController);
848         mDozeScrimController = new DozeScrimController(mScrimController, context);
849 
850         mKeyguardStatusBar = (KeyguardStatusBarView) mStatusBarWindow.findViewById(R.id.keyguard_header);
851         mKeyguardStatusView = mStatusBarWindow.findViewById(R.id.keyguard_status_view);
852         mKeyguardBottomArea =
853                 (KeyguardBottomAreaView) mStatusBarWindow.findViewById(R.id.keyguard_bottom_area);
854         mKeyguardBottomArea.setActivityStarter(this);
855         mKeyguardBottomArea.setAssistManager(mAssistManager);
856         mKeyguardIndicationController = new KeyguardIndicationController(mContext,
857                 (KeyguardIndicationTextView) mStatusBarWindow.findViewById(
858                         R.id.keyguard_indication_text),
859                 mKeyguardBottomArea.getLockIcon());
860         mKeyguardBottomArea.setKeyguardIndicationController(mKeyguardIndicationController);
861 
862         // set the initial view visibility
863         setAreThereNotifications();
864 
865         createIconController();
866 
867         // Background thread for any controllers that need it.
868         mHandlerThread = new HandlerThread(TAG, Process.THREAD_PRIORITY_BACKGROUND);
869         mHandlerThread.start();
870 
871         // Other icons
872         mLocationController = new LocationControllerImpl(mContext,
873                 mHandlerThread.getLooper()); // will post a notification
874         mBatteryController = createBatteryController();
875         mBatteryController.addStateChangedCallback(new BatteryStateChangeCallback() {
876             @Override
877             public void onPowerSaveChanged(boolean isPowerSave) {
878                 mHandler.post(mCheckBarModes);
879                 if (mDozeServiceHost != null) {
880                     mDozeServiceHost.firePowerSaveChanged(isPowerSave);
881                 }
882             }
883             @Override
884             public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
885                 // noop
886             }
887         });
888         mNetworkController = new NetworkControllerImpl(mContext, mHandlerThread.getLooper());
889         mNetworkController.setUserSetupComplete(mUserSetup);
890         mHotspotController = new HotspotControllerImpl(mContext);
891         mBluetoothController = new BluetoothControllerImpl(mContext, mHandlerThread.getLooper());
892         mSecurityController = new SecurityControllerImpl(mContext);
893         if (mContext.getResources().getBoolean(R.bool.config_showRotationLock)) {
894             mRotationLockController = new RotationLockControllerImpl(mContext);
895         }
896         mUserInfoController = new UserInfoController(mContext);
897         mVolumeComponent = getComponent(VolumeComponent.class);
898         if (mVolumeComponent != null) {
899             mZenModeController = mVolumeComponent.getZenController();
900         }
901         mCastController = new CastControllerImpl(mContext);
902 
903         initSignalCluster(mStatusBarView);
904         initSignalCluster(mKeyguardStatusBar);
905         initEmergencyCryptkeeperText();
906 
907         mFlashlightController = new FlashlightController(mContext);
908         mKeyguardBottomArea.setFlashlightController(mFlashlightController);
909         mKeyguardBottomArea.setPhoneStatusBar(this);
910         mKeyguardBottomArea.setUserSetupComplete(mUserSetup);
911         mAccessibilityController = new AccessibilityController(mContext);
912         mKeyguardBottomArea.setAccessibilityController(mAccessibilityController);
913         mNextAlarmController = new NextAlarmController(mContext);
914         mLightStatusBarController = new LightStatusBarController(mIconController,
915                 mBatteryController);
916         mKeyguardMonitor = new KeyguardMonitor(mContext);
917         mUserSwitcherController = new UserSwitcherController(mContext, mKeyguardMonitor,
918                 mHandler, this);
919         if (UserManager.get(mContext).isUserSwitcherEnabled()) {
920             createUserSwitcher();
921         }
922 
923         // Set up the quick settings tile panel
924         AutoReinflateContainer container = (AutoReinflateContainer) mStatusBarWindow.findViewById(
925                 R.id.qs_auto_reinflate_container);
926         if (container != null) {
927             final QSTileHost qsh = SystemUIFactory.getInstance().createQSTileHost(mContext, this,
928                     mBluetoothController, mLocationController, mRotationLockController,
929                     mNetworkController, mZenModeController, mHotspotController,
930                     mCastController, mFlashlightController,
931                     mUserSwitcherController, mUserInfoController, mKeyguardMonitor,
932                     mSecurityController, mBatteryController, mIconController,
933                     mNextAlarmController);
934             mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow);
935             container.addInflateListener(new InflateListener() {
936                 @Override
937                 public void onInflated(View v) {
938                     QSContainer qsContainer = (QSContainer) v.findViewById(
939                             R.id.quick_settings_container);
940                     qsContainer.setHost(qsh);
941                     mQSPanel = qsContainer.getQsPanel();
942                     mQSPanel.setBrightnessMirror(mBrightnessMirrorController);
943                     mKeyguardStatusBar.setQSPanel(mQSPanel);
944                     mHeader = qsContainer.getHeader();
945                     initSignalCluster(mHeader);
946                     mHeader.setActivityStarter(PhoneStatusBar.this);
947                 }
948             });
949         }
950 
951         // User info. Trigger first load.
952         mKeyguardStatusBar.setUserInfoController(mUserInfoController);
953         mKeyguardStatusBar.setUserSwitcherController(mUserSwitcherController);
954         mUserInfoController.reloadUserInfo();
955 
956         ((BatteryMeterView) mStatusBarView.findViewById(R.id.battery)).setBatteryController(
957                 mBatteryController);
958         mKeyguardStatusBar.setBatteryController(mBatteryController);
959 
960         mReportRejectedTouch = mStatusBarWindow.findViewById(R.id.report_rejected_touch);
961         if (mReportRejectedTouch != null) {
962             updateReportRejectedTouchVisibility();
963             mReportRejectedTouch.setOnClickListener(v -> {
964                 Uri session = mFalsingManager.reportRejectedTouch();
965                 if (session == null) { return; }
966 
967                 StringWriter message = new StringWriter();
968                 message.write("Build info: ");
969                 message.write(SystemProperties.get("ro.build.description"));
970                 message.write("\nSerial number: ");
971                 message.write(SystemProperties.get("ro.serialno"));
972                 message.write("\n");
973 
974                 PrintWriter falsingPw = new PrintWriter(message);
975                 FalsingLog.dump(falsingPw);
976                 falsingPw.flush();
977 
978                 startActivityDismissingKeyguard(Intent.createChooser(new Intent(Intent.ACTION_SEND)
979                                 .setType("*/*")
980                                 .putExtra(Intent.EXTRA_SUBJECT, "Rejected touch report")
981                                 .putExtra(Intent.EXTRA_STREAM, session)
982                                 .putExtra(Intent.EXTRA_TEXT, message.toString()),
983                         "Share rejected touch report")
984                                 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK),
985                         true /* onlyProvisioned */, true /* dismissShade */);
986             });
987         }
988 
989 
990         PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
991         mBroadcastReceiver.onReceive(mContext,
992                 new Intent(pm.isScreenOn() ? Intent.ACTION_SCREEN_ON : Intent.ACTION_SCREEN_OFF));
993         mGestureWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
994                 "GestureWakeLock");
995         mVibrator = mContext.getSystemService(Vibrator.class);
996 
997         // receive broadcasts
998         IntentFilter filter = new IntentFilter();
999         filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
1000         filter.addAction(Intent.ACTION_SCREEN_OFF);
1001         filter.addAction(Intent.ACTION_SCREEN_ON);
1002         filter.addAction(DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG);
1003         context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
1004 
1005         IntentFilter demoFilter = new IntentFilter();
1006         if (DEBUG_MEDIA_FAKE_ARTWORK) {
1007             demoFilter.addAction(ACTION_FAKE_ARTWORK);
1008         }
1009         demoFilter.addAction(ACTION_DEMO);
1010         context.registerReceiverAsUser(mDemoReceiver, UserHandle.ALL, demoFilter,
1011                 android.Manifest.permission.DUMP, null);
1012 
1013         // listen for USER_SETUP_COMPLETE setting (per-user)
1014         resetUserSetupObserver();
1015 
1016         // disable profiling bars, since they overlap and clutter the output on app windows
1017         ThreadedRenderer.overrideProperty("disableProfileBars", "true");
1018 
1019         // Private API call to make the shadows look better for Recents
1020         ThreadedRenderer.overrideProperty("ambientRatio", String.valueOf(1.5f));
1021 
1022         return mStatusBarView;
1023     }
1024 
initEmergencyCryptkeeperText()1025     private void initEmergencyCryptkeeperText() {
1026         View emergencyViewStub = mStatusBarWindow.findViewById(R.id.emergency_cryptkeeper_text);
1027         if (mNetworkController.hasEmergencyCryptKeeperText()) {
1028             if (emergencyViewStub != null) {
1029                 ((ViewStub) emergencyViewStub).inflate();
1030             }
1031             mNetworkController.addSignalCallback(new NetworkController.SignalCallback() {
1032                 @Override
1033                 public void setIsAirplaneMode(NetworkController.IconState icon) {
1034                     recomputeDisableFlags(true /* animate */);
1035                 }
1036             });
1037         } else if (emergencyViewStub != null) {
1038             ViewGroup parent = (ViewGroup) emergencyViewStub.getParent();
1039             parent.removeView(emergencyViewStub);
1040         }
1041     }
1042 
createBatteryController()1043     protected BatteryController createBatteryController() {
1044         return new BatteryControllerImpl(mContext);
1045     }
1046 
inflateOverflowContainer()1047     private void inflateOverflowContainer() {
1048         mKeyguardIconOverflowContainer =
1049                 (NotificationOverflowContainer) LayoutInflater.from(mContext).inflate(
1050                         R.layout.status_bar_notification_keyguard_overflow, mStackScroller, false);
1051         mKeyguardIconOverflowContainer.setOnActivatedListener(this);
1052         mKeyguardIconOverflowContainer.setOnClickListener(mOverflowClickListener);
1053         mStackScroller.setOverflowContainer(mKeyguardIconOverflowContainer);
1054     }
1055 
1056     @Override
onDensityOrFontScaleChanged()1057     protected void onDensityOrFontScaleChanged() {
1058         super.onDensityOrFontScaleChanged();
1059         mScrimController.onDensityOrFontScaleChanged();
1060         mStatusBarView.onDensityOrFontScaleChanged();
1061         if (mBrightnessMirrorController != null) {
1062             mBrightnessMirrorController.onDensityOrFontScaleChanged();
1063         }
1064         inflateSignalClusters();
1065         mIconController.onDensityOrFontScaleChanged();
1066         inflateDismissView();
1067         updateClearAll();
1068         inflateEmptyShadeView();
1069         updateEmptyShadeView();
1070         inflateOverflowContainer();
1071         mStatusBarKeyguardViewManager.onDensityOrFontScaleChanged();
1072         mUserInfoController.onDensityOrFontScaleChanged();
1073         if (mUserSwitcherController != null) {
1074             mUserSwitcherController.onDensityOrFontScaleChanged();
1075         }
1076         if (mKeyguardUserSwitcher != null) {
1077             mKeyguardUserSwitcher.onDensityOrFontScaleChanged();
1078         }
1079     }
1080 
inflateSignalClusters()1081     private void inflateSignalClusters() {
1082         SignalClusterView signalClusterView = reinflateSignalCluster(mStatusBarView);
1083         mIconController.setSignalCluster(signalClusterView);
1084         reinflateSignalCluster(mKeyguardStatusBar);
1085     }
1086 
reinflateSignalCluster(View view)1087     private SignalClusterView reinflateSignalCluster(View view) {
1088         SignalClusterView signalCluster =
1089                 (SignalClusterView) view.findViewById(R.id.signal_cluster);
1090         if (signalCluster != null) {
1091             ViewParent parent = signalCluster.getParent();
1092             if (parent instanceof ViewGroup) {
1093                 ViewGroup viewParent = (ViewGroup) parent;
1094                 int index = viewParent.indexOfChild(signalCluster);
1095                 viewParent.removeView(signalCluster);
1096                 SignalClusterView newCluster = (SignalClusterView) LayoutInflater.from(mContext)
1097                         .inflate(R.layout.signal_cluster_view, viewParent, false);
1098                 ViewGroup.MarginLayoutParams layoutParams =
1099                         (ViewGroup.MarginLayoutParams) viewParent.getLayoutParams();
1100                 layoutParams.setMarginsRelative(
1101                         mContext.getResources().getDimensionPixelSize(
1102                                 R.dimen.signal_cluster_margin_start),
1103                         0, 0, 0);
1104                 newCluster.setLayoutParams(layoutParams);
1105                 newCluster.setSecurityController(mSecurityController);
1106                 newCluster.setNetworkController(mNetworkController);
1107                 viewParent.addView(newCluster, index);
1108                 return newCluster;
1109             }
1110             return signalCluster;
1111         }
1112         return null;
1113     }
1114 
inflateEmptyShadeView()1115     private void inflateEmptyShadeView() {
1116         mEmptyShadeView = (EmptyShadeView) LayoutInflater.from(mContext).inflate(
1117                 R.layout.status_bar_no_notifications, mStackScroller, false);
1118         mStackScroller.setEmptyShadeView(mEmptyShadeView);
1119     }
1120 
inflateDismissView()1121     private void inflateDismissView() {
1122         mDismissView = (DismissView) LayoutInflater.from(mContext).inflate(
1123                 R.layout.status_bar_notification_dismiss_all, mStackScroller, false);
1124         mDismissView.setOnButtonClickListener(new View.OnClickListener() {
1125             @Override
1126             public void onClick(View v) {
1127                 MetricsLogger.action(mContext, MetricsEvent.ACTION_DISMISS_ALL_NOTES);
1128                 clearAllNotifications();
1129             }
1130         });
1131         mStackScroller.setDismissView(mDismissView);
1132     }
1133 
createUserSwitcher()1134     protected void createUserSwitcher() {
1135         mKeyguardUserSwitcher = new KeyguardUserSwitcher(mContext,
1136                 (ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_user_switcher),
1137                 mKeyguardStatusBar, mNotificationPanel, mUserSwitcherController);
1138     }
1139 
inflateStatusBarWindow(Context context)1140     protected void inflateStatusBarWindow(Context context) {
1141         mStatusBarWindow = (StatusBarWindowView) View.inflate(context,
1142                 R.layout.super_status_bar, null);
1143     }
1144 
createNavigationBarView(Context context)1145     protected void createNavigationBarView(Context context) {
1146         inflateNavigationBarView(context);
1147         mNavigationBarView.setDisabledFlags(mDisabled1);
1148         mNavigationBarView.setComponents(mRecents, getComponent(Divider.class));
1149         mNavigationBarView.setOnVerticalChangedListener(
1150                 new NavigationBarView.OnVerticalChangedListener() {
1151             @Override
1152             public void onVerticalChanged(boolean isVertical) {
1153                 if (mAssistManager != null) {
1154                     mAssistManager.onConfigurationChanged();
1155                 }
1156                 mNotificationPanel.setQsScrimEnabled(!isVertical);
1157             }
1158         });
1159         mNavigationBarView.setOnTouchListener(new View.OnTouchListener() {
1160             @Override
1161             public boolean onTouch(View v, MotionEvent event) {
1162                 checkUserAutohide(v, event);
1163                 return false;
1164             }});
1165     }
1166 
inflateNavigationBarView(Context context)1167     protected void inflateNavigationBarView(Context context) {
1168         mNavigationBarView = (NavigationBarView) View.inflate(
1169                 context, R.layout.navigation_bar, null);
1170     }
1171 
initSignalCluster(View containerView)1172     protected void initSignalCluster(View containerView) {
1173         SignalClusterView signalCluster =
1174                 (SignalClusterView) containerView.findViewById(R.id.signal_cluster);
1175         if (signalCluster != null) {
1176             signalCluster.setSecurityController(mSecurityController);
1177             signalCluster.setNetworkController(mNetworkController);
1178         }
1179     }
1180 
clearAllNotifications()1181     public void clearAllNotifications() {
1182 
1183         // animate-swipe all dismissable notifications, then animate the shade closed
1184         int numChildren = mStackScroller.getChildCount();
1185 
1186         final ArrayList<View> viewsToHide = new ArrayList<View>(numChildren);
1187         for (int i = 0; i < numChildren; i++) {
1188             final View child = mStackScroller.getChildAt(i);
1189             if (child instanceof ExpandableNotificationRow) {
1190                 if (mStackScroller.canChildBeDismissed(child)) {
1191                     if (child.getVisibility() == View.VISIBLE) {
1192                         viewsToHide.add(child);
1193                     }
1194                 }
1195                 ExpandableNotificationRow row = (ExpandableNotificationRow) child;
1196                 List<ExpandableNotificationRow> children = row.getNotificationChildren();
1197                 if (row.areChildrenExpanded() && children != null) {
1198                     for (ExpandableNotificationRow childRow : children) {
1199                         if (mStackScroller.canChildBeDismissed(childRow)) {
1200                             if (childRow.getVisibility() == View.VISIBLE) {
1201                                 viewsToHide.add(childRow);
1202                             }
1203                         }
1204                     }
1205                 }
1206             }
1207         }
1208         if (viewsToHide.isEmpty()) {
1209             animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
1210             return;
1211         }
1212 
1213         addPostCollapseAction(new Runnable() {
1214             @Override
1215             public void run() {
1216                 mStackScroller.setDismissAllInProgress(false);
1217                 try {
1218                     mBarService.onClearAllNotifications(mCurrentUserId);
1219                 } catch (Exception ex) { }
1220             }
1221         });
1222 
1223         performDismissAllAnimations(viewsToHide);
1224 
1225     }
1226 
performDismissAllAnimations(ArrayList<View> hideAnimatedList)1227     private void performDismissAllAnimations(ArrayList<View> hideAnimatedList) {
1228         Runnable animationFinishAction = new Runnable() {
1229             @Override
1230             public void run() {
1231                 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
1232             }
1233         };
1234 
1235         // let's disable our normal animations
1236         mStackScroller.setDismissAllInProgress(true);
1237 
1238         // Decrease the delay for every row we animate to give the sense of
1239         // accelerating the swipes
1240         int rowDelayDecrement = 10;
1241         int currentDelay = 140;
1242         int totalDelay = 180;
1243         int numItems = hideAnimatedList.size();
1244         for (int i = numItems - 1; i >= 0; i--) {
1245             View view = hideAnimatedList.get(i);
1246             Runnable endRunnable = null;
1247             if (i == 0) {
1248                 endRunnable = animationFinishAction;
1249             }
1250             mStackScroller.dismissViewAnimated(view, endRunnable, totalDelay, 260);
1251             currentDelay = Math.max(50, currentDelay - rowDelayDecrement);
1252             totalDelay += currentDelay;
1253         }
1254     }
1255 
1256     @Override
setZenMode(int mode)1257     protected void setZenMode(int mode) {
1258         super.setZenMode(mode);
1259         if (mIconPolicy != null) {
1260             mIconPolicy.setZenMode(mode);
1261         }
1262     }
1263 
startKeyguard()1264     protected void startKeyguard() {
1265         Trace.beginSection("PhoneStatusBar#startKeyguard");
1266         KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class);
1267         mFingerprintUnlockController = new FingerprintUnlockController(mContext,
1268                 mStatusBarWindowManager, mDozeScrimController, keyguardViewMediator,
1269                 mScrimController, this);
1270         mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this,
1271                 getBouncerContainer(), mStatusBarWindowManager, mScrimController,
1272                 mFingerprintUnlockController);
1273         mKeyguardIndicationController.setStatusBarKeyguardViewManager(
1274                 mStatusBarKeyguardViewManager);
1275         mFingerprintUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
1276         mIconPolicy.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
1277         mRemoteInputController.addCallback(mStatusBarKeyguardViewManager);
1278 
1279         mRemoteInputController.addCallback(new RemoteInputController.Callback() {
1280             @Override
1281             public void onRemoteInputSent(Entry entry) {
1282                 if (FORCE_REMOTE_INPUT_HISTORY && mKeysKeptForRemoteInput.contains(entry.key)) {
1283                     removeNotification(entry.key, null);
1284                 } else if (mRemoteInputEntriesToRemoveOnCollapse.contains(entry)) {
1285                     // We're currently holding onto this notification, but from the apps point of
1286                     // view it is already canceled, so we'll need to cancel it on the apps behalf
1287                     // after sending - unless the app posts an update in the mean time, so wait a
1288                     // bit.
1289                     mHandler.postDelayed(() -> {
1290                         if (mRemoteInputEntriesToRemoveOnCollapse.remove(entry)) {
1291                             removeNotification(entry.key, null);
1292                         }
1293                     }, REMOTE_INPUT_KEPT_ENTRY_AUTO_CANCEL_DELAY);
1294                 }
1295             }
1296         });
1297 
1298         mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback();
1299         mLightStatusBarController.setFingerprintUnlockController(mFingerprintUnlockController);
1300         Trace.endSection();
1301     }
1302 
1303     @Override
getStatusBarView()1304     protected View getStatusBarView() {
1305         return mStatusBarView;
1306     }
1307 
getStatusBarWindow()1308     public StatusBarWindowView getStatusBarWindow() {
1309         return mStatusBarWindow;
1310     }
1311 
getBouncerContainer()1312     protected ViewGroup getBouncerContainer() {
1313         return mStatusBarWindow;
1314     }
1315 
getStatusBarHeight()1316     public int getStatusBarHeight() {
1317         if (mNaturalBarHeight < 0) {
1318             final Resources res = mContext.getResources();
1319             mNaturalBarHeight =
1320                     res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
1321         }
1322         return mNaturalBarHeight;
1323     }
1324 
1325     private View.OnClickListener mRecentsClickListener = new View.OnClickListener() {
1326         @Override
1327         public void onClick(View v) {
1328             awakenDreams();
1329             toggleRecentApps();
1330         }
1331     };
1332 
1333     @Override
toggleSplitScreenMode(int metricsDockAction, int metricsUndockAction)1334     protected void toggleSplitScreenMode(int metricsDockAction, int metricsUndockAction) {
1335         if (mRecents == null) {
1336             return;
1337         }
1338         int dockSide = WindowManagerProxy.getInstance().getDockSide();
1339         if (dockSide == WindowManager.DOCKED_INVALID) {
1340             mRecents.dockTopTask(NavigationBarGestureHelper.DRAG_MODE_NONE,
1341                     ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, null, metricsDockAction);
1342         } else {
1343             EventBus.getDefault().send(new UndockingTaskEvent());
1344             if (metricsUndockAction != -1) {
1345                 MetricsLogger.action(mContext, metricsUndockAction);
1346             }
1347         }
1348     }
1349 
1350     private final View.OnLongClickListener mLongPressHomeListener
1351             = new View.OnLongClickListener() {
1352         @Override
1353         public boolean onLongClick(View v) {
1354             if (shouldDisableNavbarGestures()) {
1355                 return false;
1356             }
1357             MetricsLogger.action(mContext, MetricsEvent.ACTION_ASSIST_LONG_PRESS);
1358             mAssistManager.startAssist(new Bundle() /* args */);
1359             awakenDreams();
1360             if (mNavigationBarView != null) {
1361                 mNavigationBarView.abortCurrentGesture();
1362             }
1363             return true;
1364         }
1365     };
1366 
1367     private final View.OnTouchListener mHomeActionListener = new View.OnTouchListener() {
1368         public boolean mBlockedThisTouch;
1369 
1370         @Override
1371         public boolean onTouch(View v, MotionEvent event) {
1372             if (mBlockedThisTouch && event.getActionMasked() != MotionEvent.ACTION_DOWN) {
1373                 return true;
1374             }
1375             // If an incoming call is ringing, HOME is totally disabled.
1376             // (The user is already on the InCallUI at this point,
1377             // and his ONLY options are to answer or reject the call.)
1378             switch (event.getAction()) {
1379                 case MotionEvent.ACTION_DOWN:
1380                     mBlockedThisTouch = false;
1381                     TelecomManager telecomManager = mContext.getSystemService(TelecomManager.class);
1382                     if (telecomManager != null && telecomManager.isRinging()) {
1383                         if (mStatusBarKeyguardViewManager.isShowing()) {
1384                             Log.i(TAG, "Ignoring HOME; there's a ringing incoming call. " +
1385                                     "No heads up");
1386                             mBlockedThisTouch = true;
1387                             return true;
1388                         }
1389                     }
1390                     break;
1391                 case MotionEvent.ACTION_UP:
1392                 case MotionEvent.ACTION_CANCEL:
1393                     awakenDreams();
1394                     break;
1395             }
1396             return false;
1397         }
1398     };
1399 
awakenDreams()1400     private void awakenDreams() {
1401         if (mDreamManager != null) {
1402             try {
1403                 mDreamManager.awaken();
1404             } catch (RemoteException e) {
1405                 // fine, stay asleep then
1406             }
1407         }
1408     }
1409 
prepareNavigationBarView()1410     private void prepareNavigationBarView() {
1411         mNavigationBarView.reorient();
1412 
1413         ButtonDispatcher recentsButton = mNavigationBarView.getRecentsButton();
1414         recentsButton.setOnClickListener(mRecentsClickListener);
1415         recentsButton.setOnTouchListener(mRecentsPreloadOnTouchListener);
1416         recentsButton.setLongClickable(true);
1417         recentsButton.setOnLongClickListener(this::handleLongPressBackRecents);
1418 
1419         ButtonDispatcher backButton = mNavigationBarView.getBackButton();
1420         backButton.setLongClickable(true);
1421         backButton.setOnLongClickListener(this::handleLongPressBackRecents);
1422 
1423         ButtonDispatcher homeButton = mNavigationBarView.getHomeButton();
1424         homeButton.setOnTouchListener(mHomeActionListener);
1425         homeButton.setOnLongClickListener(mLongPressHomeListener);
1426 
1427         mAssistManager.onConfigurationChanged();
1428     }
1429 
1430     // For small-screen devices (read: phones) that lack hardware navigation buttons
addNavigationBar()1431     protected void addNavigationBar() {
1432         if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + mNavigationBarView);
1433         if (mNavigationBarView == null) return;
1434 
1435         try {
1436             WindowManagerGlobal.getWindowManagerService()
1437                     .watchRotation(new IRotationWatcher.Stub() {
1438                 @Override
1439                 public void onRotationChanged(int rotation) throws RemoteException {
1440                     // We need this to be scheduled as early as possible to beat the redrawing of
1441                     // window in response to the orientation change.
1442                     Message msg = Message.obtain(mHandler, () -> {
1443                         if (mNavigationBarView != null
1444                                 && mNavigationBarView.needsReorient(rotation)) {
1445                             repositionNavigationBar();
1446                         }
1447                     });
1448                     msg.setAsynchronous(true);
1449                     mHandler.sendMessageAtFrontOfQueue(msg);
1450                 }
1451             });
1452         } catch (RemoteException e) {
1453             throw e.rethrowFromSystemServer();
1454         }
1455 
1456         prepareNavigationBarView();
1457 
1458         mWindowManager.addView(mNavigationBarView, getNavigationBarLayoutParams());
1459     }
1460 
repositionNavigationBar()1461     protected void repositionNavigationBar() {
1462         if (mNavigationBarView == null || !mNavigationBarView.isAttachedToWindow()) return;
1463 
1464         prepareNavigationBarView();
1465 
1466         mWindowManager.updateViewLayout(mNavigationBarView, mNavigationBarView.getLayoutParams());
1467     }
1468 
notifyNavigationBarScreenOn(boolean screenOn)1469     private void notifyNavigationBarScreenOn(boolean screenOn) {
1470         if (mNavigationBarView == null) return;
1471         mNavigationBarView.notifyScreenOn(screenOn);
1472     }
1473 
getNavigationBarLayoutParams()1474     private WindowManager.LayoutParams getNavigationBarLayoutParams() {
1475         WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
1476                 LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
1477                 WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
1478                     0
1479                     | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
1480                     | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
1481                     | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
1482                     | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
1483                     | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
1484                     | WindowManager.LayoutParams.FLAG_SLIPPERY,
1485                 PixelFormat.TRANSLUCENT);
1486         // this will allow the navbar to run in an overlay on devices that support this
1487         if (ActivityManager.isHighEndGfx()) {
1488             lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
1489         }
1490 
1491         lp.setTitle("NavigationBar");
1492         lp.windowAnimations = 0;
1493         return lp;
1494     }
1495 
1496     @Override
setIcon(String slot, StatusBarIcon icon)1497     public void setIcon(String slot, StatusBarIcon icon) {
1498         mIconController.setIcon(slot, icon);
1499     }
1500 
1501     @Override
removeIcon(String slot)1502     public void removeIcon(String slot) {
1503         mIconController.removeIcon(slot);
1504     }
1505 
getCurrentUserHandle()1506     public UserHandle getCurrentUserHandle() {
1507         return new UserHandle(mCurrentUserId);
1508     }
1509 
1510     @Override
addNotification(StatusBarNotification notification, RankingMap ranking, Entry oldEntry)1511     public void addNotification(StatusBarNotification notification, RankingMap ranking,
1512             Entry oldEntry) {
1513         if (DEBUG) Log.d(TAG, "addNotification key=" + notification.getKey());
1514 
1515         mNotificationData.updateRanking(ranking);
1516         Entry shadeEntry = createNotificationViews(notification);
1517         if (shadeEntry == null) {
1518             return;
1519         }
1520         boolean isHeadsUped = shouldPeek(shadeEntry);
1521         if (isHeadsUped) {
1522             mHeadsUpManager.showNotification(shadeEntry);
1523             // Mark as seen immediately
1524             setNotificationShown(notification);
1525         }
1526 
1527         if (!isHeadsUped && notification.getNotification().fullScreenIntent != null) {
1528             if (shouldSuppressFullScreenIntent(notification.getKey())) {
1529                 if (DEBUG) {
1530                     Log.d(TAG, "No Fullscreen intent: suppressed by DND: " + notification.getKey());
1531                 }
1532             } else if (mNotificationData.getImportance(notification.getKey())
1533                     < NotificationListenerService.Ranking.IMPORTANCE_MAX) {
1534                 if (DEBUG) {
1535                     Log.d(TAG, "No Fullscreen intent: not important enough: "
1536                             + notification.getKey());
1537                 }
1538             } else {
1539                 // Stop screensaver if the notification has a full-screen intent.
1540                 // (like an incoming phone call)
1541                 awakenDreams();
1542 
1543                 // not immersive & a full-screen alert should be shown
1544                 if (DEBUG)
1545                     Log.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent");
1546                 try {
1547                     EventLog.writeEvent(EventLogTags.SYSUI_FULLSCREEN_NOTIFICATION,
1548                             notification.getKey());
1549                     notification.getNotification().fullScreenIntent.send();
1550                     shadeEntry.notifyFullScreenIntentLaunched();
1551                     MetricsLogger.count(mContext, "note_fullscreen", 1);
1552                 } catch (PendingIntent.CanceledException e) {
1553                 }
1554             }
1555         }
1556         addNotificationViews(shadeEntry, ranking);
1557         // Recalculate the position of the sliding windows and the titles.
1558         setAreThereNotifications();
1559     }
1560 
shouldSuppressFullScreenIntent(String key)1561     private boolean shouldSuppressFullScreenIntent(String key) {
1562         if (isDeviceInVrMode()) {
1563             return true;
1564         }
1565 
1566         if (mPowerManager.isInteractive()) {
1567             return mNotificationData.shouldSuppressScreenOn(key);
1568         } else {
1569             return mNotificationData.shouldSuppressScreenOff(key);
1570         }
1571     }
1572 
1573     @Override
updateNotificationRanking(RankingMap ranking)1574     protected void updateNotificationRanking(RankingMap ranking) {
1575         mNotificationData.updateRanking(ranking);
1576         updateNotifications();
1577     }
1578 
1579     @Override
removeNotification(String key, RankingMap ranking)1580     public void removeNotification(String key, RankingMap ranking) {
1581         boolean deferRemoval = false;
1582         if (mHeadsUpManager.isHeadsUp(key)) {
1583             // A cancel() in repsonse to a remote input shouldn't be delayed, as it makes the
1584             // sending look longer than it takes.
1585             // Also we should not defer the removal if reordering isn't allowed since otherwise
1586             // some notifications can't disappear before the panel is closed.
1587             boolean ignoreEarliestRemovalTime = mRemoteInputController.isSpinning(key)
1588                     && !FORCE_REMOTE_INPUT_HISTORY
1589                         || !mVisualStabilityManager.isReorderingAllowed();
1590             deferRemoval = !mHeadsUpManager.removeNotification(key,  ignoreEarliestRemovalTime);
1591         }
1592         if (key.equals(mMediaNotificationKey)) {
1593             clearCurrentMediaNotification();
1594             updateMediaMetaData(true, true);
1595         }
1596         if (FORCE_REMOTE_INPUT_HISTORY && mRemoteInputController.isSpinning(key)) {
1597             Entry entry = mNotificationData.get(key);
1598             StatusBarNotification sbn = entry.notification;
1599 
1600             Notification.Builder b = Notification.Builder
1601                     .recoverBuilder(mContext, sbn.getNotification().clone());
1602             CharSequence[] oldHistory = sbn.getNotification().extras
1603                     .getCharSequenceArray(Notification.EXTRA_REMOTE_INPUT_HISTORY);
1604             CharSequence[] newHistory;
1605             if (oldHistory == null) {
1606                 newHistory = new CharSequence[1];
1607             } else {
1608                 newHistory = new CharSequence[oldHistory.length + 1];
1609                 for (int i = 0; i < oldHistory.length; i++) {
1610                     newHistory[i + 1] = oldHistory[i];
1611                 }
1612             }
1613             newHistory[0] = String.valueOf(entry.remoteInputText);
1614             b.setRemoteInputHistory(newHistory);
1615 
1616             Notification newNotification = b.build();
1617 
1618             // Undo any compatibility view inflation
1619             newNotification.contentView = sbn.getNotification().contentView;
1620             newNotification.bigContentView = sbn.getNotification().bigContentView;
1621             newNotification.headsUpContentView = sbn.getNotification().headsUpContentView;
1622 
1623             StatusBarNotification newSbn = new StatusBarNotification(sbn.getPackageName(),
1624                     sbn.getOpPkg(),
1625                     sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
1626                     0, newNotification, sbn.getUser(), sbn.getPostTime());
1627 
1628             updateNotification(newSbn, null);
1629             mKeysKeptForRemoteInput.add(entry.key);
1630             return;
1631         }
1632         if (deferRemoval) {
1633             mLatestRankingMap = ranking;
1634             mHeadsUpEntriesToRemoveOnSwitch.add(mHeadsUpManager.getEntry(key));
1635             return;
1636         }
1637         Entry entry = mNotificationData.get(key);
1638 
1639         if (entry != null && mRemoteInputController.isRemoteInputActive(entry)
1640                 && (entry.row != null && !entry.row.isDismissed())) {
1641             mLatestRankingMap = ranking;
1642             mRemoteInputEntriesToRemoveOnCollapse.add(entry);
1643             return;
1644         }
1645 
1646         if (entry != null && entry.row != null) {
1647             entry.row.setRemoved();
1648         }
1649         // Let's remove the children if this was a summary
1650         handleGroupSummaryRemoved(key, ranking);
1651         StatusBarNotification old = removeNotificationViews(key, ranking);
1652         if (SPEW) Log.d(TAG, "removeNotification key=" + key + " old=" + old);
1653 
1654         if (old != null) {
1655             if (CLOSE_PANEL_WHEN_EMPTIED && !hasActiveNotifications()
1656                     && !mNotificationPanel.isTracking() && !mNotificationPanel.isQsExpanded()) {
1657                 if (mState == StatusBarState.SHADE) {
1658                     animateCollapsePanels();
1659                 } else if (mState == StatusBarState.SHADE_LOCKED && !isCollapsing()) {
1660                     goToKeyguard();
1661                 }
1662             }
1663         }
1664         setAreThereNotifications();
1665     }
1666 
1667     /**
1668      * Ensures that the group children are cancelled immediately when the group summary is cancelled
1669      * instead of waiting for the notification manager to send all cancels. Otherwise this could
1670      * lead to flickers.
1671      *
1672      * This also ensures that the animation looks nice and only consists of a single disappear
1673      * animation instead of multiple.
1674      *
1675      * @param key the key of the notification was removed
1676      * @param ranking the current ranking
1677      */
handleGroupSummaryRemoved(String key, RankingMap ranking)1678     private void handleGroupSummaryRemoved(String key,
1679             RankingMap ranking) {
1680         Entry entry = mNotificationData.get(key);
1681         if (entry != null && entry.row != null
1682                 && entry.row.isSummaryWithChildren()) {
1683             if (entry.notification.getOverrideGroupKey() != null && !entry.row.isDismissed()) {
1684                 // We don't want to remove children for autobundled notifications as they are not
1685                 // always cancelled. We only remove them if they were dismissed by the user.
1686                 return;
1687             }
1688             List<ExpandableNotificationRow> notificationChildren =
1689                     entry.row.getNotificationChildren();
1690             ArrayList<ExpandableNotificationRow> toRemove = new ArrayList<>();
1691             for (int i = 0; i < notificationChildren.size(); i++) {
1692                 ExpandableNotificationRow row = notificationChildren.get(i);
1693                 if ((row.getStatusBarNotification().getNotification().flags
1694                         & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
1695                     // the child is a forground service notification which we can't remove!
1696                     continue;
1697                 }
1698                 toRemove.add(row);
1699                 toRemove.get(i).setKeepInParent(true);
1700                 // we need to set this state earlier as otherwise we might generate some weird
1701                 // animations
1702                 toRemove.get(i).setRemoved();
1703             }
1704             for (int i = 0; i < toRemove.size(); i++) {
1705                 removeNotification(toRemove.get(i).getStatusBarNotification().getKey(), ranking);
1706                 // we need to ensure that the view is actually properly removed from the viewstate
1707                 // as this won't happen anymore when kept in the parent.
1708                 mStackScroller.removeViewStateForView(toRemove.get(i));
1709             }
1710         }
1711     }
1712 
1713     @Override
performRemoveNotification(StatusBarNotification n)1714     protected void performRemoveNotification(StatusBarNotification n) {
1715         Entry entry = mNotificationData.get(n.getKey());
1716         if (mRemoteInputController.isRemoteInputActive(entry)) {
1717             mRemoteInputController.removeRemoteInput(entry, null);
1718         }
1719         super.performRemoveNotification(n);
1720     }
1721 
1722     @Override
refreshLayout(int layoutDirection)1723     protected void refreshLayout(int layoutDirection) {
1724         if (mNavigationBarView != null) {
1725             mNavigationBarView.setLayoutDirection(layoutDirection);
1726         }
1727     }
1728 
updateNotificationShade()1729     private void updateNotificationShade() {
1730         if (mStackScroller == null) return;
1731 
1732         // Do not modify the notifications during collapse.
1733         if (isCollapsing()) {
1734             addPostCollapseAction(new Runnable() {
1735                 @Override
1736                 public void run() {
1737                     updateNotificationShade();
1738                 }
1739             });
1740             return;
1741         }
1742 
1743         ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
1744         ArrayList<ExpandableNotificationRow> toShow = new ArrayList<>(activeNotifications.size());
1745         final int N = activeNotifications.size();
1746         for (int i=0; i<N; i++) {
1747             Entry ent = activeNotifications.get(i);
1748             if (ent.row.isDismissed() || ent.row.isRemoved()) {
1749                 // we don't want to update removed notifications because they could
1750                 // temporarily become children if they were isolated before.
1751                 continue;
1752             }
1753             int vis = ent.notification.getNotification().visibility;
1754 
1755             // Display public version of the notification if we need to redact.
1756             final boolean hideSensitive =
1757                     !userAllowsPrivateNotificationsInPublic(ent.notification.getUserId());
1758             boolean sensitiveNote = vis == Notification.VISIBILITY_PRIVATE;
1759             boolean sensitivePackage = packageHasVisibilityOverride(ent.notification.getKey());
1760             boolean sensitive = (sensitiveNote && hideSensitive) || sensitivePackage;
1761             boolean showingPublic = sensitive && isLockscreenPublicMode();
1762             if (showingPublic) {
1763                 updatePublicContentView(ent, ent.notification);
1764             }
1765             ent.row.setSensitive(sensitive, hideSensitive);
1766             if (ent.autoRedacted && ent.legacy) {
1767                 // TODO: Also fade this? Or, maybe easier (and better), provide a dark redacted form
1768                 // for legacy auto redacted notifications.
1769                 if (showingPublic) {
1770                     ent.row.setShowingLegacyBackground(false);
1771                 } else {
1772                     ent.row.setShowingLegacyBackground(true);
1773                 }
1774             }
1775             if (mGroupManager.isChildInGroupWithSummary(ent.row.getStatusBarNotification())) {
1776                 ExpandableNotificationRow summary = mGroupManager.getGroupSummary(
1777                         ent.row.getStatusBarNotification());
1778                 List<ExpandableNotificationRow> orderedChildren =
1779                         mTmpChildOrderMap.get(summary);
1780                 if (orderedChildren == null) {
1781                     orderedChildren = new ArrayList<>();
1782                     mTmpChildOrderMap.put(summary, orderedChildren);
1783                 }
1784                 orderedChildren.add(ent.row);
1785             } else {
1786                 toShow.add(ent.row);
1787             }
1788 
1789         }
1790 
1791         ArrayList<ExpandableNotificationRow> toRemove = new ArrayList<>();
1792         for (int i=0; i< mStackScroller.getChildCount(); i++) {
1793             View child = mStackScroller.getChildAt(i);
1794             if (!toShow.contains(child) && child instanceof ExpandableNotificationRow) {
1795                 toRemove.add((ExpandableNotificationRow) child);
1796             }
1797         }
1798 
1799         for (ExpandableNotificationRow remove : toRemove) {
1800             if (mGroupManager.isChildInGroupWithSummary(remove.getStatusBarNotification())) {
1801                 // we are only transfering this notification to its parent, don't generate an animation
1802                 mStackScroller.setChildTransferInProgress(true);
1803             }
1804             if (remove.isSummaryWithChildren()) {
1805                 remove.removeAllChildren();
1806             }
1807             mStackScroller.removeView(remove);
1808             mStackScroller.setChildTransferInProgress(false);
1809         }
1810 
1811         removeNotificationChildren();
1812 
1813         for (int i=0; i<toShow.size(); i++) {
1814             View v = toShow.get(i);
1815             if (v.getParent() == null) {
1816                 mVisualStabilityManager.notifyViewAddition(v);
1817                 mStackScroller.addView(v);
1818             }
1819         }
1820 
1821         addNotificationChildrenAndSort();
1822 
1823         // So after all this work notifications still aren't sorted correctly.
1824         // Let's do that now by advancing through toShow and mStackScroller in
1825         // lock-step, making sure mStackScroller matches what we see in toShow.
1826         int j = 0;
1827         for (int i = 0; i < mStackScroller.getChildCount(); i++) {
1828             View child = mStackScroller.getChildAt(i);
1829             if (!(child instanceof ExpandableNotificationRow)) {
1830                 // We don't care about non-notification views.
1831                 continue;
1832             }
1833 
1834             ExpandableNotificationRow targetChild = toShow.get(j);
1835             if (child != targetChild) {
1836                 // Oops, wrong notification at this position. Put the right one
1837                 // here and advance both lists.
1838                 if (mVisualStabilityManager.canReorderNotification(targetChild)) {
1839                     mStackScroller.changeViewPosition(targetChild, i);
1840                 } else {
1841                     mVisualStabilityManager.addReorderingAllowedCallback(this);
1842                 }
1843             }
1844             j++;
1845 
1846         }
1847 
1848         mVisualStabilityManager.onReorderingFinished();
1849         // clear the map again for the next usage
1850         mTmpChildOrderMap.clear();
1851 
1852         updateRowStates();
1853         updateSpeedbump();
1854         updateClearAll();
1855         updateEmptyShadeView();
1856 
1857         updateQsExpansionEnabled();
1858         mShadeUpdates.check();
1859     }
1860 
1861     /**
1862      * Disable QS if device not provisioned.
1863      * If the user switcher is simple then disable QS during setup because
1864      * the user intends to use the lock screen user switcher, QS in not needed.
1865      */
updateQsExpansionEnabled()1866     private void updateQsExpansionEnabled() {
1867         mNotificationPanel.setQsExpansionEnabled(isDeviceProvisioned()
1868                 && (mUserSetup || mUserSwitcherController == null
1869                         || !mUserSwitcherController.isSimpleUserSwitcher())
1870                 && ((mDisabled2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) == 0)
1871                 && !ONLY_CORE_APPS);
1872     }
1873 
addNotificationChildrenAndSort()1874     private void addNotificationChildrenAndSort() {
1875         // Let's now add all notification children which are missing
1876         boolean orderChanged = false;
1877         for (int i = 0; i < mStackScroller.getChildCount(); i++) {
1878             View view = mStackScroller.getChildAt(i);
1879             if (!(view instanceof ExpandableNotificationRow)) {
1880                 // We don't care about non-notification views.
1881                 continue;
1882             }
1883 
1884             ExpandableNotificationRow parent = (ExpandableNotificationRow) view;
1885             List<ExpandableNotificationRow> children = parent.getNotificationChildren();
1886             List<ExpandableNotificationRow> orderedChildren = mTmpChildOrderMap.get(parent);
1887 
1888             for (int childIndex = 0; orderedChildren != null && childIndex < orderedChildren.size();
1889                     childIndex++) {
1890                 ExpandableNotificationRow childView = orderedChildren.get(childIndex);
1891                 if (children == null || !children.contains(childView)) {
1892                     mVisualStabilityManager.notifyViewAddition(childView);
1893                     parent.addChildNotification(childView, childIndex);
1894                     mStackScroller.notifyGroupChildAdded(childView);
1895                 }
1896             }
1897 
1898             // Finally after removing and adding has been beformed we can apply the order.
1899             orderChanged |= parent.applyChildOrder(orderedChildren, mVisualStabilityManager, this);
1900         }
1901         if (orderChanged) {
1902             mStackScroller.generateChildOrderChangedEvent();
1903         }
1904     }
1905 
removeNotificationChildren()1906     private void removeNotificationChildren() {
1907         // First let's remove all children which don't belong in the parents
1908         ArrayList<ExpandableNotificationRow> toRemove = new ArrayList<>();
1909         for (int i = 0; i < mStackScroller.getChildCount(); i++) {
1910             View view = mStackScroller.getChildAt(i);
1911             if (!(view instanceof ExpandableNotificationRow)) {
1912                 // We don't care about non-notification views.
1913                 continue;
1914             }
1915 
1916             ExpandableNotificationRow parent = (ExpandableNotificationRow) view;
1917             List<ExpandableNotificationRow> children = parent.getNotificationChildren();
1918             List<ExpandableNotificationRow> orderedChildren = mTmpChildOrderMap.get(parent);
1919 
1920             if (children != null) {
1921                 toRemove.clear();
1922                 for (ExpandableNotificationRow childRow : children) {
1923                     if ((orderedChildren == null
1924                             || !orderedChildren.contains(childRow))
1925                             && !childRow.keepInParent()) {
1926                         toRemove.add(childRow);
1927                     }
1928                 }
1929                 for (ExpandableNotificationRow remove : toRemove) {
1930                     parent.removeChildNotification(remove);
1931                     if (mNotificationData.get(remove.getStatusBarNotification().getKey()) == null) {
1932                         // We only want to add an animation if the view is completely removed
1933                         // otherwise it's just a transfer
1934                         mStackScroller.notifyGroupChildRemoved(remove,
1935                                 parent.getChildrenContainer());
1936                     }
1937                 }
1938             }
1939         }
1940     }
1941 
1942     @Override
addQsTile(ComponentName tile)1943     public void addQsTile(ComponentName tile) {
1944         mQSPanel.getHost().addTile(tile);
1945     }
1946 
1947     @Override
remQsTile(ComponentName tile)1948     public void remQsTile(ComponentName tile) {
1949         mQSPanel.getHost().removeTile(tile);
1950     }
1951 
1952     @Override
clickTile(ComponentName tile)1953     public void clickTile(ComponentName tile) {
1954         mQSPanel.clickTile(tile);
1955     }
1956 
packageHasVisibilityOverride(String key)1957     private boolean packageHasVisibilityOverride(String key) {
1958         return mNotificationData.getVisibilityOverride(key) == Notification.VISIBILITY_PRIVATE;
1959     }
1960 
updateClearAll()1961     private void updateClearAll() {
1962         boolean showDismissView =
1963                 mState != StatusBarState.KEYGUARD &&
1964                hasActiveClearableNotifications();
1965         mStackScroller.updateDismissView(showDismissView);
1966     }
1967 
1968     /**
1969      * Return whether there are any clearable notifications
1970      */
hasActiveClearableNotifications()1971     private boolean hasActiveClearableNotifications() {
1972         int childCount = mStackScroller.getChildCount();
1973         for (int i = 0; i < childCount; i++) {
1974             View child = mStackScroller.getChildAt(i);
1975             if (!(child instanceof ExpandableNotificationRow)) {
1976                 continue;
1977             }
1978             if (((ExpandableNotificationRow) child).canViewBeDismissed()) {
1979                     return true;
1980             }
1981         }
1982         return false;
1983     }
1984 
updateEmptyShadeView()1985     private void updateEmptyShadeView() {
1986         boolean showEmptyShade =
1987                 mState != StatusBarState.KEYGUARD &&
1988                         mNotificationData.getActiveNotifications().size() == 0;
1989         mNotificationPanel.setShadeEmpty(showEmptyShade);
1990     }
1991 
updateSpeedbump()1992     private void updateSpeedbump() {
1993         int speedBumpIndex = 0;
1994         int currentIndex = 0;
1995         final int N = mStackScroller.getChildCount();
1996         for (int i = 0; i < N; i++) {
1997             View view = mStackScroller.getChildAt(i);
1998             if (view.getVisibility() == View.GONE || !(view instanceof ExpandableNotificationRow)) {
1999                 continue;
2000             }
2001             ExpandableNotificationRow row = (ExpandableNotificationRow) view;
2002             currentIndex++;
2003             if (!mNotificationData.isAmbient(row.getStatusBarNotification().getKey())) {
2004                 speedBumpIndex = currentIndex;
2005             }
2006         }
2007         mStackScroller.updateSpeedBumpIndex(speedBumpIndex);
2008     }
2009 
isTopLevelChild(Entry entry)2010     public static boolean isTopLevelChild(Entry entry) {
2011         return entry.row.getParent() instanceof NotificationStackScrollLayout;
2012     }
2013 
2014     @Override
updateNotifications()2015     protected void updateNotifications() {
2016         mNotificationData.filterAndSort();
2017 
2018         updateNotificationShade();
2019         mIconController.updateNotificationIcons(mNotificationData);
2020     }
2021 
requestNotificationUpdate()2022     public void requestNotificationUpdate() {
2023         updateNotifications();
2024     }
2025 
2026     @Override
setAreThereNotifications()2027     protected void setAreThereNotifications() {
2028 
2029         if (SPEW) {
2030             final boolean clearable = hasActiveNotifications() &&
2031                     hasActiveClearableNotifications();
2032             Log.d(TAG, "setAreThereNotifications: N=" +
2033                     mNotificationData.getActiveNotifications().size() + " any=" +
2034                     hasActiveNotifications() + " clearable=" + clearable);
2035         }
2036 
2037         final View nlo = mStatusBarView.findViewById(R.id.notification_lights_out);
2038         final boolean showDot = hasActiveNotifications() && !areLightsOn();
2039         if (showDot != (nlo.getAlpha() == 1.0f)) {
2040             if (showDot) {
2041                 nlo.setAlpha(0f);
2042                 nlo.setVisibility(View.VISIBLE);
2043             }
2044             nlo.animate()
2045                 .alpha(showDot?1:0)
2046                 .setDuration(showDot?750:250)
2047                 .setInterpolator(new AccelerateInterpolator(2.0f))
2048                 .setListener(showDot ? null : new AnimatorListenerAdapter() {
2049                     @Override
2050                     public void onAnimationEnd(Animator _a) {
2051                         nlo.setVisibility(View.GONE);
2052                     }
2053                 })
2054                 .start();
2055         }
2056 
2057         findAndUpdateMediaNotifications();
2058     }
2059 
findAndUpdateMediaNotifications()2060     public void findAndUpdateMediaNotifications() {
2061         boolean metaDataChanged = false;
2062 
2063         synchronized (mNotificationData) {
2064             ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
2065             final int N = activeNotifications.size();
2066 
2067             // Promote the media notification with a controller in 'playing' state, if any.
2068             Entry mediaNotification = null;
2069             MediaController controller = null;
2070             for (int i = 0; i < N; i++) {
2071                 final Entry entry = activeNotifications.get(i);
2072                 if (isMediaNotification(entry)) {
2073                     final MediaSession.Token token =
2074                             entry.notification.getNotification().extras
2075                             .getParcelable(Notification.EXTRA_MEDIA_SESSION);
2076                     if (token != null) {
2077                         MediaController aController = new MediaController(mContext, token);
2078                         if (PlaybackState.STATE_PLAYING ==
2079                                 getMediaControllerPlaybackState(aController)) {
2080                             if (DEBUG_MEDIA) {
2081                                 Log.v(TAG, "DEBUG_MEDIA: found mediastyle controller matching "
2082                                         + entry.notification.getKey());
2083                             }
2084                             mediaNotification = entry;
2085                             controller = aController;
2086                             break;
2087                         }
2088                     }
2089                 }
2090             }
2091             if (mediaNotification == null) {
2092                 // Still nothing? OK, let's just look for live media sessions and see if they match
2093                 // one of our notifications. This will catch apps that aren't (yet!) using media
2094                 // notifications.
2095 
2096                 if (mMediaSessionManager != null) {
2097                     final List<MediaController> sessions
2098                             = mMediaSessionManager.getActiveSessionsForUser(
2099                                     null,
2100                                     UserHandle.USER_ALL);
2101 
2102                     for (MediaController aController : sessions) {
2103                         if (PlaybackState.STATE_PLAYING ==
2104                                 getMediaControllerPlaybackState(aController)) {
2105                             // now to see if we have one like this
2106                             final String pkg = aController.getPackageName();
2107 
2108                             for (int i = 0; i < N; i++) {
2109                                 final Entry entry = activeNotifications.get(i);
2110                                 if (entry.notification.getPackageName().equals(pkg)) {
2111                                     if (DEBUG_MEDIA) {
2112                                         Log.v(TAG, "DEBUG_MEDIA: found controller matching "
2113                                             + entry.notification.getKey());
2114                                     }
2115                                     controller = aController;
2116                                     mediaNotification = entry;
2117                                     break;
2118                                 }
2119                             }
2120                         }
2121                     }
2122                 }
2123             }
2124 
2125             if (controller != null && !sameSessions(mMediaController, controller)) {
2126                 // We have a new media session
2127                 clearCurrentMediaNotification();
2128                 mMediaController = controller;
2129                 mMediaController.registerCallback(mMediaListener);
2130                 mMediaMetadata = mMediaController.getMetadata();
2131                 if (DEBUG_MEDIA) {
2132                     Log.v(TAG, "DEBUG_MEDIA: insert listener, receive metadata: "
2133                             + mMediaMetadata);
2134                 }
2135 
2136                 if (mediaNotification != null) {
2137                     mMediaNotificationKey = mediaNotification.notification.getKey();
2138                     if (DEBUG_MEDIA) {
2139                         Log.v(TAG, "DEBUG_MEDIA: Found new media notification: key="
2140                                 + mMediaNotificationKey + " controller=" + mMediaController);
2141                     }
2142                 }
2143                 metaDataChanged = true;
2144             }
2145         }
2146 
2147         if (metaDataChanged) {
2148             updateNotifications();
2149         }
2150         updateMediaMetaData(metaDataChanged, true);
2151     }
2152 
getMediaControllerPlaybackState(MediaController controller)2153     private int getMediaControllerPlaybackState(MediaController controller) {
2154         if (controller != null) {
2155             final PlaybackState playbackState = controller.getPlaybackState();
2156             if (playbackState != null) {
2157                 return playbackState.getState();
2158             }
2159         }
2160         return PlaybackState.STATE_NONE;
2161     }
2162 
isPlaybackActive(int state)2163     private boolean isPlaybackActive(int state) {
2164         if (state != PlaybackState.STATE_STOPPED
2165                 && state != PlaybackState.STATE_ERROR
2166                 && state != PlaybackState.STATE_NONE) {
2167             return true;
2168         }
2169         return false;
2170     }
2171 
clearCurrentMediaNotification()2172     private void clearCurrentMediaNotification() {
2173         mMediaNotificationKey = null;
2174         mMediaMetadata = null;
2175         if (mMediaController != null) {
2176             if (DEBUG_MEDIA) {
2177                 Log.v(TAG, "DEBUG_MEDIA: Disconnecting from old controller: "
2178                         + mMediaController.getPackageName());
2179             }
2180             mMediaController.unregisterCallback(mMediaListener);
2181         }
2182         mMediaController = null;
2183     }
2184 
sameSessions(MediaController a, MediaController b)2185     private boolean sameSessions(MediaController a, MediaController b) {
2186         if (a == b) return true;
2187         if (a == null) return false;
2188         return a.controlsSameSession(b);
2189     }
2190 
2191     /**
2192      * Hide the album artwork that is fading out and release its bitmap.
2193      */
2194     private Runnable mHideBackdropFront = new Runnable() {
2195         @Override
2196         public void run() {
2197             if (DEBUG_MEDIA) {
2198                 Log.v(TAG, "DEBUG_MEDIA: removing fade layer");
2199             }
2200             mBackdropFront.setVisibility(View.INVISIBLE);
2201             mBackdropFront.animate().cancel();
2202             mBackdropFront.setImageDrawable(null);
2203         }
2204     };
2205 
2206     /**
2207      * Refresh or remove lockscreen artwork from media metadata or the lockscreen wallpaper.
2208      */
updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation)2209     public void updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation) {
2210         Trace.beginSection("PhoneStatusBar#updateMediaMetaData");
2211         if (!SHOW_LOCKSCREEN_MEDIA_ARTWORK) {
2212             Trace.endSection();
2213             return;
2214         }
2215 
2216         if (mBackdrop == null) {
2217             Trace.endSection();
2218             return; // called too early
2219         }
2220 
2221         if (mLaunchTransitionFadingAway) {
2222             mBackdrop.setVisibility(View.INVISIBLE);
2223             Trace.endSection();
2224             return;
2225         }
2226 
2227         if (DEBUG_MEDIA) {
2228             Log.v(TAG, "DEBUG_MEDIA: updating album art for notification " + mMediaNotificationKey
2229                     + " metadata=" + mMediaMetadata
2230                     + " metaDataChanged=" + metaDataChanged
2231                     + " state=" + mState);
2232         }
2233 
2234         Drawable artworkDrawable = null;
2235         if (mMediaMetadata != null) {
2236             Bitmap artworkBitmap = null;
2237             artworkBitmap = mMediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ART);
2238             if (artworkBitmap == null) {
2239                 artworkBitmap = mMediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
2240                 // might still be null
2241             }
2242             if (artworkBitmap != null) {
2243                 artworkDrawable = new BitmapDrawable(mBackdropBack.getResources(), artworkBitmap);
2244             }
2245         }
2246         boolean allowWhenShade = false;
2247         if (ENABLE_LOCKSCREEN_WALLPAPER && artworkDrawable == null) {
2248             Bitmap lockWallpaper = mLockscreenWallpaper.getBitmap();
2249             if (lockWallpaper != null) {
2250                 artworkDrawable = new LockscreenWallpaper.WallpaperDrawable(
2251                         mBackdropBack.getResources(), lockWallpaper);
2252                 // We're in the SHADE mode on the SIM screen - yet we still need to show
2253                 // the lockscreen wallpaper in that mode.
2254                 allowWhenShade = mStatusBarKeyguardViewManager != null
2255                         && mStatusBarKeyguardViewManager.isShowing();
2256             }
2257         }
2258 
2259         boolean hideBecauseOccluded = mStatusBarKeyguardViewManager != null
2260                 && mStatusBarKeyguardViewManager.isOccluded();
2261 
2262         final boolean hasArtwork = artworkDrawable != null;
2263 
2264         if ((hasArtwork || DEBUG_MEDIA_FAKE_ARTWORK)
2265                 && (mState != StatusBarState.SHADE || allowWhenShade)
2266                 && mFingerprintUnlockController.getMode()
2267                         != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
2268                 && !hideBecauseOccluded) {
2269             // time to show some art!
2270             if (mBackdrop.getVisibility() != View.VISIBLE) {
2271                 mBackdrop.setVisibility(View.VISIBLE);
2272                 if (allowEnterAnimation) {
2273                     mBackdrop.setAlpha(SRC_MIN_ALPHA);
2274                     mBackdrop.animate().alpha(1f);
2275                 } else {
2276                     mBackdrop.animate().cancel();
2277                     mBackdrop.setAlpha(1f);
2278                 }
2279                 mStatusBarWindowManager.setBackdropShowing(true);
2280                 metaDataChanged = true;
2281                 if (DEBUG_MEDIA) {
2282                     Log.v(TAG, "DEBUG_MEDIA: Fading in album artwork");
2283                 }
2284             }
2285             if (metaDataChanged) {
2286                 if (mBackdropBack.getDrawable() != null) {
2287                     Drawable drawable =
2288                             mBackdropBack.getDrawable().getConstantState()
2289                                     .newDrawable(mBackdropFront.getResources()).mutate();
2290                     mBackdropFront.setImageDrawable(drawable);
2291                     if (mScrimSrcModeEnabled) {
2292                         mBackdropFront.getDrawable().mutate().setXfermode(mSrcOverXferMode);
2293                     }
2294                     mBackdropFront.setAlpha(1f);
2295                     mBackdropFront.setVisibility(View.VISIBLE);
2296                 } else {
2297                     mBackdropFront.setVisibility(View.INVISIBLE);
2298                 }
2299 
2300                 if (DEBUG_MEDIA_FAKE_ARTWORK) {
2301                     final int c = 0xFF000000 | (int)(Math.random() * 0xFFFFFF);
2302                     Log.v(TAG, String.format("DEBUG_MEDIA: setting new color: 0x%08x", c));
2303                     mBackdropBack.setBackgroundColor(0xFFFFFFFF);
2304                     mBackdropBack.setImageDrawable(new ColorDrawable(c));
2305                 } else {
2306                     mBackdropBack.setImageDrawable(artworkDrawable);
2307                 }
2308                 if (mScrimSrcModeEnabled) {
2309                     mBackdropBack.getDrawable().mutate().setXfermode(mSrcXferMode);
2310                 }
2311 
2312                 if (mBackdropFront.getVisibility() == View.VISIBLE) {
2313                     if (DEBUG_MEDIA) {
2314                         Log.v(TAG, "DEBUG_MEDIA: Crossfading album artwork from "
2315                                 + mBackdropFront.getDrawable()
2316                                 + " to "
2317                                 + mBackdropBack.getDrawable());
2318                     }
2319                     mBackdropFront.animate()
2320                             .setDuration(250)
2321                             .alpha(0f).withEndAction(mHideBackdropFront);
2322                 }
2323             }
2324         } else {
2325             // need to hide the album art, either because we are unlocked or because
2326             // the metadata isn't there to support it
2327             if (mBackdrop.getVisibility() != View.GONE) {
2328                 if (DEBUG_MEDIA) {
2329                     Log.v(TAG, "DEBUG_MEDIA: Fading out album artwork");
2330                 }
2331                 if (mFingerprintUnlockController.getMode()
2332                         == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
2333                         || hideBecauseOccluded) {
2334 
2335                     // We are unlocking directly - no animation!
2336                     mBackdrop.setVisibility(View.GONE);
2337                     mBackdropBack.setImageDrawable(null);
2338                     mStatusBarWindowManager.setBackdropShowing(false);
2339                 } else {
2340                     mStatusBarWindowManager.setBackdropShowing(false);
2341                     mBackdrop.animate()
2342                             .alpha(SRC_MIN_ALPHA)
2343                             .setInterpolator(Interpolators.ACCELERATE_DECELERATE)
2344                             .setDuration(300)
2345                             .setStartDelay(0)
2346                             .withEndAction(new Runnable() {
2347                                 @Override
2348                                 public void run() {
2349                                     mBackdrop.setVisibility(View.GONE);
2350                                     mBackdropFront.animate().cancel();
2351                                     mBackdropBack.setImageDrawable(null);
2352                                     mHandler.post(mHideBackdropFront);
2353                                 }
2354                             });
2355                     if (mKeyguardFadingAway) {
2356                         mBackdrop.animate()
2357                                 // Make it disappear faster, as the focus should be on the activity
2358                                 // behind.
2359                                 .setDuration(mKeyguardFadingAwayDuration / 2)
2360                                 .setStartDelay(mKeyguardFadingAwayDelay)
2361                                 .setInterpolator(Interpolators.LINEAR)
2362                                 .start();
2363                     }
2364                 }
2365             }
2366         }
2367         Trace.endSection();
2368     }
2369 
updateReportRejectedTouchVisibility()2370     private void updateReportRejectedTouchVisibility() {
2371         if (mReportRejectedTouch == null) {
2372             return;
2373         }
2374         mReportRejectedTouch.setVisibility(mState == StatusBarState.KEYGUARD
2375                 && mFalsingManager.isReportingEnabled() ? View.VISIBLE : View.INVISIBLE);
2376     }
2377 
adjustDisableFlags(int state)2378     protected int adjustDisableFlags(int state) {
2379         if (!mLaunchTransitionFadingAway && !mKeyguardFadingAway
2380                 && (mExpandedVisible || mBouncerShowing || mWaitingForKeyguardExit)) {
2381             state |= StatusBarManager.DISABLE_NOTIFICATION_ICONS;
2382             state |= StatusBarManager.DISABLE_SYSTEM_INFO;
2383         }
2384         if (mNetworkController != null && EncryptionHelper.IS_DATA_ENCRYPTED) {
2385             if (mNetworkController.hasEmergencyCryptKeeperText()) {
2386                 state |= StatusBarManager.DISABLE_NOTIFICATION_ICONS;
2387             }
2388             if (!mNetworkController.isRadioOn()) {
2389                 state |= StatusBarManager.DISABLE_SYSTEM_INFO;
2390             }
2391         }
2392         return state;
2393     }
2394 
2395     /**
2396      * State is one or more of the DISABLE constants from StatusBarManager.
2397      */
2398     @Override
disable(int state1, int state2, boolean animate)2399     public void disable(int state1, int state2, boolean animate) {
2400         animate &= mStatusBarWindowState != WINDOW_STATE_HIDDEN;
2401         mDisabledUnmodified1 = state1;
2402         mDisabledUnmodified2 = state2;
2403         state1 = adjustDisableFlags(state1);
2404         final int old1 = mDisabled1;
2405         final int diff1 = state1 ^ old1;
2406         mDisabled1 = state1;
2407 
2408         final int old2 = mDisabled2;
2409         final int diff2 = state2 ^ old2;
2410         mDisabled2 = state2;
2411 
2412         if (DEBUG) {
2413             Log.d(TAG, String.format("disable1: 0x%08x -> 0x%08x (diff1: 0x%08x)",
2414                 old1, state1, diff1));
2415             Log.d(TAG, String.format("disable2: 0x%08x -> 0x%08x (diff2: 0x%08x)",
2416                 old2, state2, diff2));
2417         }
2418 
2419         StringBuilder flagdbg = new StringBuilder();
2420         flagdbg.append("disable: < ");
2421         flagdbg.append(((state1 & StatusBarManager.DISABLE_EXPAND) != 0) ? "EXPAND" : "expand");
2422         flagdbg.append(((diff1  & StatusBarManager.DISABLE_EXPAND) != 0) ? "* " : " ");
2423         flagdbg.append(((state1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) ? "ICONS" : "icons");
2424         flagdbg.append(((diff1  & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) ? "* " : " ");
2425         flagdbg.append(((state1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) ? "ALERTS" : "alerts");
2426         flagdbg.append(((diff1  & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) ? "* " : " ");
2427         flagdbg.append(((state1 & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) ? "SYSTEM_INFO" : "system_info");
2428         flagdbg.append(((diff1  & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) ? "* " : " ");
2429         flagdbg.append(((state1 & StatusBarManager.DISABLE_BACK) != 0) ? "BACK" : "back");
2430         flagdbg.append(((diff1  & StatusBarManager.DISABLE_BACK) != 0) ? "* " : " ");
2431         flagdbg.append(((state1 & StatusBarManager.DISABLE_HOME) != 0) ? "HOME" : "home");
2432         flagdbg.append(((diff1  & StatusBarManager.DISABLE_HOME) != 0) ? "* " : " ");
2433         flagdbg.append(((state1 & StatusBarManager.DISABLE_RECENT) != 0) ? "RECENT" : "recent");
2434         flagdbg.append(((diff1  & StatusBarManager.DISABLE_RECENT) != 0) ? "* " : " ");
2435         flagdbg.append(((state1 & StatusBarManager.DISABLE_CLOCK) != 0) ? "CLOCK" : "clock");
2436         flagdbg.append(((diff1  & StatusBarManager.DISABLE_CLOCK) != 0) ? "* " : " ");
2437         flagdbg.append(((state1 & StatusBarManager.DISABLE_SEARCH) != 0) ? "SEARCH" : "search");
2438         flagdbg.append(((diff1  & StatusBarManager.DISABLE_SEARCH) != 0) ? "* " : " ");
2439         flagdbg.append(((state2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) ? "QUICK_SETTINGS"
2440                 : "quick_settings");
2441         flagdbg.append(((diff2  & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) ? "* " : " ");
2442         flagdbg.append(">");
2443         Log.d(TAG, flagdbg.toString());
2444 
2445         if ((diff1 & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
2446             if ((state1 & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
2447                 mIconController.hideSystemIconArea(animate);
2448             } else {
2449                 mIconController.showSystemIconArea(animate);
2450             }
2451         }
2452 
2453         if ((diff1 & StatusBarManager.DISABLE_CLOCK) != 0) {
2454             boolean visible = (state1 & StatusBarManager.DISABLE_CLOCK) == 0;
2455             mIconController.setClockVisibility(visible);
2456         }
2457         if ((diff1 & StatusBarManager.DISABLE_EXPAND) != 0) {
2458             if ((state1 & StatusBarManager.DISABLE_EXPAND) != 0) {
2459                 animateCollapsePanels();
2460             }
2461         }
2462 
2463         if ((diff1 & (StatusBarManager.DISABLE_HOME
2464                         | StatusBarManager.DISABLE_RECENT
2465                         | StatusBarManager.DISABLE_BACK
2466                         | StatusBarManager.DISABLE_SEARCH)) != 0) {
2467             // the nav bar will take care of these
2468             if (mNavigationBarView != null) mNavigationBarView.setDisabledFlags(state1);
2469 
2470             if ((state1 & StatusBarManager.DISABLE_RECENT) != 0) {
2471                 // close recents if it's visible
2472                 mHandler.removeMessages(MSG_HIDE_RECENT_APPS);
2473                 mHandler.sendEmptyMessage(MSG_HIDE_RECENT_APPS);
2474             }
2475         }
2476 
2477         if ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
2478             if ((state1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
2479                 mIconController.hideNotificationIconArea(animate);
2480             } else {
2481                 mIconController.showNotificationIconArea(animate);
2482             }
2483         }
2484 
2485         if ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) {
2486             mDisableNotificationAlerts =
2487                     (state1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
2488             mHeadsUpObserver.onChange(true);
2489         }
2490 
2491         if ((diff2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) {
2492             updateQsExpansionEnabled();
2493         }
2494     }
2495 
2496     /**
2497      * Reapplies the disable flags as last requested by StatusBarManager.
2498      *
2499      * This needs to be called if state used by {@link #adjustDisableFlags} changes.
2500      */
recomputeDisableFlags(boolean animate)2501     private void recomputeDisableFlags(boolean animate) {
2502         disable(mDisabledUnmodified1, mDisabledUnmodified2, animate);
2503     }
2504 
2505     @Override
createHandler()2506     protected BaseStatusBar.H createHandler() {
2507         return new PhoneStatusBar.H();
2508     }
2509 
2510     @Override
startActivity(Intent intent, boolean dismissShade)2511     public void startActivity(Intent intent, boolean dismissShade) {
2512         startActivityDismissingKeyguard(intent, false, dismissShade);
2513     }
2514 
2515     @Override
startActivity(Intent intent, boolean dismissShade, Callback callback)2516     public void startActivity(Intent intent, boolean dismissShade, Callback callback) {
2517         startActivityDismissingKeyguard(intent, false, dismissShade, callback);
2518     }
2519 
2520     @Override
preventNextAnimation()2521     public void preventNextAnimation() {
2522         overrideActivityPendingAppTransition(true /* keyguardShowing */);
2523     }
2524 
setQsExpanded(boolean expanded)2525     public void setQsExpanded(boolean expanded) {
2526         mStatusBarWindowManager.setQsExpanded(expanded);
2527         mKeyguardStatusView.setImportantForAccessibility(expanded
2528                 ? View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
2529                 : View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
2530     }
2531 
isGoingToNotificationShade()2532     public boolean isGoingToNotificationShade() {
2533         return mLeaveOpenOnKeyguardHide;
2534     }
2535 
isQsExpanded()2536     public boolean isQsExpanded() {
2537         return mNotificationPanel.isQsExpanded();
2538     }
2539 
isWakeUpComingFromTouch()2540     public boolean isWakeUpComingFromTouch() {
2541         return mWakeUpComingFromTouch;
2542     }
2543 
isFalsingThresholdNeeded()2544     public boolean isFalsingThresholdNeeded() {
2545         return getBarState() == StatusBarState.KEYGUARD;
2546     }
2547 
isDozing()2548     public boolean isDozing() {
2549         return mDozing;
2550     }
2551 
2552     @Override  // NotificationData.Environment
getCurrentMediaNotificationKey()2553     public String getCurrentMediaNotificationKey() {
2554         return mMediaNotificationKey;
2555     }
2556 
isScrimSrcModeEnabled()2557     public boolean isScrimSrcModeEnabled() {
2558         return mScrimSrcModeEnabled;
2559     }
2560 
2561     /**
2562      * To be called when there's a state change in StatusBarKeyguardViewManager.
2563      */
onKeyguardViewManagerStatesUpdated()2564     public void onKeyguardViewManagerStatesUpdated() {
2565         logStateToEventlog();
2566     }
2567 
2568     @Override  // UnlockMethodCache.OnUnlockMethodChangedListener
onUnlockMethodStateChanged()2569     public void onUnlockMethodStateChanged() {
2570         logStateToEventlog();
2571     }
2572 
2573     @Override
onHeadsUpPinnedModeChanged(boolean inPinnedMode)2574     public void onHeadsUpPinnedModeChanged(boolean inPinnedMode) {
2575         if (inPinnedMode) {
2576             mStatusBarWindowManager.setHeadsUpShowing(true);
2577             mStatusBarWindowManager.setForceStatusBarVisible(true);
2578             if (mNotificationPanel.isFullyCollapsed()) {
2579                 // We need to ensure that the touchable region is updated before the window will be
2580                 // resized, in order to not catch any touches. A layout will ensure that
2581                 // onComputeInternalInsets will be called and after that we can resize the layout. Let's
2582                 // make sure that the window stays small for one frame until the touchableRegion is set.
2583                 mNotificationPanel.requestLayout();
2584                 mStatusBarWindowManager.setForceWindowCollapsed(true);
2585                 mNotificationPanel.post(new Runnable() {
2586                     @Override
2587                     public void run() {
2588                         mStatusBarWindowManager.setForceWindowCollapsed(false);
2589                     }
2590                 });
2591             }
2592         } else {
2593             if (!mNotificationPanel.isFullyCollapsed() || mNotificationPanel.isTracking()) {
2594                 // We are currently tracking or is open and the shade doesn't need to be kept
2595                 // open artificially.
2596                 mStatusBarWindowManager.setHeadsUpShowing(false);
2597             } else {
2598                 // we need to keep the panel open artificially, let's wait until the animation
2599                 // is finished.
2600                 mHeadsUpManager.setHeadsUpGoingAway(true);
2601                 mStackScroller.runAfterAnimationFinished(new Runnable() {
2602                     @Override
2603                     public void run() {
2604                         if (!mHeadsUpManager.hasPinnedHeadsUp()) {
2605                             mStatusBarWindowManager.setHeadsUpShowing(false);
2606                             mHeadsUpManager.setHeadsUpGoingAway(false);
2607                         }
2608                         removeRemoteInputEntriesKeptUntilCollapsed();
2609                     }
2610                 });
2611             }
2612         }
2613     }
2614 
2615     @Override
onHeadsUpPinned(ExpandableNotificationRow headsUp)2616     public void onHeadsUpPinned(ExpandableNotificationRow headsUp) {
2617         dismissVolumeDialog();
2618     }
2619 
2620     @Override
onHeadsUpUnPinned(ExpandableNotificationRow headsUp)2621     public void onHeadsUpUnPinned(ExpandableNotificationRow headsUp) {
2622     }
2623 
2624     @Override
onHeadsUpStateChanged(Entry entry, boolean isHeadsUp)2625     public void onHeadsUpStateChanged(Entry entry, boolean isHeadsUp) {
2626         if (!isHeadsUp && mHeadsUpEntriesToRemoveOnSwitch.contains(entry)) {
2627             removeNotification(entry.key, mLatestRankingMap);
2628             mHeadsUpEntriesToRemoveOnSwitch.remove(entry);
2629             if (mHeadsUpEntriesToRemoveOnSwitch.isEmpty()) {
2630                 mLatestRankingMap = null;
2631             }
2632         } else {
2633             updateNotificationRanking(null);
2634         }
2635 
2636     }
2637 
2638     @Override
updateHeadsUp(String key, Entry entry, boolean shouldPeek, boolean alertAgain)2639     protected void updateHeadsUp(String key, Entry entry, boolean shouldPeek,
2640             boolean alertAgain) {
2641         final boolean wasHeadsUp = isHeadsUp(key);
2642         if (wasHeadsUp) {
2643             if (!shouldPeek) {
2644                 // We don't want this to be interrupting anymore, lets remove it
2645                 mHeadsUpManager.removeNotification(key, false /* ignoreEarliestRemovalTime */);
2646             } else {
2647                 mHeadsUpManager.updateNotification(entry, alertAgain);
2648             }
2649         } else if (shouldPeek && alertAgain) {
2650             // This notification was updated to be a heads-up, show it!
2651             mHeadsUpManager.showNotification(entry);
2652         }
2653     }
2654 
2655     @Override
setHeadsUpUser(int newUserId)2656     protected void setHeadsUpUser(int newUserId) {
2657         if (mHeadsUpManager != null) {
2658             mHeadsUpManager.setUser(newUserId);
2659         }
2660     }
2661 
isHeadsUp(String key)2662     public boolean isHeadsUp(String key) {
2663         return mHeadsUpManager.isHeadsUp(key);
2664     }
2665 
2666     @Override
isSnoozedPackage(StatusBarNotification sbn)2667     protected boolean isSnoozedPackage(StatusBarNotification sbn) {
2668         return mHeadsUpManager.isSnoozed(sbn.getPackageName());
2669     }
2670 
isKeyguardCurrentlySecure()2671     public boolean isKeyguardCurrentlySecure() {
2672         return !mUnlockMethodCache.canSkipBouncer();
2673     }
2674 
setPanelExpanded(boolean isExpanded)2675     public void setPanelExpanded(boolean isExpanded) {
2676         mStatusBarWindowManager.setPanelExpanded(isExpanded);
2677         mVisualStabilityManager.setPanelExpanded(isExpanded);
2678         if (isExpanded && getBarState() != StatusBarState.KEYGUARD) {
2679             if (DEBUG) {
2680                 Log.v(TAG, "clearing notification effects from setPanelExpanded");
2681             }
2682             clearNotificationEffects();
2683         }
2684 
2685         if (!isExpanded) {
2686             removeRemoteInputEntriesKeptUntilCollapsed();
2687         }
2688     }
2689 
removeRemoteInputEntriesKeptUntilCollapsed()2690     private void removeRemoteInputEntriesKeptUntilCollapsed() {
2691         for (int i = 0; i < mRemoteInputEntriesToRemoveOnCollapse.size(); i++) {
2692             Entry entry = mRemoteInputEntriesToRemoveOnCollapse.valueAt(i);
2693             mRemoteInputController.removeRemoteInput(entry, null);
2694             removeNotification(entry.key, mLatestRankingMap);
2695         }
2696         mRemoteInputEntriesToRemoveOnCollapse.clear();
2697     }
2698 
onScreenTurnedOff()2699     public void onScreenTurnedOff() {
2700         mFalsingManager.onScreenOff();
2701     }
2702 
2703     @Override
onReorderingAllowed()2704     public void onReorderingAllowed() {
2705         updateNotifications();
2706     }
2707 
2708     /**
2709      * All changes to the status bar and notifications funnel through here and are batched.
2710      */
2711     private class H extends BaseStatusBar.H {
2712         @Override
handleMessage(Message m)2713         public void handleMessage(Message m) {
2714             super.handleMessage(m);
2715             switch (m.what) {
2716                 case MSG_OPEN_NOTIFICATION_PANEL:
2717                     animateExpandNotificationsPanel();
2718                     break;
2719                 case MSG_OPEN_SETTINGS_PANEL:
2720                     animateExpandSettingsPanel((String) m.obj);
2721                     break;
2722                 case MSG_CLOSE_PANELS:
2723                     animateCollapsePanels();
2724                     break;
2725                 case MSG_LAUNCH_TRANSITION_TIMEOUT:
2726                     onLaunchTransitionTimeout();
2727                     break;
2728             }
2729         }
2730     }
2731 
2732     @Override
maybeEscalateHeadsUp()2733     public void maybeEscalateHeadsUp() {
2734         Collection<HeadsUpManager.HeadsUpEntry> entries = mHeadsUpManager.getAllEntries();
2735         for (HeadsUpManager.HeadsUpEntry entry : entries) {
2736             final StatusBarNotification sbn = entry.entry.notification;
2737             final Notification notification = sbn.getNotification();
2738             if (notification.fullScreenIntent != null) {
2739                 if (DEBUG) {
2740                     Log.d(TAG, "converting a heads up to fullScreen");
2741                 }
2742                 try {
2743                     EventLog.writeEvent(EventLogTags.SYSUI_HEADS_UP_ESCALATION,
2744                             sbn.getKey());
2745                     notification.fullScreenIntent.send();
2746                     entry.entry.notifyFullScreenIntentLaunched();
2747                 } catch (PendingIntent.CanceledException e) {
2748                 }
2749             }
2750         }
2751         mHeadsUpManager.releaseAllImmediately();
2752     }
2753 
2754     /**
2755      * Called for system navigation gestures. First action opens the panel, second opens
2756      * settings. Down action closes the entire panel.
2757      */
2758     @Override
handleSystemNavigationKey(int key)2759     public void handleSystemNavigationKey(int key) {
2760         if (SPEW) Log.d(TAG, "handleSystemNavigationKey: " + key);
2761         if (!panelsEnabled() || !mKeyguardMonitor.isDeviceInteractive()
2762                 || mKeyguardMonitor.isShowing() && !mKeyguardMonitor.isOccluded()) {
2763             return;
2764         }
2765 
2766         // Panels are not available in setup
2767         if (!mUserSetup) return;
2768 
2769         if (KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP == key) {
2770             MetricsLogger.action(mContext, MetricsEvent.ACTION_SYSTEM_NAVIGATION_KEY_UP);
2771             mNotificationPanel.collapse(false /* delayed */, 1.0f /* speedUpFactor */);
2772         } else if (KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN == key) {
2773             MetricsLogger.action(mContext, MetricsEvent.ACTION_SYSTEM_NAVIGATION_KEY_DOWN);
2774             if (mNotificationPanel.isFullyCollapsed()) {
2775                 mNotificationPanel.expand(true /* animate */);
2776                 MetricsLogger.count(mContext, NotificationPanelView.COUNTER_PANEL_OPEN, 1);
2777             } else if (!mNotificationPanel.isInSettings() && !mNotificationPanel.isExpanding()){
2778                 mNotificationPanel.flingSettings(0 /* velocity */, true /* expand */);
2779                 MetricsLogger.count(mContext, NotificationPanelView.COUNTER_PANEL_OPEN_QS, 1);
2780             }
2781         }
2782 
2783     }
2784 
panelsEnabled()2785     boolean panelsEnabled() {
2786         return (mDisabled1 & StatusBarManager.DISABLE_EXPAND) == 0 && !ONLY_CORE_APPS;
2787     }
2788 
makeExpandedVisible(boolean force)2789     void makeExpandedVisible(boolean force) {
2790         if (SPEW) Log.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible);
2791         if (!force && (mExpandedVisible || !panelsEnabled())) {
2792             return;
2793         }
2794 
2795         mExpandedVisible = true;
2796 
2797         // Expand the window to encompass the full screen in anticipation of the drag.
2798         // This is only possible to do atomically because the status bar is at the top of the screen!
2799         mStatusBarWindowManager.setPanelVisible(true);
2800 
2801         visibilityChanged(true);
2802         mWaitingForKeyguardExit = false;
2803         recomputeDisableFlags(!force /* animate */);
2804         setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true);
2805     }
2806 
animateCollapsePanels()2807     public void animateCollapsePanels() {
2808         animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
2809     }
2810 
2811     private final Runnable mAnimateCollapsePanels = new Runnable() {
2812         @Override
2813         public void run() {
2814             animateCollapsePanels();
2815         }
2816     };
2817 
postAnimateCollapsePanels()2818     public void postAnimateCollapsePanels() {
2819         mHandler.post(mAnimateCollapsePanels);
2820     }
2821 
postAnimateOpenPanels()2822     public void postAnimateOpenPanels() {
2823         mHandler.sendEmptyMessage(MSG_OPEN_SETTINGS_PANEL);
2824     }
2825 
2826     @Override
animateCollapsePanels(int flags)2827     public void animateCollapsePanels(int flags) {
2828         animateCollapsePanels(flags, false /* force */, false /* delayed */,
2829                 1.0f /* speedUpFactor */);
2830     }
2831 
2832     @Override
animateCollapsePanels(int flags, boolean force)2833     public void animateCollapsePanels(int flags, boolean force) {
2834         animateCollapsePanels(flags, force, false /* delayed */, 1.0f /* speedUpFactor */);
2835     }
2836 
2837     @Override
animateCollapsePanels(int flags, boolean force, boolean delayed)2838     public void animateCollapsePanels(int flags, boolean force, boolean delayed) {
2839         animateCollapsePanels(flags, force, delayed, 1.0f /* speedUpFactor */);
2840     }
2841 
animateCollapsePanels(int flags, boolean force, boolean delayed, float speedUpFactor)2842     public void animateCollapsePanels(int flags, boolean force, boolean delayed,
2843             float speedUpFactor) {
2844         if (!force && mState != StatusBarState.SHADE) {
2845             runPostCollapseRunnables();
2846             return;
2847         }
2848         if (SPEW) {
2849             Log.d(TAG, "animateCollapse():"
2850                     + " mExpandedVisible=" + mExpandedVisible
2851                     + " flags=" + flags);
2852         }
2853 
2854         if ((flags & CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL) == 0) {
2855             if (!mHandler.hasMessages(MSG_HIDE_RECENT_APPS)) {
2856                 mHandler.removeMessages(MSG_HIDE_RECENT_APPS);
2857                 mHandler.sendEmptyMessage(MSG_HIDE_RECENT_APPS);
2858             }
2859         }
2860 
2861         if (mStatusBarWindow != null) {
2862             // release focus immediately to kick off focus change transition
2863             mStatusBarWindowManager.setStatusBarFocusable(false);
2864 
2865             mStatusBarWindow.cancelExpandHelper();
2866             mStatusBarView.collapsePanel(true /* animate */, delayed, speedUpFactor);
2867         }
2868     }
2869 
runPostCollapseRunnables()2870     private void runPostCollapseRunnables() {
2871         ArrayList<Runnable> clonedList = new ArrayList<>(mPostCollapseRunnables);
2872         mPostCollapseRunnables.clear();
2873         int size = clonedList.size();
2874         for (int i = 0; i < size; i++) {
2875             clonedList.get(i).run();
2876         }
2877 
2878     }
2879 
2880     @Override
animateExpandNotificationsPanel()2881     public void animateExpandNotificationsPanel() {
2882         if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible);
2883         if (!panelsEnabled()) {
2884             return ;
2885         }
2886 
2887         mNotificationPanel.expand(true /* animate */);
2888 
2889         if (false) postStartTracing();
2890     }
2891 
2892     @Override
animateExpandSettingsPanel(String subPanel)2893     public void animateExpandSettingsPanel(String subPanel) {
2894         if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible);
2895         if (!panelsEnabled()) {
2896             return;
2897         }
2898 
2899         // Settings are not available in setup
2900         if (!mUserSetup) return;
2901 
2902 
2903         if (subPanel != null) {
2904             mQSPanel.openDetails(subPanel);
2905         }
2906         mNotificationPanel.expandWithQs();
2907 
2908         if (false) postStartTracing();
2909     }
2910 
animateCollapseQuickSettings()2911     public void animateCollapseQuickSettings() {
2912         if (mState == StatusBarState.SHADE) {
2913             mStatusBarView.collapsePanel(true, false /* delayed */, 1.0f /* speedUpFactor */);
2914         }
2915     }
2916 
makeExpandedInvisible()2917     void makeExpandedInvisible() {
2918         if (SPEW) Log.d(TAG, "makeExpandedInvisible: mExpandedVisible=" + mExpandedVisible
2919                 + " mExpandedVisible=" + mExpandedVisible);
2920 
2921         if (!mExpandedVisible || mStatusBarWindow == null) {
2922             return;
2923         }
2924 
2925         // Ensure the panel is fully collapsed (just in case; bug 6765842, 7260868)
2926         mStatusBarView.collapsePanel(/*animate=*/ false, false /* delayed*/,
2927                 1.0f /* speedUpFactor */);
2928 
2929         mNotificationPanel.closeQs();
2930 
2931         mExpandedVisible = false;
2932         visibilityChanged(false);
2933 
2934         // Shrink the window to the size of the status bar only
2935         mStatusBarWindowManager.setPanelVisible(false);
2936         mStatusBarWindowManager.setForceStatusBarVisible(false);
2937 
2938         // Close any "App info" popups that might have snuck on-screen
2939         dismissPopups();
2940 
2941         runPostCollapseRunnables();
2942         setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
2943         showBouncerIfKeyguard();
2944         recomputeDisableFlags(true /* animate */);
2945 
2946         // Trimming will happen later if Keyguard is showing - doing it here might cause a jank in
2947         // the bouncer appear animation.
2948         if (!mStatusBarKeyguardViewManager.isShowing()) {
2949             WindowManagerGlobal.getInstance().trimMemory(ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
2950         }
2951     }
2952 
interceptTouchEvent(MotionEvent event)2953     public boolean interceptTouchEvent(MotionEvent event) {
2954         if (DEBUG_GESTURES) {
2955             if (event.getActionMasked() != MotionEvent.ACTION_MOVE) {
2956                 EventLog.writeEvent(EventLogTags.SYSUI_STATUSBAR_TOUCH,
2957                         event.getActionMasked(), (int) event.getX(), (int) event.getY(),
2958                         mDisabled1, mDisabled2);
2959             }
2960 
2961         }
2962 
2963         if (SPEW) {
2964             Log.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled1="
2965                 + mDisabled1 + " mDisabled2=" + mDisabled2 + " mTracking=" + mTracking);
2966         } else if (CHATTY) {
2967             if (event.getAction() != MotionEvent.ACTION_MOVE) {
2968                 Log.d(TAG, String.format(
2969                             "panel: %s at (%f, %f) mDisabled1=0x%08x mDisabled2=0x%08x",
2970                             MotionEvent.actionToString(event.getAction()),
2971                             event.getRawX(), event.getRawY(), mDisabled1, mDisabled2));
2972             }
2973         }
2974 
2975         if (DEBUG_GESTURES) {
2976             mGestureRec.add(event);
2977         }
2978 
2979         if (mStatusBarWindowState == WINDOW_STATE_SHOWING) {
2980             final boolean upOrCancel =
2981                     event.getAction() == MotionEvent.ACTION_UP ||
2982                     event.getAction() == MotionEvent.ACTION_CANCEL;
2983             if (upOrCancel && !mExpandedVisible) {
2984                 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
2985             } else {
2986                 setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true);
2987             }
2988         }
2989         return false;
2990     }
2991 
getGestureRecorder()2992     public GestureRecorder getGestureRecorder() {
2993         return mGestureRec;
2994     }
2995 
setNavigationIconHints(int hints)2996     private void setNavigationIconHints(int hints) {
2997         if (hints == mNavigationIconHints) return;
2998 
2999         mNavigationIconHints = hints;
3000 
3001         if (mNavigationBarView != null) {
3002             mNavigationBarView.setNavigationIconHints(hints);
3003         }
3004         checkBarModes();
3005     }
3006 
3007     @Override // CommandQueue
setWindowState(int window, int state)3008     public void setWindowState(int window, int state) {
3009         boolean showing = state == WINDOW_STATE_SHOWING;
3010         if (mStatusBarWindow != null
3011                 && window == StatusBarManager.WINDOW_STATUS_BAR
3012                 && mStatusBarWindowState != state) {
3013             mStatusBarWindowState = state;
3014             if (DEBUG_WINDOW_STATE) Log.d(TAG, "Status bar " + windowStateToString(state));
3015             if (!showing && mState == StatusBarState.SHADE) {
3016                 mStatusBarView.collapsePanel(false /* animate */, false /* delayed */,
3017                         1.0f /* speedUpFactor */);
3018             }
3019         }
3020         if (mNavigationBarView != null
3021                 && window == StatusBarManager.WINDOW_NAVIGATION_BAR
3022                 && mNavigationBarWindowState != state) {
3023             mNavigationBarWindowState = state;
3024             if (DEBUG_WINDOW_STATE) Log.d(TAG, "Navigation bar " + windowStateToString(state));
3025         }
3026     }
3027 
3028     @Override // CommandQueue
buzzBeepBlinked()3029     public void buzzBeepBlinked() {
3030         if (mDozeServiceHost != null) {
3031             mDozeServiceHost.fireBuzzBeepBlinked();
3032         }
3033     }
3034 
3035     @Override
notificationLightOff()3036     public void notificationLightOff() {
3037         if (mDozeServiceHost != null) {
3038             mDozeServiceHost.fireNotificationLight(false);
3039         }
3040     }
3041 
3042     @Override
notificationLightPulse(int argb, int onMillis, int offMillis)3043     public void notificationLightPulse(int argb, int onMillis, int offMillis) {
3044         if (mDozeServiceHost != null) {
3045             mDozeServiceHost.fireNotificationLight(true);
3046         }
3047     }
3048 
3049     @Override // CommandQueue
setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds)3050     public void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis,
3051             int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
3052         final int oldVal = mSystemUiVisibility;
3053         final int newVal = (oldVal&~mask) | (vis&mask);
3054         final int diff = newVal ^ oldVal;
3055         if (DEBUG) Log.d(TAG, String.format(
3056                 "setSystemUiVisibility vis=%s mask=%s oldVal=%s newVal=%s diff=%s",
3057                 Integer.toHexString(vis), Integer.toHexString(mask),
3058                 Integer.toHexString(oldVal), Integer.toHexString(newVal),
3059                 Integer.toHexString(diff)));
3060         boolean sbModeChanged = false;
3061         if (diff != 0) {
3062             mSystemUiVisibility = newVal;
3063 
3064             // update low profile
3065             if ((diff & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0) {
3066                 setAreThereNotifications();
3067             }
3068 
3069             // ready to unhide
3070             if ((vis & View.STATUS_BAR_UNHIDE) != 0) {
3071                 mSystemUiVisibility &= ~View.STATUS_BAR_UNHIDE;
3072                 mNoAnimationOnNextBarModeChange = true;
3073             }
3074 
3075             // update status bar mode
3076             final int sbMode = computeBarMode(oldVal, newVal, mStatusBarView.getBarTransitions(),
3077                     View.STATUS_BAR_TRANSIENT, View.STATUS_BAR_TRANSLUCENT,
3078                     View.STATUS_BAR_TRANSPARENT);
3079 
3080             // update navigation bar mode
3081             final int nbMode = mNavigationBarView == null ? -1 : computeBarMode(
3082                     oldVal, newVal, mNavigationBarView.getBarTransitions(),
3083                     View.NAVIGATION_BAR_TRANSIENT, View.NAVIGATION_BAR_TRANSLUCENT,
3084                     View.NAVIGATION_BAR_TRANSPARENT);
3085             sbModeChanged = sbMode != -1;
3086             final boolean nbModeChanged = nbMode != -1;
3087             boolean checkBarModes = false;
3088             if (sbModeChanged && sbMode != mStatusBarMode) {
3089                 mStatusBarMode = sbMode;
3090                 checkBarModes = true;
3091             }
3092             if (nbModeChanged && nbMode != mNavigationBarMode) {
3093                 mNavigationBarMode = nbMode;
3094                 checkBarModes = true;
3095             }
3096             if (checkBarModes) {
3097                 checkBarModes();
3098             }
3099             if (sbModeChanged || nbModeChanged) {
3100                 // update transient bar autohide
3101                 if (mStatusBarMode == MODE_SEMI_TRANSPARENT || mNavigationBarMode == MODE_SEMI_TRANSPARENT) {
3102                     scheduleAutohide();
3103                 } else {
3104                     cancelAutohide();
3105                 }
3106             }
3107 
3108             if ((vis & View.NAVIGATION_BAR_UNHIDE) != 0) {
3109                 mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE;
3110             }
3111 
3112             // send updated sysui visibility to window manager
3113             notifyUiVisibilityChanged(mSystemUiVisibility);
3114         }
3115 
3116         mLightStatusBarController.onSystemUiVisibilityChanged(fullscreenStackVis, dockedStackVis,
3117                 mask, fullscreenStackBounds, dockedStackBounds, sbModeChanged, mStatusBarMode);
3118     }
3119 
computeBarMode(int oldVis, int newVis, BarTransitions transitions, int transientFlag, int translucentFlag, int transparentFlag)3120     private int computeBarMode(int oldVis, int newVis, BarTransitions transitions,
3121             int transientFlag, int translucentFlag, int transparentFlag) {
3122         final int oldMode = barMode(oldVis, transientFlag, translucentFlag, transparentFlag);
3123         final int newMode = barMode(newVis, transientFlag, translucentFlag, transparentFlag);
3124         if (oldMode == newMode) {
3125             return -1; // no mode change
3126         }
3127         return newMode;
3128     }
3129 
barMode(int vis, int transientFlag, int translucentFlag, int transparentFlag)3130     private int barMode(int vis, int transientFlag, int translucentFlag, int transparentFlag) {
3131         int lightsOutTransparent = View.SYSTEM_UI_FLAG_LOW_PROFILE | transparentFlag;
3132         return (vis & transientFlag) != 0 ? MODE_SEMI_TRANSPARENT
3133                 : (vis & translucentFlag) != 0 ? MODE_TRANSLUCENT
3134                 : (vis & lightsOutTransparent) == lightsOutTransparent ? MODE_LIGHTS_OUT_TRANSPARENT
3135                 : (vis & transparentFlag) != 0 ? MODE_TRANSPARENT
3136                 : (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0 ? MODE_LIGHTS_OUT
3137                 : MODE_OPAQUE;
3138     }
3139 
checkBarModes()3140     private void checkBarModes() {
3141         if (mDemoMode) return;
3142         checkBarMode(mStatusBarMode, mStatusBarWindowState, mStatusBarView.getBarTransitions(),
3143                 mNoAnimationOnNextBarModeChange);
3144         if (mNavigationBarView != null) {
3145             checkBarMode(mNavigationBarMode,
3146                     mNavigationBarWindowState, mNavigationBarView.getBarTransitions(),
3147                     mNoAnimationOnNextBarModeChange);
3148         }
3149         mNoAnimationOnNextBarModeChange = false;
3150     }
3151 
checkBarMode(int mode, int windowState, BarTransitions transitions, boolean noAnimation)3152     private void checkBarMode(int mode, int windowState, BarTransitions transitions,
3153             boolean noAnimation) {
3154         final boolean powerSave = mBatteryController.isPowerSave();
3155         final boolean anim = !noAnimation && mDeviceInteractive
3156                 && windowState != WINDOW_STATE_HIDDEN && !powerSave;
3157         if (powerSave && getBarState() == StatusBarState.SHADE) {
3158             mode = MODE_WARNING;
3159         }
3160         transitions.transitionTo(mode, anim);
3161     }
3162 
finishBarAnimations()3163     private void finishBarAnimations() {
3164         mStatusBarView.getBarTransitions().finishAnimations();
3165         if (mNavigationBarView != null) {
3166             mNavigationBarView.getBarTransitions().finishAnimations();
3167         }
3168     }
3169 
3170     private final Runnable mCheckBarModes = new Runnable() {
3171         @Override
3172         public void run() {
3173             checkBarModes();
3174         }
3175     };
3176 
3177     @Override
setInteracting(int barWindow, boolean interacting)3178     public void setInteracting(int barWindow, boolean interacting) {
3179         final boolean changing = ((mInteractingWindows & barWindow) != 0) != interacting;
3180         mInteractingWindows = interacting
3181                 ? (mInteractingWindows | barWindow)
3182                 : (mInteractingWindows & ~barWindow);
3183         if (mInteractingWindows != 0) {
3184             suspendAutohide();
3185         } else {
3186             resumeSuspendedAutohide();
3187         }
3188         // manually dismiss the volume panel when interacting with the nav bar
3189         if (changing && interacting && barWindow == StatusBarManager.WINDOW_NAVIGATION_BAR) {
3190             dismissVolumeDialog();
3191         }
3192         checkBarModes();
3193     }
3194 
dismissVolumeDialog()3195     private void dismissVolumeDialog() {
3196         if (mVolumeComponent != null) {
3197             mVolumeComponent.dismissNow();
3198         }
3199     }
3200 
resumeSuspendedAutohide()3201     private void resumeSuspendedAutohide() {
3202         if (mAutohideSuspended) {
3203             scheduleAutohide();
3204             mHandler.postDelayed(mCheckBarModes, 500); // longer than home -> launcher
3205         }
3206     }
3207 
suspendAutohide()3208     private void suspendAutohide() {
3209         mHandler.removeCallbacks(mAutohide);
3210         mHandler.removeCallbacks(mCheckBarModes);
3211         mAutohideSuspended = (mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0;
3212     }
3213 
cancelAutohide()3214     private void cancelAutohide() {
3215         mAutohideSuspended = false;
3216         mHandler.removeCallbacks(mAutohide);
3217     }
3218 
scheduleAutohide()3219     private void scheduleAutohide() {
3220         cancelAutohide();
3221         mHandler.postDelayed(mAutohide, AUTOHIDE_TIMEOUT_MS);
3222     }
3223 
checkUserAutohide(View v, MotionEvent event)3224     private void checkUserAutohide(View v, MotionEvent event) {
3225         if ((mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0  // a transient bar is revealed
3226                 && event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar
3227                 && event.getX() == 0 && event.getY() == 0  // a touch outside both bars
3228                 && !mRemoteInputController.isRemoteInputActive()) { // not due to typing in IME
3229             userAutohide();
3230         }
3231     }
3232 
checkRemoteInputOutside(MotionEvent event)3233     private void checkRemoteInputOutside(MotionEvent event) {
3234         if (event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar
3235                 && event.getX() == 0 && event.getY() == 0  // a touch outside both bars
3236                 && mRemoteInputController.isRemoteInputActive()) {
3237             mRemoteInputController.closeRemoteInputs();
3238         }
3239     }
3240 
userAutohide()3241     private void userAutohide() {
3242         cancelAutohide();
3243         mHandler.postDelayed(mAutohide, 350); // longer than app gesture -> flag clear
3244     }
3245 
areLightsOn()3246     private boolean areLightsOn() {
3247         return 0 == (mSystemUiVisibility & View.SYSTEM_UI_FLAG_LOW_PROFILE);
3248     }
3249 
setLightsOn(boolean on)3250     public void setLightsOn(boolean on) {
3251         Log.v(TAG, "setLightsOn(" + on + ")");
3252         if (on) {
3253             setSystemUiVisibility(0, 0, 0, View.SYSTEM_UI_FLAG_LOW_PROFILE,
3254                     mLastFullscreenStackBounds, mLastDockedStackBounds);
3255         } else {
3256             setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE, 0, 0,
3257                     View.SYSTEM_UI_FLAG_LOW_PROFILE, mLastFullscreenStackBounds,
3258                     mLastDockedStackBounds);
3259         }
3260     }
3261 
notifyUiVisibilityChanged(int vis)3262     private void notifyUiVisibilityChanged(int vis) {
3263         try {
3264             if (mLastDispatchedSystemUiVisibility != vis) {
3265                 mWindowManagerService.statusBarVisibilityChanged(vis);
3266                 mLastDispatchedSystemUiVisibility = vis;
3267             }
3268         } catch (RemoteException ex) {
3269         }
3270     }
3271 
3272     @Override
topAppWindowChanged(boolean showMenu)3273     public void topAppWindowChanged(boolean showMenu) {
3274         if (SPEW) {
3275             Log.d(TAG, (showMenu?"showing":"hiding") + " the MENU button");
3276         }
3277         if (mNavigationBarView != null) {
3278             mNavigationBarView.setMenuVisibility(showMenu);
3279         }
3280 
3281         // See above re: lights-out policy for legacy apps.
3282         if (showMenu) setLightsOn(true);
3283     }
3284 
3285     @Override
setImeWindowStatus(IBinder token, int vis, int backDisposition, boolean showImeSwitcher)3286     public void setImeWindowStatus(IBinder token, int vis, int backDisposition,
3287             boolean showImeSwitcher) {
3288         boolean imeShown = (vis & InputMethodService.IME_VISIBLE) != 0;
3289         int flags = mNavigationIconHints;
3290         if ((backDisposition == InputMethodService.BACK_DISPOSITION_WILL_DISMISS) || imeShown) {
3291             flags |= NAVIGATION_HINT_BACK_ALT;
3292         } else {
3293             flags &= ~NAVIGATION_HINT_BACK_ALT;
3294         }
3295         if (showImeSwitcher) {
3296             flags |= NAVIGATION_HINT_IME_SHOWN;
3297         } else {
3298             flags &= ~NAVIGATION_HINT_IME_SHOWN;
3299         }
3300 
3301         setNavigationIconHints(flags);
3302     }
3303 
viewInfo(View v)3304     public static String viewInfo(View v) {
3305         return "[(" + v.getLeft() + "," + v.getTop() + ")(" + v.getRight() + "," + v.getBottom()
3306                 + ") " + v.getWidth() + "x" + v.getHeight() + "]";
3307     }
3308 
3309     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)3310     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
3311         synchronized (mQueueLock) {
3312             pw.println("Current Status Bar state:");
3313             pw.println("  mExpandedVisible=" + mExpandedVisible
3314                     + ", mTrackingPosition=" + mTrackingPosition);
3315             pw.println("  mTracking=" + mTracking);
3316             pw.println("  mDisplayMetrics=" + mDisplayMetrics);
3317             pw.println("  mStackScroller: " + viewInfo(mStackScroller));
3318             pw.println("  mStackScroller: " + viewInfo(mStackScroller)
3319                     + " scroll " + mStackScroller.getScrollX()
3320                     + "," + mStackScroller.getScrollY());
3321         }
3322 
3323         pw.print("  mInteractingWindows="); pw.println(mInteractingWindows);
3324         pw.print("  mStatusBarWindowState=");
3325         pw.println(windowStateToString(mStatusBarWindowState));
3326         pw.print("  mStatusBarMode=");
3327         pw.println(BarTransitions.modeToString(mStatusBarMode));
3328         pw.print("  mDozing="); pw.println(mDozing);
3329         pw.print("  mZenMode=");
3330         pw.println(Settings.Global.zenModeToString(mZenMode));
3331         pw.print("  mUseHeadsUp=");
3332         pw.println(mUseHeadsUp);
3333         dumpBarTransitions(pw, "mStatusBarView", mStatusBarView.getBarTransitions());
3334         if (mNavigationBarView != null) {
3335             pw.print("  mNavigationBarWindowState=");
3336             pw.println(windowStateToString(mNavigationBarWindowState));
3337             pw.print("  mNavigationBarMode=");
3338             pw.println(BarTransitions.modeToString(mNavigationBarMode));
3339             dumpBarTransitions(pw, "mNavigationBarView", mNavigationBarView.getBarTransitions());
3340         }
3341 
3342         pw.print("  mNavigationBarView=");
3343         if (mNavigationBarView == null) {
3344             pw.println("null");
3345         } else {
3346             mNavigationBarView.dump(fd, pw, args);
3347         }
3348 
3349         pw.print("  mMediaSessionManager=");
3350         pw.println(mMediaSessionManager);
3351         pw.print("  mMediaNotificationKey=");
3352         pw.println(mMediaNotificationKey);
3353         pw.print("  mMediaController=");
3354         pw.print(mMediaController);
3355         if (mMediaController != null) {
3356             pw.print(" state=" + mMediaController.getPlaybackState());
3357         }
3358         pw.println();
3359         pw.print("  mMediaMetadata=");
3360         pw.print(mMediaMetadata);
3361         if (mMediaMetadata != null) {
3362             pw.print(" title=" + mMediaMetadata.getText(MediaMetadata.METADATA_KEY_TITLE));
3363         }
3364         pw.println();
3365 
3366         pw.println("  Panels: ");
3367         if (mNotificationPanel != null) {
3368             pw.println("    mNotificationPanel=" +
3369                 mNotificationPanel + " params=" + mNotificationPanel.getLayoutParams().debug(""));
3370             pw.print  ("      ");
3371             mNotificationPanel.dump(fd, pw, args);
3372         }
3373 
3374         DozeLog.dump(pw);
3375 
3376         if (DUMPTRUCK) {
3377             synchronized (mNotificationData) {
3378                 mNotificationData.dump(pw, "  ");
3379             }
3380 
3381             mIconController.dump(pw);
3382 
3383             if (false) {
3384                 pw.println("see the logcat for a dump of the views we have created.");
3385                 // must happen on ui thread
3386                 mHandler.post(new Runnable() {
3387                         @Override
3388                         public void run() {
3389                             mStatusBarView.getLocationOnScreen(mAbsPos);
3390                             Log.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
3391                                     + ") " + mStatusBarView.getWidth() + "x"
3392                                     + getStatusBarHeight());
3393                             mStatusBarView.debug();
3394                         }
3395                     });
3396             }
3397         }
3398 
3399         if (DEBUG_GESTURES) {
3400             pw.print("  status bar gestures: ");
3401             mGestureRec.dump(fd, pw, args);
3402         }
3403         if (mStatusBarWindowManager != null) {
3404             mStatusBarWindowManager.dump(fd, pw, args);
3405         }
3406         if (mNetworkController != null) {
3407             mNetworkController.dump(fd, pw, args);
3408         }
3409         if (mBluetoothController != null) {
3410             mBluetoothController.dump(fd, pw, args);
3411         }
3412         if (mHotspotController != null) {
3413             mHotspotController.dump(fd, pw, args);
3414         }
3415         if (mCastController != null) {
3416             mCastController.dump(fd, pw, args);
3417         }
3418         if (mUserSwitcherController != null) {
3419             mUserSwitcherController.dump(fd, pw, args);
3420         }
3421         if (mBatteryController != null) {
3422             mBatteryController.dump(fd, pw, args);
3423         }
3424         if (mNextAlarmController != null) {
3425             mNextAlarmController.dump(fd, pw, args);
3426         }
3427         if (mSecurityController != null) {
3428             mSecurityController.dump(fd, pw, args);
3429         }
3430         if (mHeadsUpManager != null) {
3431             mHeadsUpManager.dump(fd, pw, args);
3432         } else {
3433             pw.println("  mHeadsUpManager: null");
3434         }
3435         if (mGroupManager != null) {
3436             mGroupManager.dump(fd, pw, args);
3437         } else {
3438             pw.println("  mGroupManager: null");
3439         }
3440         if (KeyguardUpdateMonitor.getInstance(mContext) != null) {
3441             KeyguardUpdateMonitor.getInstance(mContext).dump(fd, pw, args);
3442         }
3443         if (mFlashlightController != null) {
3444             mFlashlightController.dump(fd, pw, args);
3445         }
3446 
3447         FalsingManager.getInstance(mContext).dump(pw);
3448         FalsingLog.dump(pw);
3449 
3450         pw.println("SharedPreferences:");
3451         for (Map.Entry<String, ?> entry : Prefs.getAll(mContext).entrySet()) {
3452             pw.print("  "); pw.print(entry.getKey()); pw.print("="); pw.println(entry.getValue());
3453         }
3454     }
3455 
dumpBarTransitions(PrintWriter pw, String var, BarTransitions transitions)3456     private static void dumpBarTransitions(PrintWriter pw, String var, BarTransitions transitions) {
3457         pw.print("  "); pw.print(var); pw.print(".BarTransitions.mMode=");
3458         pw.println(BarTransitions.modeToString(transitions.getMode()));
3459     }
3460 
3461     @Override
createAndAddWindows()3462     public void createAndAddWindows() {
3463         addStatusBarWindow();
3464     }
3465 
addStatusBarWindow()3466     private void addStatusBarWindow() {
3467         makeStatusBarView();
3468         mStatusBarWindowManager = new StatusBarWindowManager(mContext);
3469         mRemoteInputController = new RemoteInputController(mStatusBarWindowManager,
3470                 mHeadsUpManager);
3471         mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());
3472     }
3473 
3474     // called by makeStatusbar and also by PhoneStatusBarView
updateDisplaySize()3475     void updateDisplaySize() {
3476         mDisplay.getMetrics(mDisplayMetrics);
3477         mDisplay.getSize(mCurrentDisplaySize);
3478         if (DEBUG_GESTURES) {
3479             mGestureRec.tag("display",
3480                     String.format("%dx%d", mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels));
3481         }
3482     }
3483 
getDisplayDensity()3484     float getDisplayDensity() {
3485         return mDisplayMetrics.density;
3486     }
3487 
startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned, boolean dismissShade)3488     public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned,
3489             boolean dismissShade) {
3490         startActivityDismissingKeyguard(intent, onlyProvisioned, dismissShade, null /* callback */);
3491     }
3492 
startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned, final boolean dismissShade, final Callback callback)3493     public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned,
3494             final boolean dismissShade, final Callback callback) {
3495         if (onlyProvisioned && !isDeviceProvisioned()) return;
3496 
3497         final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity(
3498                 mContext, intent, mCurrentUserId);
3499         final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
3500         Runnable runnable = new Runnable() {
3501             @Override
3502             public void run() {
3503                 mAssistManager.hideAssist();
3504                 intent.setFlags(
3505                         Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
3506                 int result = ActivityManager.START_CANCELED;
3507                 ActivityOptions options = new ActivityOptions(getActivityOptions());
3508                 if (intent == KeyguardBottomAreaView.INSECURE_CAMERA_INTENT) {
3509                     // Normally an activity will set it's requested rotation
3510                     // animation on its window. However when launching an activity
3511                     // causes the orientation to change this is too late. In these cases
3512                     // the default animation is used. This doesn't look good for
3513                     // the camera (as it rotates the camera contents out of sync
3514                     // with physical reality). So, we ask the WindowManager to
3515                     // force the crossfade animation if an orientation change
3516                     // happens to occur during the launch.
3517                     options.setRotationAnimationHint(
3518                             WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS);
3519                 }
3520                 try {
3521                     result = ActivityManagerNative.getDefault().startActivityAsUser(
3522                             null, mContext.getBasePackageName(),
3523                             intent,
3524                             intent.resolveTypeIfNeeded(mContext.getContentResolver()),
3525                             null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null,
3526                             options.toBundle(), UserHandle.CURRENT.getIdentifier());
3527                 } catch (RemoteException e) {
3528                     Log.w(TAG, "Unable to start activity", e);
3529                 }
3530                 overrideActivityPendingAppTransition(
3531                         keyguardShowing && !afterKeyguardGone);
3532                 if (callback != null) {
3533                     callback.onActivityStarted(result);
3534                 }
3535             }
3536         };
3537         Runnable cancelRunnable = new Runnable() {
3538             @Override
3539             public void run() {
3540                 if (callback != null) {
3541                     callback.onActivityStarted(ActivityManager.START_CANCELED);
3542                 }
3543             }
3544         };
3545         executeRunnableDismissingKeyguard(runnable, cancelRunnable, dismissShade,
3546                 afterKeyguardGone, true /* deferred */);
3547     }
3548 
executeRunnableDismissingKeyguard(final Runnable runnable, final Runnable cancelAction, final boolean dismissShade, final boolean afterKeyguardGone, final boolean deferred)3549     public void executeRunnableDismissingKeyguard(final Runnable runnable,
3550             final Runnable cancelAction,
3551             final boolean dismissShade,
3552             final boolean afterKeyguardGone,
3553             final boolean deferred) {
3554         final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
3555         dismissKeyguardThenExecute(new OnDismissAction() {
3556             @Override
3557             public boolean onDismiss() {
3558                 AsyncTask.execute(new Runnable() {
3559                     @Override
3560                     public void run() {
3561                         try {
3562                             if (keyguardShowing && !afterKeyguardGone) {
3563                                 ActivityManagerNative.getDefault()
3564                                         .keyguardWaitingForActivityDrawn();
3565                             }
3566                             if (runnable != null) {
3567                                 runnable.run();
3568                             }
3569                         } catch (RemoteException e) {
3570                         }
3571                     }
3572                 });
3573                 if (dismissShade) {
3574                     animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */,
3575                             true /* delayed*/);
3576                 }
3577                 return deferred;
3578             }
3579         }, cancelAction, afterKeyguardGone);
3580     }
3581 
3582     private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
3583         @Override
3584         public void onReceive(Context context, Intent intent) {
3585             if (DEBUG) Log.v(TAG, "onReceive: " + intent);
3586             String action = intent.getAction();
3587             if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
3588                 KeyboardShortcuts.dismiss();
3589                 if (mRemoteInputController != null) {
3590                     mRemoteInputController.closeRemoteInputs();
3591                 }
3592                 if (isCurrentProfile(getSendingUserId())) {
3593                     int flags = CommandQueue.FLAG_EXCLUDE_NONE;
3594                     String reason = intent.getStringExtra("reason");
3595                     if (reason != null && reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) {
3596                         flags |= CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL;
3597                     }
3598                     animateCollapsePanels(flags);
3599                 }
3600             }
3601             else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
3602                 notifyNavigationBarScreenOn(false);
3603                 notifyHeadsUpScreenOff();
3604                 finishBarAnimations();
3605                 resetUserExpandedStates();
3606             }
3607             else if (Intent.ACTION_SCREEN_ON.equals(action)) {
3608                 notifyNavigationBarScreenOn(true);
3609             }
3610             else if (DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG.equals(action)) {
3611                 mQSPanel.showDeviceMonitoringDialog();
3612             }
3613         }
3614     };
3615 
3616     private BroadcastReceiver mDemoReceiver = new BroadcastReceiver() {
3617         @Override
3618         public void onReceive(Context context, Intent intent) {
3619             if (DEBUG) Log.v(TAG, "onReceive: " + intent);
3620             String action = intent.getAction();
3621             if (ACTION_DEMO.equals(action)) {
3622                 Bundle bundle = intent.getExtras();
3623                 if (bundle != null) {
3624                     String command = bundle.getString("command", "").trim().toLowerCase();
3625                     if (command.length() > 0) {
3626                         try {
3627                             dispatchDemoCommand(command, bundle);
3628                         } catch (Throwable t) {
3629                             Log.w(TAG, "Error running demo command, intent=" + intent, t);
3630                         }
3631                     }
3632                 }
3633             } else if (ACTION_FAKE_ARTWORK.equals(action)) {
3634                 if (DEBUG_MEDIA_FAKE_ARTWORK) {
3635                     updateMediaMetaData(true, true);
3636                 }
3637             }
3638         }
3639     };
3640 
resetUserExpandedStates()3641     public void resetUserExpandedStates() {
3642         ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
3643         final int notificationCount = activeNotifications.size();
3644         for (int i = 0; i < notificationCount; i++) {
3645             NotificationData.Entry entry = activeNotifications.get(i);
3646             if (entry.row != null) {
3647                 entry.row.resetUserExpansion();
3648             }
3649         }
3650     }
3651 
3652     @Override
dismissKeyguardThenExecute(OnDismissAction action, boolean afterKeyguardGone)3653     protected void dismissKeyguardThenExecute(OnDismissAction action, boolean afterKeyguardGone) {
3654         dismissKeyguardThenExecute(action, null /* cancelRunnable */, afterKeyguardGone);
3655     }
3656 
dismissKeyguard()3657     public void dismissKeyguard() {
3658         mStatusBarKeyguardViewManager.dismiss();
3659     }
3660 
dismissKeyguardThenExecute(OnDismissAction action, Runnable cancelAction, boolean afterKeyguardGone)3661     private void dismissKeyguardThenExecute(OnDismissAction action, Runnable cancelAction,
3662             boolean afterKeyguardGone) {
3663         if (mStatusBarKeyguardViewManager.isShowing()) {
3664             mStatusBarKeyguardViewManager.dismissWithAction(action, cancelAction,
3665                     afterKeyguardGone);
3666         } else {
3667             action.onDismiss();
3668         }
3669     }
3670 
3671     // SystemUIService notifies SystemBars of configuration changes, which then calls down here
3672     @Override
onConfigurationChanged(Configuration newConfig)3673     protected void onConfigurationChanged(Configuration newConfig) {
3674         updateResources();
3675         updateDisplaySize(); // populates mDisplayMetrics
3676         super.onConfigurationChanged(newConfig); // calls refreshLayout
3677 
3678         if (DEBUG) {
3679             Log.v(TAG, "configuration changed: " + mContext.getResources().getConfiguration());
3680         }
3681 
3682         repositionNavigationBar();
3683         updateRowStates();
3684         mScreenPinningRequest.onConfigurationChanged();
3685         mNetworkController.onConfigurationChanged();
3686     }
3687 
3688     @Override
userSwitched(int newUserId)3689     public void userSwitched(int newUserId) {
3690         super.userSwitched(newUserId);
3691         if (MULTIUSER_DEBUG) mNotificationPanelDebugText.setText("USER " + newUserId);
3692         animateCollapsePanels();
3693         updatePublicMode();
3694         updateNotifications();
3695         resetUserSetupObserver();
3696         setControllerUsers();
3697         clearCurrentMediaNotification();
3698         mLockscreenWallpaper.setCurrentUser(newUserId);
3699         mScrimController.setCurrentUser(newUserId);
3700         updateMediaMetaData(true, false);
3701     }
3702 
setControllerUsers()3703     private void setControllerUsers() {
3704         if (mZenModeController != null) {
3705             mZenModeController.setUserId(mCurrentUserId);
3706         }
3707         if (mSecurityController != null) {
3708             mSecurityController.onUserSwitched(mCurrentUserId);
3709         }
3710     }
3711 
resetUserSetupObserver()3712     private void resetUserSetupObserver() {
3713         mContext.getContentResolver().unregisterContentObserver(mUserSetupObserver);
3714         mUserSetupObserver.onChange(false);
3715         mContext.getContentResolver().registerContentObserver(
3716                 Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE), true,
3717                 mUserSetupObserver, mCurrentUserId);
3718     }
3719 
3720     /**
3721      * Reload some of our resources when the configuration changes.
3722      *
3723      * We don't reload everything when the configuration changes -- we probably
3724      * should, but getting that smooth is tough.  Someday we'll fix that.  In the
3725      * meantime, just update the things that we know change.
3726      */
updateResources()3727     void updateResources() {
3728         // Update the quick setting tiles
3729         if (mQSPanel != null) {
3730             mQSPanel.updateResources();
3731         }
3732 
3733         loadDimens();
3734 
3735         if (mNotificationPanel != null) {
3736             mNotificationPanel.updateResources();
3737         }
3738         if (mBrightnessMirrorController != null) {
3739             mBrightnessMirrorController.updateResources();
3740         }
3741     }
3742 
loadDimens()3743     protected void loadDimens() {
3744         final Resources res = mContext.getResources();
3745 
3746         int oldBarHeight = mNaturalBarHeight;
3747         mNaturalBarHeight = res.getDimensionPixelSize(
3748                 com.android.internal.R.dimen.status_bar_height);
3749         if (mStatusBarWindowManager != null && mNaturalBarHeight != oldBarHeight) {
3750             mStatusBarWindowManager.setBarHeight(mNaturalBarHeight);
3751         }
3752         mMaxAllowedKeyguardNotifications = res.getInteger(
3753                 R.integer.keyguard_max_notification_count);
3754 
3755         if (DEBUG) Log.v(TAG, "defineSlots");
3756     }
3757 
3758     // Visibility reporting
3759 
3760     @Override
handleVisibleToUserChanged(boolean visibleToUser)3761     protected void handleVisibleToUserChanged(boolean visibleToUser) {
3762         if (visibleToUser) {
3763             super.handleVisibleToUserChanged(visibleToUser);
3764             startNotificationLogging();
3765         } else {
3766             stopNotificationLogging();
3767             super.handleVisibleToUserChanged(visibleToUser);
3768         }
3769     }
3770 
stopNotificationLogging()3771     private void stopNotificationLogging() {
3772         // Report all notifications as invisible and turn down the
3773         // reporter.
3774         if (!mCurrentlyVisibleNotifications.isEmpty()) {
3775             logNotificationVisibilityChanges(Collections.<NotificationVisibility>emptyList(),
3776                     mCurrentlyVisibleNotifications);
3777             recycleAllVisibilityObjects(mCurrentlyVisibleNotifications);
3778         }
3779         mHandler.removeCallbacks(mVisibilityReporter);
3780         mStackScroller.setChildLocationsChangedListener(null);
3781     }
3782 
startNotificationLogging()3783     private void startNotificationLogging() {
3784         mStackScroller.setChildLocationsChangedListener(mNotificationLocationsChangedListener);
3785         // Some transitions like mVisibleToUser=false -> mVisibleToUser=true don't
3786         // cause the scroller to emit child location events. Hence generate
3787         // one ourselves to guarantee that we're reporting visible
3788         // notifications.
3789         // (Note that in cases where the scroller does emit events, this
3790         // additional event doesn't break anything.)
3791         mNotificationLocationsChangedListener.onChildLocationsChanged(mStackScroller);
3792     }
3793 
logNotificationVisibilityChanges( Collection<NotificationVisibility> newlyVisible, Collection<NotificationVisibility> noLongerVisible)3794     private void logNotificationVisibilityChanges(
3795             Collection<NotificationVisibility> newlyVisible,
3796             Collection<NotificationVisibility> noLongerVisible) {
3797         if (newlyVisible.isEmpty() && noLongerVisible.isEmpty()) {
3798             return;
3799         }
3800         NotificationVisibility[] newlyVisibleAr =
3801                 newlyVisible.toArray(new NotificationVisibility[newlyVisible.size()]);
3802         NotificationVisibility[] noLongerVisibleAr =
3803                 noLongerVisible.toArray(new NotificationVisibility[noLongerVisible.size()]);
3804         try {
3805             mBarService.onNotificationVisibilityChanged(newlyVisibleAr, noLongerVisibleAr);
3806         } catch (RemoteException e) {
3807             // Ignore.
3808         }
3809 
3810         final int N = newlyVisible.size();
3811         if (N > 0) {
3812             String[] newlyVisibleKeyAr = new String[N];
3813             for (int i = 0; i < N; i++) {
3814                 newlyVisibleKeyAr[i] = newlyVisibleAr[i].key;
3815             }
3816 
3817             setNotificationsShown(newlyVisibleKeyAr);
3818         }
3819     }
3820 
3821     // State logging
3822 
logStateToEventlog()3823     private void logStateToEventlog() {
3824         boolean isShowing = mStatusBarKeyguardViewManager.isShowing();
3825         boolean isOccluded = mStatusBarKeyguardViewManager.isOccluded();
3826         boolean isBouncerShowing = mStatusBarKeyguardViewManager.isBouncerShowing();
3827         boolean isSecure = mUnlockMethodCache.isMethodSecure();
3828         boolean canSkipBouncer = mUnlockMethodCache.canSkipBouncer();
3829         int stateFingerprint = getLoggingFingerprint(mState,
3830                 isShowing,
3831                 isOccluded,
3832                 isBouncerShowing,
3833                 isSecure,
3834                 canSkipBouncer);
3835         if (stateFingerprint != mLastLoggedStateFingerprint) {
3836             EventLogTags.writeSysuiStatusBarState(mState,
3837                     isShowing ? 1 : 0,
3838                     isOccluded ? 1 : 0,
3839                     isBouncerShowing ? 1 : 0,
3840                     isSecure ? 1 : 0,
3841                     canSkipBouncer ? 1 : 0);
3842             mLastLoggedStateFingerprint = stateFingerprint;
3843         }
3844     }
3845 
3846     /**
3847      * Returns a fingerprint of fields logged to eventlog
3848      */
getLoggingFingerprint(int statusBarState, boolean keyguardShowing, boolean keyguardOccluded, boolean bouncerShowing, boolean secure, boolean currentlyInsecure)3849     private static int getLoggingFingerprint(int statusBarState, boolean keyguardShowing,
3850             boolean keyguardOccluded, boolean bouncerShowing, boolean secure,
3851             boolean currentlyInsecure) {
3852         // Reserve 8 bits for statusBarState. We'll never go higher than
3853         // that, right? Riiiight.
3854         return (statusBarState & 0xFF)
3855                 | ((keyguardShowing   ? 1 : 0) <<  8)
3856                 | ((keyguardOccluded  ? 1 : 0) <<  9)
3857                 | ((bouncerShowing    ? 1 : 0) << 10)
3858                 | ((secure            ? 1 : 0) << 11)
3859                 | ((currentlyInsecure ? 1 : 0) << 12);
3860     }
3861 
3862     //
3863     // tracing
3864     //
3865 
postStartTracing()3866     void postStartTracing() {
3867         mHandler.postDelayed(mStartTracing, 3000);
3868     }
3869 
vibrate()3870     void vibrate() {
3871         android.os.Vibrator vib = (android.os.Vibrator)mContext.getSystemService(
3872                 Context.VIBRATOR_SERVICE);
3873         vib.vibrate(250, VIBRATION_ATTRIBUTES);
3874     }
3875 
3876     Runnable mStartTracing = new Runnable() {
3877         @Override
3878         public void run() {
3879             vibrate();
3880             SystemClock.sleep(250);
3881             Log.d(TAG, "startTracing");
3882             android.os.Debug.startMethodTracing("/data/statusbar-traces/trace");
3883             mHandler.postDelayed(mStopTracing, 10000);
3884         }
3885     };
3886 
3887     Runnable mStopTracing = new Runnable() {
3888         @Override
3889         public void run() {
3890             android.os.Debug.stopMethodTracing();
3891             Log.d(TAG, "stopTracing");
3892             vibrate();
3893         }
3894     };
3895 
3896     @Override
shouldDisableNavbarGestures()3897     public boolean shouldDisableNavbarGestures() {
3898         return !isDeviceProvisioned() || (mDisabled1 & StatusBarManager.DISABLE_SEARCH) != 0;
3899     }
3900 
postQSRunnableDismissingKeyguard(final Runnable runnable)3901     public void postQSRunnableDismissingKeyguard(final Runnable runnable) {
3902         mHandler.post(new Runnable() {
3903             @Override
3904             public void run() {
3905                 mLeaveOpenOnKeyguardHide = true;
3906                 executeRunnableDismissingKeyguard(runnable, null, false, false, false);
3907             }
3908         });
3909     }
3910 
postStartActivityDismissingKeyguard(final PendingIntent intent)3911     public void postStartActivityDismissingKeyguard(final PendingIntent intent) {
3912         mHandler.post(new Runnable() {
3913             @Override
3914             public void run() {
3915                 startPendingIntentDismissingKeyguard(intent);
3916             }
3917         });
3918     }
3919 
postStartActivityDismissingKeyguard(final Intent intent, int delay)3920     public void postStartActivityDismissingKeyguard(final Intent intent, int delay) {
3921         mHandler.postDelayed(new Runnable() {
3922             @Override
3923             public void run() {
3924                 handleStartActivityDismissingKeyguard(intent, true /*onlyProvisioned*/);
3925             }
3926         }, delay);
3927     }
3928 
handleStartActivityDismissingKeyguard(Intent intent, boolean onlyProvisioned)3929     private void handleStartActivityDismissingKeyguard(Intent intent, boolean onlyProvisioned) {
3930         startActivityDismissingKeyguard(intent, onlyProvisioned, true /* dismissShade */);
3931     }
3932 
3933     private static class FastColorDrawable extends Drawable {
3934         private final int mColor;
3935 
FastColorDrawable(int color)3936         public FastColorDrawable(int color) {
3937             mColor = 0xff000000 | color;
3938         }
3939 
3940         @Override
draw(Canvas canvas)3941         public void draw(Canvas canvas) {
3942             canvas.drawColor(mColor, PorterDuff.Mode.SRC);
3943         }
3944 
3945         @Override
setAlpha(int alpha)3946         public void setAlpha(int alpha) {
3947         }
3948 
3949         @Override
setColorFilter(ColorFilter colorFilter)3950         public void setColorFilter(ColorFilter colorFilter) {
3951         }
3952 
3953         @Override
getOpacity()3954         public int getOpacity() {
3955             return PixelFormat.OPAQUE;
3956         }
3957 
3958         @Override
setBounds(int left, int top, int right, int bottom)3959         public void setBounds(int left, int top, int right, int bottom) {
3960         }
3961 
3962         @Override
setBounds(Rect bounds)3963         public void setBounds(Rect bounds) {
3964         }
3965     }
3966 
3967     @Override
destroy()3968     public void destroy() {
3969         super.destroy();
3970         if (mStatusBarWindow != null) {
3971             mWindowManager.removeViewImmediate(mStatusBarWindow);
3972             mStatusBarWindow = null;
3973         }
3974         if (mNavigationBarView != null) {
3975             mWindowManager.removeViewImmediate(mNavigationBarView);
3976             mNavigationBarView = null;
3977         }
3978         if (mHandlerThread != null) {
3979             mHandlerThread.quitSafely();
3980             mHandlerThread = null;
3981         }
3982         mContext.unregisterReceiver(mBroadcastReceiver);
3983         mContext.unregisterReceiver(mDemoReceiver);
3984         mAssistManager.destroy();
3985 
3986         final SignalClusterView signalCluster =
3987                 (SignalClusterView) mStatusBarView.findViewById(R.id.signal_cluster);
3988         final SignalClusterView signalClusterKeyguard =
3989                 (SignalClusterView) mKeyguardStatusBar.findViewById(R.id.signal_cluster);
3990         final SignalClusterView signalClusterQs =
3991                 (SignalClusterView) mHeader.findViewById(R.id.signal_cluster);
3992         mNetworkController.removeSignalCallback(signalCluster);
3993         mNetworkController.removeSignalCallback(signalClusterKeyguard);
3994         mNetworkController.removeSignalCallback(signalClusterQs);
3995         if (mQSPanel != null && mQSPanel.getHost() != null) {
3996             mQSPanel.getHost().destroy();
3997         }
3998     }
3999 
4000     private boolean mDemoModeAllowed;
4001     private boolean mDemoMode;
4002 
4003     @Override
dispatchDemoCommand(String command, Bundle args)4004     public void dispatchDemoCommand(String command, Bundle args) {
4005         if (!mDemoModeAllowed) {
4006             mDemoModeAllowed = Settings.Global.getInt(mContext.getContentResolver(),
4007                     DEMO_MODE_ALLOWED, 0) != 0;
4008         }
4009         if (!mDemoModeAllowed) return;
4010         if (command.equals(COMMAND_ENTER)) {
4011             mDemoMode = true;
4012         } else if (command.equals(COMMAND_EXIT)) {
4013             mDemoMode = false;
4014             checkBarModes();
4015         } else if (!mDemoMode) {
4016             // automatically enter demo mode on first demo command
4017             dispatchDemoCommand(COMMAND_ENTER, new Bundle());
4018         }
4019         boolean modeChange = command.equals(COMMAND_ENTER) || command.equals(COMMAND_EXIT);
4020         if ((modeChange || command.equals(COMMAND_VOLUME)) && mVolumeComponent != null) {
4021             mVolumeComponent.dispatchDemoCommand(command, args);
4022         }
4023         if (modeChange || command.equals(COMMAND_CLOCK)) {
4024             dispatchDemoCommandToView(command, args, R.id.clock);
4025         }
4026         if (modeChange || command.equals(COMMAND_BATTERY)) {
4027             mBatteryController.dispatchDemoCommand(command, args);
4028         }
4029         if (modeChange || command.equals(COMMAND_STATUS)) {
4030             mIconController.dispatchDemoCommand(command, args);
4031         }
4032         if (mNetworkController != null && (modeChange || command.equals(COMMAND_NETWORK))) {
4033             mNetworkController.dispatchDemoCommand(command, args);
4034         }
4035         if (modeChange || command.equals(COMMAND_NOTIFICATIONS)) {
4036             View notifications = mStatusBarView == null ? null
4037                     : mStatusBarView.findViewById(R.id.notification_icon_area);
4038             if (notifications != null) {
4039                 String visible = args.getString("visible");
4040                 int vis = mDemoMode && "false".equals(visible) ? View.INVISIBLE : View.VISIBLE;
4041                 notifications.setVisibility(vis);
4042             }
4043         }
4044         if (command.equals(COMMAND_BARS)) {
4045             String mode = args.getString("mode");
4046             int barMode = "opaque".equals(mode) ? MODE_OPAQUE :
4047                     "translucent".equals(mode) ? MODE_TRANSLUCENT :
4048                     "semi-transparent".equals(mode) ? MODE_SEMI_TRANSPARENT :
4049                     "transparent".equals(mode) ? MODE_TRANSPARENT :
4050                     "warning".equals(mode) ? MODE_WARNING :
4051                     -1;
4052             if (barMode != -1) {
4053                 boolean animate = true;
4054                 if (mStatusBarView != null) {
4055                     mStatusBarView.getBarTransitions().transitionTo(barMode, animate);
4056                 }
4057                 if (mNavigationBarView != null) {
4058                     mNavigationBarView.getBarTransitions().transitionTo(barMode, animate);
4059                 }
4060             }
4061         }
4062     }
4063 
dispatchDemoCommandToView(String command, Bundle args, int id)4064     private void dispatchDemoCommandToView(String command, Bundle args, int id) {
4065         if (mStatusBarView == null) return;
4066         View v = mStatusBarView.findViewById(id);
4067         if (v instanceof DemoMode) {
4068             ((DemoMode)v).dispatchDemoCommand(command, args);
4069         }
4070     }
4071 
4072     /**
4073      * @return The {@link StatusBarState} the status bar is in.
4074      */
getBarState()4075     public int getBarState() {
4076         return mState;
4077     }
4078 
4079     @Override
isPanelFullyCollapsed()4080     public boolean isPanelFullyCollapsed() {
4081         return mNotificationPanel.isFullyCollapsed();
4082     }
4083 
showKeyguard()4084     public void showKeyguard() {
4085         if (mLaunchTransitionFadingAway) {
4086             mNotificationPanel.animate().cancel();
4087             onLaunchTransitionFadingEnded();
4088         }
4089         mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
4090         if (mUserSwitcherController != null && mUserSwitcherController.useFullscreenUserSwitcher()) {
4091             setBarState(StatusBarState.FULLSCREEN_USER_SWITCHER);
4092         } else {
4093             setBarState(StatusBarState.KEYGUARD);
4094         }
4095         updateKeyguardState(false /* goingToFullShade */, false /* fromShadeLocked */);
4096         if (!mDeviceInteractive) {
4097 
4098             // If the screen is off already, we need to disable touch events because these might
4099             // collapse the panel after we expanded it, and thus we would end up with a blank
4100             // Keyguard.
4101             mNotificationPanel.setTouchDisabled(true);
4102         }
4103         if (mState == StatusBarState.KEYGUARD) {
4104             instantExpandNotificationsPanel();
4105         } else if (mState == StatusBarState.FULLSCREEN_USER_SWITCHER) {
4106             instantCollapseNotificationPanel();
4107         }
4108         mLeaveOpenOnKeyguardHide = false;
4109         if (mDraggedDownRow != null) {
4110             mDraggedDownRow.setUserLocked(false);
4111             mDraggedDownRow.notifyHeightChanged(false  /* needsAnimation */);
4112             mDraggedDownRow = null;
4113         }
4114         mPendingRemoteInputView = null;
4115         mAssistManager.onLockscreenShown();
4116     }
4117 
onLaunchTransitionFadingEnded()4118     private void onLaunchTransitionFadingEnded() {
4119         mNotificationPanel.setAlpha(1.0f);
4120         mNotificationPanel.onAffordanceLaunchEnded();
4121         releaseGestureWakeLock();
4122         runLaunchTransitionEndRunnable();
4123         mLaunchTransitionFadingAway = false;
4124         mScrimController.forceHideScrims(false /* hide */);
4125         updateMediaMetaData(true /* metaDataChanged */, true);
4126     }
4127 
4128     @Override
isCollapsing()4129     public boolean isCollapsing() {
4130         return mNotificationPanel.isCollapsing();
4131     }
4132 
4133     @Override
addPostCollapseAction(Runnable r)4134     public void addPostCollapseAction(Runnable r) {
4135         mPostCollapseRunnables.add(r);
4136     }
4137 
isInLaunchTransition()4138     public boolean isInLaunchTransition() {
4139         return mNotificationPanel.isLaunchTransitionRunning()
4140                 || mNotificationPanel.isLaunchTransitionFinished();
4141     }
4142 
4143     /**
4144      * Fades the content of the keyguard away after the launch transition is done.
4145      *
4146      * @param beforeFading the runnable to be run when the circle is fully expanded and the fading
4147      *                     starts
4148      * @param endRunnable the runnable to be run when the transition is done
4149      */
fadeKeyguardAfterLaunchTransition(final Runnable beforeFading, Runnable endRunnable)4150     public void fadeKeyguardAfterLaunchTransition(final Runnable beforeFading,
4151             Runnable endRunnable) {
4152         mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
4153         mLaunchTransitionEndRunnable = endRunnable;
4154         Runnable hideRunnable = new Runnable() {
4155             @Override
4156             public void run() {
4157                 mLaunchTransitionFadingAway = true;
4158                 if (beforeFading != null) {
4159                     beforeFading.run();
4160                 }
4161                 mScrimController.forceHideScrims(true /* hide */);
4162                 updateMediaMetaData(false, true);
4163                 mNotificationPanel.setAlpha(1);
4164                 mStackScroller.setParentFadingOut(true);
4165                 mNotificationPanel.animate()
4166                         .alpha(0)
4167                         .setStartDelay(FADE_KEYGUARD_START_DELAY)
4168                         .setDuration(FADE_KEYGUARD_DURATION)
4169                         .withLayer()
4170                         .withEndAction(new Runnable() {
4171                             @Override
4172                             public void run() {
4173                                 onLaunchTransitionFadingEnded();
4174                             }
4175                         });
4176                 mIconController.appTransitionStarting(SystemClock.uptimeMillis(),
4177                         StatusBarIconController.DEFAULT_TINT_ANIMATION_DURATION);
4178             }
4179         };
4180         if (mNotificationPanel.isLaunchTransitionRunning()) {
4181             mNotificationPanel.setLaunchTransitionEndRunnable(hideRunnable);
4182         } else {
4183             hideRunnable.run();
4184         }
4185     }
4186 
4187     /**
4188      * Fades the content of the Keyguard while we are dozing and makes it invisible when finished
4189      * fading.
4190      */
fadeKeyguardWhilePulsing()4191     public void fadeKeyguardWhilePulsing() {
4192         mNotificationPanel.animate()
4193                 .alpha(0f)
4194                 .setStartDelay(0)
4195                 .setDuration(FADE_KEYGUARD_DURATION_PULSING)
4196                 .setInterpolator(ScrimController.KEYGUARD_FADE_OUT_INTERPOLATOR)
4197                 .start();
4198     }
4199 
4200     /**
4201      * Plays the animation when an activity that was occluding Keyguard goes away.
4202      */
animateKeyguardUnoccluding()4203     public void animateKeyguardUnoccluding() {
4204         mScrimController.animateKeyguardUnoccluding(500);
4205         mNotificationPanel.setExpandedFraction(0f);
4206         animateExpandNotificationsPanel();
4207     }
4208 
4209     /**
4210      * Starts the timeout when we try to start the affordances on Keyguard. We usually rely that
4211      * Keyguard goes away via fadeKeyguardAfterLaunchTransition, however, that might not happen
4212      * because the launched app crashed or something else went wrong.
4213      */
startLaunchTransitionTimeout()4214     public void startLaunchTransitionTimeout() {
4215         mHandler.sendEmptyMessageDelayed(MSG_LAUNCH_TRANSITION_TIMEOUT,
4216                 LAUNCH_TRANSITION_TIMEOUT_MS);
4217     }
4218 
onLaunchTransitionTimeout()4219     private void onLaunchTransitionTimeout() {
4220         Log.w(TAG, "Launch transition: Timeout!");
4221         mNotificationPanel.onAffordanceLaunchEnded();
4222         releaseGestureWakeLock();
4223         mNotificationPanel.resetViews();
4224     }
4225 
runLaunchTransitionEndRunnable()4226     private void runLaunchTransitionEndRunnable() {
4227         if (mLaunchTransitionEndRunnable != null) {
4228             Runnable r = mLaunchTransitionEndRunnable;
4229 
4230             // mLaunchTransitionEndRunnable might call showKeyguard, which would execute it again,
4231             // which would lead to infinite recursion. Protect against it.
4232             mLaunchTransitionEndRunnable = null;
4233             r.run();
4234         }
4235     }
4236 
4237     /**
4238      * @return true if we would like to stay in the shade, false if it should go away entirely
4239      */
hideKeyguard()4240     public boolean hideKeyguard() {
4241         Trace.beginSection("PhoneStatusBar#hideKeyguard");
4242         boolean staying = mLeaveOpenOnKeyguardHide;
4243         setBarState(StatusBarState.SHADE);
4244         View viewToClick = null;
4245         if (mLeaveOpenOnKeyguardHide) {
4246             mLeaveOpenOnKeyguardHide = false;
4247             long delay = calculateGoingToFullShadeDelay();
4248             mNotificationPanel.animateToFullShade(delay);
4249             if (mDraggedDownRow != null) {
4250                 mDraggedDownRow.setUserLocked(false);
4251                 mDraggedDownRow = null;
4252             }
4253             viewToClick = mPendingRemoteInputView;
4254             mPendingRemoteInputView = null;
4255 
4256             // Disable layout transitions in navbar for this transition because the load is just
4257             // too heavy for the CPU and GPU on any device.
4258             if (mNavigationBarView != null) {
4259                 mNavigationBarView.setLayoutTransitionsEnabled(false);
4260                 mNavigationBarView.postDelayed(new Runnable() {
4261                     @Override
4262                     public void run() {
4263                         mNavigationBarView.setLayoutTransitionsEnabled(true);
4264                     }
4265                 }, delay + StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE);
4266             }
4267         } else {
4268             instantCollapseNotificationPanel();
4269         }
4270         updateKeyguardState(staying, false /* fromShadeLocked */);
4271 
4272         if (viewToClick != null && viewToClick.isAttachedToWindow()) {
4273             viewToClick.callOnClick();
4274         }
4275 
4276         // Keyguard state has changed, but QS is not listening anymore. Make sure to update the tile
4277         // visibilities so next time we open the panel we know the correct height already.
4278         if (mQSPanel != null) {
4279             mQSPanel.refreshAllTiles();
4280         }
4281         mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
4282         releaseGestureWakeLock();
4283         mNotificationPanel.onAffordanceLaunchEnded();
4284         mNotificationPanel.animate().cancel();
4285         mNotificationPanel.setAlpha(1f);
4286         Trace.endSection();
4287         return staying;
4288     }
4289 
releaseGestureWakeLock()4290     private void releaseGestureWakeLock() {
4291         if (mGestureWakeLock.isHeld()) {
4292             mGestureWakeLock.release();
4293         }
4294     }
4295 
calculateGoingToFullShadeDelay()4296     public long calculateGoingToFullShadeDelay() {
4297         return mKeyguardFadingAwayDelay + mKeyguardFadingAwayDuration;
4298     }
4299 
4300     /**
4301      * Notifies the status bar that Keyguard is going away very soon.
4302      */
keyguardGoingAway()4303     public void keyguardGoingAway() {
4304 
4305         // Treat Keyguard exit animation as an app transition to achieve nice transition for status
4306         // bar.
4307         mKeyguardGoingAway = true;
4308         mIconController.appTransitionPending();
4309     }
4310 
4311     /**
4312      * Notifies the status bar the Keyguard is fading away with the specified timings.
4313      *
4314      * @param startTime the start time of the animations in uptime millis
4315      * @param delay the precalculated animation delay in miliseconds
4316      * @param fadeoutDuration the duration of the exit animation, in milliseconds
4317      */
setKeyguardFadingAway(long startTime, long delay, long fadeoutDuration)4318     public void setKeyguardFadingAway(long startTime, long delay, long fadeoutDuration) {
4319         mKeyguardFadingAway = true;
4320         mKeyguardFadingAwayDelay = delay;
4321         mKeyguardFadingAwayDuration = fadeoutDuration;
4322         mWaitingForKeyguardExit = false;
4323         mIconController.appTransitionStarting(
4324                 startTime + fadeoutDuration
4325                         - StatusBarIconController.DEFAULT_TINT_ANIMATION_DURATION,
4326                 StatusBarIconController.DEFAULT_TINT_ANIMATION_DURATION);
4327         recomputeDisableFlags(fadeoutDuration > 0 /* animate */);
4328     }
4329 
isKeyguardFadingAway()4330     public boolean isKeyguardFadingAway() {
4331         return mKeyguardFadingAway;
4332     }
4333 
4334     /**
4335      * Notifies that the Keyguard fading away animation is done.
4336      */
finishKeyguardFadingAway()4337     public void finishKeyguardFadingAway() {
4338         mKeyguardFadingAway = false;
4339         mKeyguardGoingAway = false;
4340     }
4341 
stopWaitingForKeyguardExit()4342     public void stopWaitingForKeyguardExit() {
4343         mWaitingForKeyguardExit = false;
4344     }
4345 
updatePublicMode()4346     private void updatePublicMode() {
4347         boolean isPublic = false;
4348         if (mStatusBarKeyguardViewManager.isShowing()) {
4349             for (int i = mCurrentProfiles.size() - 1; i >= 0; i--) {
4350                 UserInfo userInfo = mCurrentProfiles.valueAt(i);
4351                 if (mStatusBarKeyguardViewManager.isSecure(userInfo.id)) {
4352                     isPublic = true;
4353                     break;
4354                 }
4355             }
4356         }
4357         setLockscreenPublicMode(isPublic);
4358     }
4359 
updateKeyguardState(boolean goingToFullShade, boolean fromShadeLocked)4360     protected void updateKeyguardState(boolean goingToFullShade, boolean fromShadeLocked) {
4361         Trace.beginSection("PhoneStatusBar#updateKeyguardState");
4362         if (mState == StatusBarState.KEYGUARD) {
4363             mKeyguardIndicationController.setVisible(true);
4364             mNotificationPanel.resetViews();
4365             if (mKeyguardUserSwitcher != null) {
4366                 mKeyguardUserSwitcher.setKeyguard(true, fromShadeLocked);
4367             }
4368             mStatusBarView.removePendingHideExpandedRunnables();
4369         } else {
4370             mKeyguardIndicationController.setVisible(false);
4371             if (mKeyguardUserSwitcher != null) {
4372                 mKeyguardUserSwitcher.setKeyguard(false,
4373                         goingToFullShade ||
4374                         mState == StatusBarState.SHADE_LOCKED ||
4375                         fromShadeLocked);
4376             }
4377         }
4378         if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
4379             mScrimController.setKeyguardShowing(true);
4380         } else {
4381             mScrimController.setKeyguardShowing(false);
4382         }
4383         mIconPolicy.notifyKeyguardShowingChanged();
4384         mNotificationPanel.setBarState(mState, mKeyguardFadingAway, goingToFullShade);
4385         updateDozingState();
4386         updatePublicMode();
4387         updateStackScrollerState(goingToFullShade, fromShadeLocked);
4388         updateNotifications();
4389         checkBarModes();
4390         updateMediaMetaData(false, mState != StatusBarState.KEYGUARD);
4391         mKeyguardMonitor.notifyKeyguardState(mStatusBarKeyguardViewManager.isShowing(),
4392                 mStatusBarKeyguardViewManager.isSecure(),
4393                 mStatusBarKeyguardViewManager.isOccluded());
4394         Trace.endSection();
4395     }
4396 
updateDozingState()4397     private void updateDozingState() {
4398         Trace.beginSection("PhoneStatusBar#updateDozingState");
4399         boolean animate = !mDozing && mDozeScrimController.isPulsing();
4400         mNotificationPanel.setDozing(mDozing, animate);
4401         mStackScroller.setDark(mDozing, animate, mWakeUpTouchLocation);
4402         mScrimController.setDozing(mDozing);
4403 
4404         // Immediately abort the dozing from the doze scrim controller in case of wake-and-unlock
4405         // for pulsing so the Keyguard fade-out animation scrim can take over.
4406         mDozeScrimController.setDozing(mDozing &&
4407                 mFingerprintUnlockController.getMode()
4408                         != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING, animate);
4409         Trace.endSection();
4410     }
4411 
updateStackScrollerState(boolean goingToFullShade, boolean fromShadeLocked)4412     public void updateStackScrollerState(boolean goingToFullShade, boolean fromShadeLocked) {
4413         if (mStackScroller == null) return;
4414         boolean onKeyguard = mState == StatusBarState.KEYGUARD;
4415         mStackScroller.setHideSensitive(isLockscreenPublicMode(), goingToFullShade);
4416         mStackScroller.setDimmed(onKeyguard, fromShadeLocked /* animate */);
4417         mStackScroller.setExpandingEnabled(!onKeyguard);
4418         ActivatableNotificationView activatedChild = mStackScroller.getActivatedChild();
4419         mStackScroller.setActivatedChild(null);
4420         if (activatedChild != null) {
4421             activatedChild.makeInactive(false /* animate */);
4422         }
4423     }
4424 
userActivity()4425     public void userActivity() {
4426         if (mState == StatusBarState.KEYGUARD) {
4427             mKeyguardViewMediatorCallback.userActivity();
4428         }
4429     }
4430 
interceptMediaKey(KeyEvent event)4431     public boolean interceptMediaKey(KeyEvent event) {
4432         return mState == StatusBarState.KEYGUARD
4433                 && mStatusBarKeyguardViewManager.interceptMediaKey(event);
4434     }
4435 
onMenuPressed()4436     public boolean onMenuPressed() {
4437         if (mDeviceInteractive && mState != StatusBarState.SHADE
4438                 && mStatusBarKeyguardViewManager.shouldDismissOnMenuPressed()) {
4439             animateCollapsePanels(
4440                     CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL /* flags */, true /* force */);
4441             return true;
4442         }
4443         return false;
4444     }
4445 
endAffordanceLaunch()4446     public void endAffordanceLaunch() {
4447         releaseGestureWakeLock();
4448         mNotificationPanel.onAffordanceLaunchEnded();
4449     }
4450 
onBackPressed()4451     public boolean onBackPressed() {
4452         if (mStatusBarKeyguardViewManager.onBackPressed()) {
4453             return true;
4454         }
4455         if (mNotificationPanel.isQsExpanded()) {
4456             if (mNotificationPanel.isQsDetailShowing()) {
4457                 mNotificationPanel.closeQsDetail();
4458             } else {
4459                 mNotificationPanel.animateCloseQs();
4460             }
4461             return true;
4462         }
4463         if (mState != StatusBarState.KEYGUARD && mState != StatusBarState.SHADE_LOCKED) {
4464             animateCollapsePanels();
4465             return true;
4466         }
4467         return false;
4468     }
4469 
onSpacePressed()4470     public boolean onSpacePressed() {
4471         if (mDeviceInteractive && mState != StatusBarState.SHADE) {
4472             animateCollapsePanels(
4473                     CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL /* flags */, true /* force */);
4474             return true;
4475         }
4476         return false;
4477     }
4478 
showBouncerIfKeyguard()4479     private void showBouncerIfKeyguard() {
4480         if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
4481             showBouncer();
4482         }
4483     }
4484 
showBouncer()4485     private void showBouncer() {
4486         mWaitingForKeyguardExit = mStatusBarKeyguardViewManager.isShowing();
4487         mStatusBarKeyguardViewManager.dismiss();
4488     }
4489 
instantExpandNotificationsPanel()4490     private void instantExpandNotificationsPanel() {
4491 
4492         // Make our window larger and the panel expanded.
4493         makeExpandedVisible(true);
4494         mNotificationPanel.expand(false /* animate */);
4495     }
4496 
instantCollapseNotificationPanel()4497     private void instantCollapseNotificationPanel() {
4498         mNotificationPanel.instantCollapse();
4499     }
4500 
4501     @Override
onActivated(ActivatableNotificationView view)4502     public void onActivated(ActivatableNotificationView view) {
4503         EventLogTags.writeSysuiLockscreenGesture(
4504                 EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_TAP_NOTIFICATION_ACTIVATE,
4505                 0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */);
4506         mKeyguardIndicationController.showTransientIndication(R.string.notification_tap_again);
4507         ActivatableNotificationView previousView = mStackScroller.getActivatedChild();
4508         if (previousView != null) {
4509             previousView.makeInactive(true /* animate */);
4510         }
4511         mStackScroller.setActivatedChild(view);
4512     }
4513 
getHomeButton()4514     public ButtonDispatcher getHomeButton() {
4515         return mNavigationBarView.getHomeButton();
4516     }
4517 
4518     /**
4519      * @param state The {@link StatusBarState} to set.
4520      */
setBarState(int state)4521     public void setBarState(int state) {
4522         // If we're visible and switched to SHADE_LOCKED (the user dragged
4523         // down on the lockscreen), clear notification LED, vibration,
4524         // ringing.
4525         // Other transitions are covered in handleVisibleToUserChanged().
4526         if (state != mState && mVisible && (state == StatusBarState.SHADE_LOCKED
4527                 || (state == StatusBarState.SHADE && isGoingToNotificationShade()))) {
4528             clearNotificationEffects();
4529         }
4530         if (state == StatusBarState.KEYGUARD) {
4531             removeRemoteInputEntriesKeptUntilCollapsed();
4532             maybeEscalateHeadsUp();
4533         }
4534         mState = state;
4535         mGroupManager.setStatusBarState(state);
4536         mHeadsUpManager.setStatusBarState(state);
4537         mFalsingManager.setStatusBarState(state);
4538         mStatusBarWindowManager.setStatusBarState(state);
4539         updateReportRejectedTouchVisibility();
4540         updateDozing();
4541     }
4542 
4543     @Override
onActivationReset(ActivatableNotificationView view)4544     public void onActivationReset(ActivatableNotificationView view) {
4545         if (view == mStackScroller.getActivatedChild()) {
4546             mKeyguardIndicationController.hideTransientIndication();
4547             mStackScroller.setActivatedChild(null);
4548         }
4549     }
4550 
onTrackingStarted()4551     public void onTrackingStarted() {
4552         runPostCollapseRunnables();
4553     }
4554 
onClosingFinished()4555     public void onClosingFinished() {
4556         runPostCollapseRunnables();
4557     }
4558 
onUnlockHintStarted()4559     public void onUnlockHintStarted() {
4560         mFalsingManager.onUnlockHintStarted();
4561         mKeyguardIndicationController.showTransientIndication(R.string.keyguard_unlock);
4562     }
4563 
onHintFinished()4564     public void onHintFinished() {
4565         // Delay the reset a bit so the user can read the text.
4566         mKeyguardIndicationController.hideTransientIndicationDelayed(HINT_RESET_DELAY_MS);
4567     }
4568 
onCameraHintStarted()4569     public void onCameraHintStarted() {
4570         mFalsingManager.onCameraHintStarted();
4571         mKeyguardIndicationController.showTransientIndication(R.string.camera_hint);
4572     }
4573 
onVoiceAssistHintStarted()4574     public void onVoiceAssistHintStarted() {
4575         mFalsingManager.onLeftAffordanceHintStarted();
4576         mKeyguardIndicationController.showTransientIndication(R.string.voice_hint);
4577     }
4578 
onPhoneHintStarted()4579     public void onPhoneHintStarted() {
4580         mFalsingManager.onLeftAffordanceHintStarted();
4581         mKeyguardIndicationController.showTransientIndication(R.string.phone_hint);
4582     }
4583 
onTrackingStopped(boolean expand)4584     public void onTrackingStopped(boolean expand) {
4585         if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
4586             if (!expand && !mUnlockMethodCache.canSkipBouncer()) {
4587                 showBouncerIfKeyguard();
4588             }
4589         }
4590     }
4591 
4592     @Override
getMaxKeyguardNotifications(boolean recompute)4593     protected int getMaxKeyguardNotifications(boolean recompute) {
4594         if (recompute) {
4595             mMaxKeyguardNotifications = Math.max(1,
4596                     mNotificationPanel.computeMaxKeyguardNotifications(
4597                             mMaxAllowedKeyguardNotifications));
4598             return mMaxKeyguardNotifications;
4599         }
4600         return mMaxKeyguardNotifications;
4601     }
4602 
getMaxKeyguardNotifications()4603     public int getMaxKeyguardNotifications() {
4604         return getMaxKeyguardNotifications(false /* recompute */);
4605     }
4606 
getNavigationBarView()4607     public NavigationBarView getNavigationBarView() {
4608         return mNavigationBarView;
4609     }
4610 
4611     // ---------------------- DragDownHelper.OnDragDownListener ------------------------------------
4612 
4613 
4614     /* Only ever called as a consequence of a lockscreen expansion gesture. */
4615     @Override
onDraggedDown(View startingChild, int dragLengthY)4616     public boolean onDraggedDown(View startingChild, int dragLengthY) {
4617         if (hasActiveNotifications()) {
4618             EventLogTags.writeSysuiLockscreenGesture(
4619                     EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_SWIPE_DOWN_FULL_SHADE,
4620                     (int) (dragLengthY / mDisplayMetrics.density),
4621                     0 /* velocityDp - N/A */);
4622 
4623             // We have notifications, go to locked shade.
4624             goToLockedShade(startingChild);
4625             if (startingChild instanceof ExpandableNotificationRow) {
4626                 ExpandableNotificationRow row = (ExpandableNotificationRow) startingChild;
4627                 row.onExpandedByGesture(true /* drag down is always an open */);
4628             }
4629             return true;
4630         } else {
4631 
4632             // No notifications - abort gesture.
4633             return false;
4634         }
4635     }
4636 
4637     @Override
onDragDownReset()4638     public void onDragDownReset() {
4639         mStackScroller.setDimmed(true /* dimmed */, true /* animated */);
4640         mStackScroller.resetScrollPosition();
4641     }
4642 
4643     @Override
onCrossedThreshold(boolean above)4644     public void onCrossedThreshold(boolean above) {
4645         mStackScroller.setDimmed(!above /* dimmed */, true /* animate */);
4646     }
4647 
4648     @Override
onTouchSlopExceeded()4649     public void onTouchSlopExceeded() {
4650         mStackScroller.removeLongPressCallback();
4651     }
4652 
4653     @Override
setEmptyDragAmount(float amount)4654     public void setEmptyDragAmount(float amount) {
4655         mNotificationPanel.setEmptyDragAmount(amount);
4656     }
4657 
4658     /**
4659      * If secure with redaction: Show bouncer, go to unlocked shade.
4660      *
4661      * <p>If secure without redaction or no security: Go to {@link StatusBarState#SHADE_LOCKED}.</p>
4662      *
4663      * @param expandView The view to expand after going to the shade.
4664      */
goToLockedShade(View expandView)4665     public void goToLockedShade(View expandView) {
4666         ExpandableNotificationRow row = null;
4667         if (expandView instanceof ExpandableNotificationRow) {
4668             row = (ExpandableNotificationRow) expandView;
4669             row.setUserExpanded(true /* userExpanded */, true /* allowChildExpansion */);
4670             // Indicate that the group expansion is changing at this time -- this way the group
4671             // and children backgrounds / divider animations will look correct.
4672             row.setGroupExpansionChanging(true);
4673         }
4674         boolean fullShadeNeedsBouncer = !userAllowsPrivateNotificationsInPublic(mCurrentUserId)
4675                 || !mShowLockscreenNotifications || mFalsingManager.shouldEnforceBouncer();
4676         if (isLockscreenPublicMode() && fullShadeNeedsBouncer) {
4677             mLeaveOpenOnKeyguardHide = true;
4678             showBouncerIfKeyguard();
4679             mDraggedDownRow = row;
4680             mPendingRemoteInputView = null;
4681         } else {
4682             mNotificationPanel.animateToFullShade(0 /* delay */);
4683             setBarState(StatusBarState.SHADE_LOCKED);
4684             updateKeyguardState(false /* goingToFullShade */, false /* fromShadeLocked */);
4685         }
4686     }
4687 
4688     @Override
onLockedNotificationImportanceChange(OnDismissAction dismissAction)4689     public void onLockedNotificationImportanceChange(OnDismissAction dismissAction) {
4690         mLeaveOpenOnKeyguardHide = true;
4691         dismissKeyguardThenExecute(dismissAction, true /* afterKeyguardGone */);
4692     }
4693 
4694     @Override
onLockedRemoteInput(ExpandableNotificationRow row, View clicked)4695     protected void onLockedRemoteInput(ExpandableNotificationRow row, View clicked) {
4696         mLeaveOpenOnKeyguardHide = true;
4697         showBouncer();
4698         mPendingRemoteInputView = clicked;
4699     }
4700 
4701     @Override
startWorkChallengeIfNecessary(int userId, IntentSender intendSender, String notificationKey)4702     protected boolean startWorkChallengeIfNecessary(int userId, IntentSender intendSender,
4703             String notificationKey) {
4704         // Clear pending remote view, as we do not want to trigger pending remote input view when
4705         // it's called by other code
4706         mPendingWorkRemoteInputView = null;
4707         return super.startWorkChallengeIfNecessary(userId, intendSender, notificationKey);
4708     }
4709 
4710     @Override
onLockedWorkRemoteInput(int userId, ExpandableNotificationRow row, View clicked)4711     protected void onLockedWorkRemoteInput(int userId, ExpandableNotificationRow row,
4712             View clicked) {
4713         // Collapse notification and show work challenge
4714         animateCollapsePanels();
4715         startWorkChallengeIfNecessary(userId, null, null);
4716         // Add pending remote input view after starting work challenge, as starting work challenge
4717         // will clear all previous pending review view
4718         mPendingWorkRemoteInputView = clicked;
4719     }
4720 
4721     @Override
onWorkChallengeUnlocked()4722     protected void onWorkChallengeUnlocked() {
4723         if (mPendingWorkRemoteInputView != null) {
4724             final View pendingWorkRemoteInputView = mPendingWorkRemoteInputView;
4725             // Expand notification panel and the notification row, then click on remote input view
4726             final Runnable clickPendingViewRunnable = new Runnable() {
4727                 @Override
4728                 public void run() {
4729                     if (mPendingWorkRemoteInputView != null) {
4730                         final View pendingWorkRemoteInputView = mPendingWorkRemoteInputView;
4731                         ViewParent p = pendingWorkRemoteInputView.getParent();
4732                         while (p != null) {
4733                             if (p instanceof ExpandableNotificationRow) {
4734                                 final ExpandableNotificationRow row = (ExpandableNotificationRow) p;
4735                                 ViewParent viewParent = row.getParent();
4736                                 if (viewParent instanceof NotificationStackScrollLayout) {
4737                                     final NotificationStackScrollLayout scrollLayout =
4738                                             (NotificationStackScrollLayout) viewParent;
4739                                     row.makeActionsVisibile();
4740                                     row.post(new Runnable() {
4741                                         @Override
4742                                         public void run() {
4743                                             final Runnable finishScrollingCallback = new Runnable()
4744                                             {
4745                                                 @Override
4746                                                 public void run() {
4747                                                     mPendingWorkRemoteInputView.callOnClick();
4748                                                     mPendingWorkRemoteInputView = null;
4749                                                     scrollLayout.setFinishScrollingCallback(null);
4750                                                 }
4751                                             };
4752                                             if (scrollLayout.scrollTo(row)) {
4753                                                 // It scrolls! So call it when it's finished.
4754                                                 scrollLayout.setFinishScrollingCallback(
4755                                                         finishScrollingCallback);
4756                                             } else {
4757                                                 // It does not scroll, so call it now!
4758                                                 finishScrollingCallback.run();
4759                                             }
4760                                         }
4761                                     });
4762                                 }
4763                                 break;
4764                             }
4765                             p = p.getParent();
4766                         }
4767                     }
4768                 }
4769             };
4770             mNotificationPanel.getViewTreeObserver().addOnGlobalLayoutListener(
4771                     new ViewTreeObserver.OnGlobalLayoutListener() {
4772                         @Override
4773                         public void onGlobalLayout() {
4774                             if (mNotificationPanel.mStatusBar.getStatusBarWindow()
4775                                     .getHeight() != mNotificationPanel.mStatusBar
4776                                             .getStatusBarHeight()) {
4777                                 mNotificationPanel.getViewTreeObserver()
4778                                         .removeOnGlobalLayoutListener(this);
4779                                 mNotificationPanel.post(clickPendingViewRunnable);
4780                             }
4781                         }
4782                     });
4783             instantExpandNotificationsPanel();
4784         }
4785     }
4786 
4787     @Override
onExpandClicked(Entry clickedEntry, boolean nowExpanded)4788     public void onExpandClicked(Entry clickedEntry, boolean nowExpanded) {
4789         mHeadsUpManager.setExpanded(clickedEntry, nowExpanded);
4790         if (mState == StatusBarState.KEYGUARD && nowExpanded) {
4791             goToLockedShade(clickedEntry.row);
4792         }
4793     }
4794 
4795     /**
4796      * Goes back to the keyguard after hanging around in {@link StatusBarState#SHADE_LOCKED}.
4797      */
goToKeyguard()4798     public void goToKeyguard() {
4799         if (mState == StatusBarState.SHADE_LOCKED) {
4800             mStackScroller.onGoToKeyguard();
4801             setBarState(StatusBarState.KEYGUARD);
4802             updateKeyguardState(false /* goingToFullShade */, true /* fromShadeLocked*/);
4803         }
4804     }
4805 
getKeyguardFadingAwayDelay()4806     public long getKeyguardFadingAwayDelay() {
4807         return mKeyguardFadingAwayDelay;
4808     }
4809 
getKeyguardFadingAwayDuration()4810     public long getKeyguardFadingAwayDuration() {
4811         return mKeyguardFadingAwayDuration;
4812     }
4813 
4814     @Override
setBouncerShowing(boolean bouncerShowing)4815     public void setBouncerShowing(boolean bouncerShowing) {
4816         super.setBouncerShowing(bouncerShowing);
4817         mStatusBarView.setBouncerShowing(bouncerShowing);
4818         recomputeDisableFlags(true /* animate */);
4819     }
4820 
onStartedGoingToSleep()4821     public void onStartedGoingToSleep() {
4822         mStartedGoingToSleep = true;
4823     }
4824 
onFinishedGoingToSleep()4825     public void onFinishedGoingToSleep() {
4826         mNotificationPanel.onAffordanceLaunchEnded();
4827         releaseGestureWakeLock();
4828         mLaunchCameraOnScreenTurningOn = false;
4829         mStartedGoingToSleep = false;
4830         mDeviceInteractive = false;
4831         mWakeUpComingFromTouch = false;
4832         mWakeUpTouchLocation = null;
4833         mStackScroller.setAnimationsEnabled(false);
4834         mVisualStabilityManager.setScreenOn(false);
4835         updateVisibleToUser();
4836         if (mLaunchCameraOnFinishedGoingToSleep) {
4837             mLaunchCameraOnFinishedGoingToSleep = false;
4838 
4839             // This gets executed before we will show Keyguard, so post it in order that the state
4840             // is correct.
4841             mHandler.post(new Runnable() {
4842                 @Override
4843                 public void run() {
4844                     onCameraLaunchGestureDetected(mLastCameraLaunchSource);
4845                 }
4846             });
4847         }
4848     }
4849 
onStartedWakingUp()4850     public void onStartedWakingUp() {
4851         mDeviceInteractive = true;
4852         mStackScroller.setAnimationsEnabled(true);
4853         mVisualStabilityManager.setScreenOn(true);
4854         mNotificationPanel.setTouchDisabled(false);
4855         updateVisibleToUser();
4856     }
4857 
onScreenTurningOn()4858     public void onScreenTurningOn() {
4859         mScreenTurningOn = true;
4860         mFalsingManager.onScreenTurningOn();
4861         mNotificationPanel.onScreenTurningOn();
4862         if (mLaunchCameraOnScreenTurningOn) {
4863             mNotificationPanel.launchCamera(false, mLastCameraLaunchSource);
4864             mLaunchCameraOnScreenTurningOn = false;
4865         }
4866     }
4867 
vibrateForCameraGesture()4868     private void vibrateForCameraGesture() {
4869         // Make sure to pass -1 for repeat so VibratorService doesn't stop us when going to sleep.
4870         mVibrator.vibrate(new long[]{0, 400}, -1 /* repeat */);
4871     }
4872 
onScreenTurnedOn()4873     public void onScreenTurnedOn() {
4874         mScreenTurningOn = false;
4875         mDozeScrimController.onScreenTurnedOn();
4876     }
4877 
4878     /**
4879      * This handles long-press of both back and recents.  They are
4880      * handled together to capture them both being long-pressed
4881      * at the same time to exit screen pinning (lock task).
4882      *
4883      * When accessibility mode is on, only a long-press from recents
4884      * is required to exit.
4885      *
4886      * In all other circumstances we try to pass through long-press events
4887      * for Back, so that apps can still use it.  Which can be from two things.
4888      * 1) Not currently in screen pinning (lock task).
4889      * 2) Back is long-pressed without recents.
4890      */
handleLongPressBackRecents(View v)4891     private boolean handleLongPressBackRecents(View v) {
4892         try {
4893             boolean sendBackLongPress = false;
4894             IActivityManager activityManager = ActivityManagerNative.getDefault();
4895             boolean touchExplorationEnabled = mAccessibilityManager.isTouchExplorationEnabled();
4896             boolean inLockTaskMode = activityManager.isInLockTaskMode();
4897             if (inLockTaskMode && !touchExplorationEnabled) {
4898                 long time = System.currentTimeMillis();
4899                 // If we recently long-pressed the other button then they were
4900                 // long-pressed 'together'
4901                 if ((time - mLastLockToAppLongPress) < LOCK_TO_APP_GESTURE_TOLERENCE) {
4902                     activityManager.stopLockTaskMode();
4903                     // When exiting refresh disabled flags.
4904                     mNavigationBarView.setDisabledFlags(mDisabled1, true);
4905                     return true;
4906                 } else if ((v.getId() == R.id.back)
4907                         && !mNavigationBarView.getRecentsButton().getCurrentView().isPressed()) {
4908                     // If we aren't pressing recents right now then they presses
4909                     // won't be together, so send the standard long-press action.
4910                     sendBackLongPress = true;
4911                 }
4912                 mLastLockToAppLongPress = time;
4913             } else {
4914                 // If this is back still need to handle sending the long-press event.
4915                 if (v.getId() == R.id.back) {
4916                     sendBackLongPress = true;
4917                 } else if (touchExplorationEnabled && inLockTaskMode) {
4918                     // When in accessibility mode a long press that is recents (not back)
4919                     // should stop lock task.
4920                     activityManager.stopLockTaskMode();
4921                     // When exiting refresh disabled flags.
4922                     mNavigationBarView.setDisabledFlags(mDisabled1, true);
4923                     return true;
4924                 } else if (v.getId() == R.id.recent_apps) {
4925                     return handleLongPressRecents();
4926                 }
4927             }
4928             if (sendBackLongPress) {
4929                 KeyButtonView keyButtonView = (KeyButtonView) v;
4930                 keyButtonView.sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.FLAG_LONG_PRESS);
4931                 keyButtonView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
4932                 return true;
4933             }
4934         } catch (RemoteException e) {
4935             Log.d(TAG, "Unable to reach activity manager", e);
4936         }
4937         return false;
4938     }
4939 
handleLongPressRecents()4940     private boolean handleLongPressRecents() {
4941         if (mRecents == null || !ActivityManager.supportsMultiWindow()
4942                 || !getComponent(Divider.class).getView().getSnapAlgorithm()
4943                 .isSplitScreenFeasible()) {
4944             return false;
4945         }
4946 
4947         toggleSplitScreenMode(MetricsEvent.ACTION_WINDOW_DOCK_LONGPRESS,
4948                 MetricsEvent.ACTION_WINDOW_UNDOCK_LONGPRESS);
4949         return true;
4950     }
4951 
4952     @Override
showScreenPinningRequest(int taskId)4953     public void showScreenPinningRequest(int taskId) {
4954         if (mKeyguardMonitor.isShowing()) {
4955             // Don't allow apps to trigger this from keyguard.
4956             return;
4957         }
4958         // Show screen pinning request, since this comes from an app, show 'no thanks', button.
4959         showScreenPinningRequest(taskId, true);
4960     }
4961 
showScreenPinningRequest(int taskId, boolean allowCancel)4962     public void showScreenPinningRequest(int taskId, boolean allowCancel) {
4963         mScreenPinningRequest.showPrompt(taskId, allowCancel);
4964     }
4965 
hasActiveNotifications()4966     public boolean hasActiveNotifications() {
4967         return !mNotificationData.getActiveNotifications().isEmpty();
4968     }
4969 
wakeUpIfDozing(long time, MotionEvent event)4970     public void wakeUpIfDozing(long time, MotionEvent event) {
4971         if (mDozing && mDozeScrimController.isPulsing()) {
4972             PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
4973             pm.wakeUp(time, "com.android.systemui:NODOZE");
4974             mWakeUpComingFromTouch = true;
4975             mWakeUpTouchLocation = new PointF(event.getX(), event.getY());
4976             mNotificationPanel.setTouchDisabled(false);
4977             mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested();
4978             mFalsingManager.onScreenOnFromTouch();
4979         }
4980     }
4981 
4982     @Override
appTransitionPending()4983     public void appTransitionPending() {
4984 
4985         // Use own timings when Keyguard is going away, see keyguardGoingAway and
4986         // setKeyguardFadingAway
4987         if (!mKeyguardFadingAway) {
4988             mIconController.appTransitionPending();
4989         }
4990     }
4991 
4992     @Override
appTransitionCancelled()4993     public void appTransitionCancelled() {
4994         mIconController.appTransitionCancelled();
4995         EventBus.getDefault().send(new AppTransitionFinishedEvent());
4996     }
4997 
4998     @Override
appTransitionStarting(long startTime, long duration)4999     public void appTransitionStarting(long startTime, long duration) {
5000 
5001         // Use own timings when Keyguard is going away, see keyguardGoingAway and
5002         // setKeyguardFadingAway.
5003         if (!mKeyguardGoingAway) {
5004             mIconController.appTransitionStarting(startTime, duration);
5005         }
5006         if (mIconPolicy != null) {
5007             mIconPolicy.appTransitionStarting(startTime, duration);
5008         }
5009     }
5010 
5011     @Override
appTransitionFinished()5012     public void appTransitionFinished() {
5013         EventBus.getDefault().send(new AppTransitionFinishedEvent());
5014     }
5015 
5016     @Override
onCameraLaunchGestureDetected(int source)5017     public void onCameraLaunchGestureDetected(int source) {
5018         mLastCameraLaunchSource = source;
5019         if (mStartedGoingToSleep) {
5020             mLaunchCameraOnFinishedGoingToSleep = true;
5021             return;
5022         }
5023         if (!mNotificationPanel.canCameraGestureBeLaunched(
5024                 mStatusBarKeyguardViewManager.isShowing() && mExpandedVisible)) {
5025             return;
5026         }
5027         if (!mDeviceInteractive) {
5028             PowerManager pm = mContext.getSystemService(PowerManager.class);
5029             pm.wakeUp(SystemClock.uptimeMillis(), "com.android.systemui:CAMERA_GESTURE");
5030             mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested();
5031         }
5032         vibrateForCameraGesture();
5033         if (!mStatusBarKeyguardViewManager.isShowing()) {
5034             startActivity(KeyguardBottomAreaView.INSECURE_CAMERA_INTENT,
5035                     true /* dismissShade */);
5036         } else {
5037             if (!mDeviceInteractive) {
5038                 // Avoid flickering of the scrim when we instant launch the camera and the bouncer
5039                 // comes on.
5040                 mScrimController.dontAnimateBouncerChangesUntilNextFrame();
5041                 mGestureWakeLock.acquire(LAUNCH_TRANSITION_TIMEOUT_MS + 1000L);
5042             }
5043             if (mScreenTurningOn || mStatusBarKeyguardViewManager.isScreenTurnedOn()) {
5044                 mNotificationPanel.launchCamera(mDeviceInteractive /* animate */, source);
5045             } else {
5046                 // We need to defer the camera launch until the screen comes on, since otherwise
5047                 // we will dismiss us too early since we are waiting on an activity to be drawn and
5048                 // incorrectly get notified because of the screen on event (which resumes and pauses
5049                 // some activities)
5050                 mLaunchCameraOnScreenTurningOn = true;
5051             }
5052         }
5053     }
5054 
5055     @Override
showTvPictureInPictureMenu()5056     public void showTvPictureInPictureMenu() {
5057         // no-op.
5058     }
5059 
notifyFpAuthModeChanged()5060     public void notifyFpAuthModeChanged() {
5061         updateDozing();
5062     }
5063 
updateDozing()5064     private void updateDozing() {
5065         Trace.beginSection("PhoneStatusBar#updateDozing");
5066         // When in wake-and-unlock while pulsing, keep dozing state until fully unlocked.
5067         mDozing = mDozingRequested && mState == StatusBarState.KEYGUARD
5068                 || mFingerprintUnlockController.getMode()
5069                         == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING;
5070         updateDozingState();
5071         Trace.endSection();
5072     }
5073 
5074     private final class ShadeUpdates {
5075         private final ArraySet<String> mVisibleNotifications = new ArraySet<String>();
5076         private final ArraySet<String> mNewVisibleNotifications = new ArraySet<String>();
5077 
check()5078         public void check() {
5079             mNewVisibleNotifications.clear();
5080             ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
5081             for (int i = 0; i < activeNotifications.size(); i++) {
5082                 final Entry entry = activeNotifications.get(i);
5083                 final boolean visible = entry.row != null
5084                         && entry.row.getVisibility() == View.VISIBLE;
5085                 if (visible) {
5086                     mNewVisibleNotifications.add(entry.key + entry.notification.getPostTime());
5087                 }
5088             }
5089             final boolean updates = !mVisibleNotifications.containsAll(mNewVisibleNotifications);
5090             mVisibleNotifications.clear();
5091             mVisibleNotifications.addAll(mNewVisibleNotifications);
5092 
5093             // We have new notifications
5094             if (updates && mDozeServiceHost != null) {
5095                 mDozeServiceHost.fireNewNotifications();
5096             }
5097         }
5098     }
5099 
5100     private final class DozeServiceHost implements DozeHost {
5101         // Amount of time to allow to update the time shown on the screen before releasing
5102         // the wakelock.  This timeout is design to compensate for the fact that we don't
5103         // currently have a way to know when time display contents have actually been
5104         // refreshed once we've finished rendering a new frame.
5105         private static final long PROCESSING_TIME = 500;
5106 
5107         private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
5108         private final H mHandler = new H();
5109 
5110         // Keeps the last reported state by fireNotificationLight.
5111         private boolean mNotificationLightOn;
5112 
5113         @Override
toString()5114         public String toString() {
5115             return "PSB.DozeServiceHost[mCallbacks=" + mCallbacks.size() + "]";
5116         }
5117 
firePowerSaveChanged(boolean active)5118         public void firePowerSaveChanged(boolean active) {
5119             for (Callback callback : mCallbacks) {
5120                 callback.onPowerSaveChanged(active);
5121             }
5122         }
5123 
fireBuzzBeepBlinked()5124         public void fireBuzzBeepBlinked() {
5125             for (Callback callback : mCallbacks) {
5126                 callback.onBuzzBeepBlinked();
5127             }
5128         }
5129 
fireNotificationLight(boolean on)5130         public void fireNotificationLight(boolean on) {
5131             mNotificationLightOn = on;
5132             for (Callback callback : mCallbacks) {
5133                 callback.onNotificationLight(on);
5134             }
5135         }
5136 
fireNewNotifications()5137         public void fireNewNotifications() {
5138             for (Callback callback : mCallbacks) {
5139                 callback.onNewNotifications();
5140             }
5141         }
5142 
5143         @Override
addCallback(@onNull Callback callback)5144         public void addCallback(@NonNull Callback callback) {
5145             mCallbacks.add(callback);
5146         }
5147 
5148         @Override
removeCallback(@onNull Callback callback)5149         public void removeCallback(@NonNull Callback callback) {
5150             mCallbacks.remove(callback);
5151         }
5152 
5153         @Override
startDozing(@onNull Runnable ready)5154         public void startDozing(@NonNull Runnable ready) {
5155             mHandler.obtainMessage(H.MSG_START_DOZING, ready).sendToTarget();
5156         }
5157 
5158         @Override
pulseWhileDozing(@onNull PulseCallback callback, int reason)5159         public void pulseWhileDozing(@NonNull PulseCallback callback, int reason) {
5160             mHandler.obtainMessage(H.MSG_PULSE_WHILE_DOZING, reason, 0, callback).sendToTarget();
5161         }
5162 
5163         @Override
stopDozing()5164         public void stopDozing() {
5165             mHandler.obtainMessage(H.MSG_STOP_DOZING).sendToTarget();
5166         }
5167 
5168         @Override
isPowerSaveActive()5169         public boolean isPowerSaveActive() {
5170             return mBatteryController != null && mBatteryController.isPowerSave();
5171         }
5172 
5173         @Override
isPulsingBlocked()5174         public boolean isPulsingBlocked() {
5175             return mFingerprintUnlockController.getMode()
5176                     == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK;
5177         }
5178 
5179         @Override
isNotificationLightOn()5180         public boolean isNotificationLightOn() {
5181             return mNotificationLightOn;
5182         }
5183 
handleStartDozing(@onNull Runnable ready)5184         private void handleStartDozing(@NonNull Runnable ready) {
5185             if (!mDozingRequested) {
5186                 mDozingRequested = true;
5187                 DozeLog.traceDozing(mContext, mDozing);
5188                 updateDozing();
5189             }
5190             ready.run();
5191         }
5192 
handlePulseWhileDozing(@onNull PulseCallback callback, int reason)5193         private void handlePulseWhileDozing(@NonNull PulseCallback callback, int reason) {
5194             mDozeScrimController.pulse(new PulseCallback() {
5195 
5196                 @Override
5197                 public void onPulseStarted() {
5198                     callback.onPulseStarted();
5199                     mStackScroller.setPulsing(true);
5200                 }
5201 
5202                 @Override
5203                 public void onPulseFinished() {
5204                     callback.onPulseFinished();
5205                     mStackScroller.setPulsing(false);
5206                 }
5207             }, reason);
5208         }
5209 
handleStopDozing()5210         private void handleStopDozing() {
5211             if (mDozingRequested) {
5212                 mDozingRequested = false;
5213                 DozeLog.traceDozing(mContext, mDozing);
5214                 updateDozing();
5215             }
5216         }
5217 
5218         private final class H extends Handler {
5219             private static final int MSG_START_DOZING = 1;
5220             private static final int MSG_PULSE_WHILE_DOZING = 2;
5221             private static final int MSG_STOP_DOZING = 3;
5222 
5223             @Override
handleMessage(Message msg)5224             public void handleMessage(Message msg) {
5225                 switch (msg.what) {
5226                     case MSG_START_DOZING:
5227                         handleStartDozing((Runnable) msg.obj);
5228                         break;
5229                     case MSG_PULSE_WHILE_DOZING:
5230                         handlePulseWhileDozing((PulseCallback) msg.obj, msg.arg1);
5231                         break;
5232                     case MSG_STOP_DOZING:
5233                         handleStopDozing();
5234                         break;
5235                 }
5236             }
5237         }
5238     }
5239 }
5240