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