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