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