OSDN Git Service

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