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