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