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