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