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