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