PhoneStatusBar.java revision ecc798e6668046c2f67cf30c6ab1db2eba80cab1
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.systemui.statusbar.phone;
18
19
20import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT;
21import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN;
22import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
23import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
24import static android.app.StatusBarManager.windowStateToString;
25import static com.android.keyguard.KeyguardHostView.OnDismissAction;
26import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
27import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
28import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
29import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSLUCENT;
30import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
31
32import android.animation.Animator;
33import android.animation.AnimatorListenerAdapter;
34import android.animation.TimeInterpolator;
35import android.animation.ValueAnimator;
36import android.app.ActivityManager;
37import android.app.ActivityManagerNative;
38import android.app.Notification;
39import android.app.PendingIntent;
40import android.app.StatusBarManager;
41import android.content.BroadcastReceiver;
42import android.content.Context;
43import android.content.Intent;
44import android.content.IntentFilter;
45import android.content.res.Configuration;
46import android.content.res.Resources;
47import android.database.ContentObserver;
48import android.graphics.Canvas;
49import android.graphics.ColorFilter;
50import android.graphics.PixelFormat;
51import android.graphics.Point;
52import android.graphics.PorterDuff;
53import android.graphics.Rect;
54import android.graphics.drawable.Drawable;
55import android.inputmethodservice.InputMethodService;
56import android.media.AudioManager;
57import android.os.Bundle;
58import android.os.Handler;
59import android.os.IBinder;
60import android.os.Message;
61import android.os.PowerManager;
62import android.os.RemoteException;
63import android.os.SystemClock;
64import android.os.UserHandle;
65import android.provider.Settings;
66import android.provider.Settings.Global;
67import android.service.notification.StatusBarNotification;
68import android.util.ArraySet;
69import android.util.DisplayMetrics;
70import android.util.EventLog;
71import android.util.Log;
72import android.view.Display;
73import android.view.Gravity;
74import android.view.KeyEvent;
75import android.view.LayoutInflater;
76import android.view.MotionEvent;
77import android.view.VelocityTracker;
78import android.view.View;
79import android.view.ViewGroup;
80import android.view.ViewGroup.LayoutParams;
81import android.view.ViewPropertyAnimator;
82import android.view.ViewTreeObserver;
83import android.view.WindowManager;
84import android.view.animation.AccelerateInterpolator;
85import android.view.animation.Animation;
86import android.view.animation.AnimationUtils;
87import android.view.animation.DecelerateInterpolator;
88import android.widget.FrameLayout;
89import android.widget.ImageView;
90import android.widget.LinearLayout;
91import android.widget.TextView;
92
93import com.android.internal.statusbar.StatusBarIcon;
94import com.android.keyguard.ViewMediatorCallback;
95import com.android.systemui.DemoMode;
96import com.android.systemui.EventLogTags;
97import com.android.systemui.R;
98import com.android.systemui.keyguard.KeyguardViewMediator;
99import com.android.systemui.qs.CircularClipper;
100import com.android.systemui.qs.QSPanel;
101import com.android.systemui.qs.QSTile;
102import com.android.systemui.statusbar.BaseStatusBar;
103import com.android.systemui.statusbar.CommandQueue;
104import com.android.systemui.statusbar.DragDownHelper;
105import com.android.systemui.statusbar.ExpandableNotificationRow;
106import com.android.systemui.statusbar.GestureRecorder;
107import com.android.systemui.statusbar.InterceptedNotifications;
108import com.android.systemui.statusbar.NotificationData;
109import com.android.systemui.statusbar.NotificationData.Entry;
110import com.android.systemui.statusbar.NotificationOverflowContainer;
111import com.android.systemui.statusbar.SignalClusterView;
112import com.android.systemui.statusbar.SpeedBumpView;
113import com.android.systemui.statusbar.StatusBarIconView;
114import com.android.systemui.statusbar.StatusBarState;
115import com.android.systemui.statusbar.policy.BatteryController;
116import com.android.systemui.statusbar.policy.BluetoothControllerImpl;
117import com.android.systemui.statusbar.policy.CastControllerImpl;
118import com.android.systemui.statusbar.policy.DateView;
119import com.android.systemui.statusbar.policy.HeadsUpNotificationView;
120import com.android.systemui.statusbar.policy.UserInfoController;
121import com.android.systemui.statusbar.policy.LocationControllerImpl;
122import com.android.systemui.statusbar.policy.NetworkControllerImpl;
123import com.android.systemui.statusbar.policy.RotationLockControllerImpl;
124import com.android.systemui.statusbar.policy.ZenModeControllerImpl;
125import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
126import com.android.systemui.statusbar.stack.NotificationStackScrollLayout.OnChildLocationsChangedListener;
127import com.android.systemui.statusbar.stack.StackScrollState.ViewState;
128
129import java.io.FileDescriptor;
130import java.io.PrintWriter;
131import java.util.ArrayList;
132import java.util.Collection;
133import java.util.Collections;
134
135public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
136        DragDownHelper.OnDragDownListener, ActivityStarter {
137    static final String TAG = "PhoneStatusBar";
138    public static final boolean DEBUG = BaseStatusBar.DEBUG;
139    public static final boolean SPEW = false;
140    public static final boolean DUMPTRUCK = true; // extra dumpsys info
141    public static final boolean DEBUG_GESTURES = false;
142
143    public static final boolean DEBUG_WINDOW_STATE = false;
144
145    public static final boolean SETTINGS_DRAG_SHORTCUT = true;
146
147    // additional instrumentation for testing purposes; intended to be left on during development
148    public static final boolean CHATTY = DEBUG;
149
150    public static final String ACTION_STATUSBAR_START
151            = "com.android.internal.policy.statusbar.START";
152
153    private static final int MSG_OPEN_NOTIFICATION_PANEL = 1000;
154    private static final int MSG_CLOSE_PANELS = 1001;
155    private static final int MSG_OPEN_SETTINGS_PANEL = 1002;
156    // 1020-1030 reserved for BaseStatusBar
157
158    private static final boolean CLOSE_PANEL_WHEN_EMPTIED = true;
159
160    private static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10; // see NotificationManagerService
161    private static final int HIDE_ICONS_BELOW_SCORE = Notification.PRIORITY_LOW * NOTIFICATION_PRIORITY_MULTIPLIER;
162
163    /**
164     * Default value of {@link android.provider.Settings.Global#LOCK_SCREEN_SHOW_NOTIFICATIONS}.
165     */
166    private static final boolean ALLOW_NOTIFICATIONS_DEFAULT = false;
167
168    private static final int STATUS_OR_NAV_TRANSIENT =
169            View.STATUS_BAR_TRANSIENT | View.NAVIGATION_BAR_TRANSIENT;
170    private static final long AUTOHIDE_TIMEOUT_MS = 3000;
171
172    /** The minimum delay in ms between reports of notification visibility. */
173    private static final int VISIBILITY_REPORT_MIN_DELAY_MS = 500;
174
175    // fling gesture tuning parameters, scaled to display density
176    private float mSelfExpandVelocityPx; // classic value: 2000px/s
177    private float mSelfCollapseVelocityPx; // classic value: 2000px/s (will be negated to collapse "up")
178    private float mFlingExpandMinVelocityPx; // classic value: 200px/s
179    private float mFlingCollapseMinVelocityPx; // classic value: 200px/s
180    private float mCollapseMinDisplayFraction; // classic value: 0.08 (25px/min(320px,480px) on G1)
181    private float mExpandMinDisplayFraction; // classic value: 0.5 (drag open halfway to expand)
182    private float mFlingGestureMaxXVelocityPx; // classic value: 150px/s
183
184    private float mExpandAccelPx; // classic value: 2000px/s/s
185    private float mCollapseAccelPx; // classic value: 2000px/s/s (will be negated to collapse "up")
186
187    private float mFlingGestureMaxOutputVelocityPx; // how fast can it really go? (should be a little
188                                                    // faster than mSelfCollapseVelocityPx)
189
190    PhoneStatusBarPolicy mIconPolicy;
191
192    // These are no longer handled by the policy, because we need custom strategies for them
193    BluetoothControllerImpl mBluetoothController;
194    BatteryController mBatteryController;
195    LocationControllerImpl mLocationController;
196    NetworkControllerImpl mNetworkController;
197    RotationLockControllerImpl mRotationLockController;
198    UserInfoController mUserInfoController;
199    ZenModeControllerImpl mZenModeController;
200    CastControllerImpl mCastController;
201
202    int mNaturalBarHeight = -1;
203    int mIconSize = -1;
204    int mIconHPadding = -1;
205    Display mDisplay;
206    Point mCurrentDisplaySize = new Point();
207
208    StatusBarWindowView mStatusBarWindow;
209    PhoneStatusBarView mStatusBarView;
210    private int mStatusBarWindowState = WINDOW_STATE_SHOWING;
211    private StatusBarWindowManager mStatusBarWindowManager;
212
213    int mPixelFormat;
214    Object mQueueLock = new Object();
215
216    // viewgroup containing the normal contents of the statusbar
217    LinearLayout mStatusBarContents;
218
219    // right-hand icons
220    LinearLayout mSystemIconArea;
221    LinearLayout mSystemIcons;
222
223    // left-hand icons
224    LinearLayout mStatusIcons;
225    // the icons themselves
226    IconMerger mNotificationIcons;
227    // [+>
228    View mMoreIcon;
229
230    // expanded notifications
231    NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
232    View mExpandedContents;
233    int mNotificationPanelGravity;
234    int mNotificationPanelMarginBottomPx;
235    float mNotificationPanelMinHeightFrac;
236    TextView mNotificationPanelDebugText;
237
238    // settings
239    View mFlipSettingsView;
240    private QSPanel mQSPanel;
241
242    // top bar
243    StatusBarHeaderView mHeader;
244    View mKeyguardStatusView;
245    KeyguardBottomAreaView mKeyguardBottomArea;
246    boolean mLeaveOpenOnKeyguardHide;
247    KeyguardIndicationTextView mKeyguardIndicationTextView;
248
249    // TODO: Fetch phrase from search/hotword provider.
250    String mKeyguardHotwordPhrase = "";
251    int mKeyguardMaxNotificationCount;
252    View mDateTimeView;
253
254    // carrier/wifi label
255    private TextView mCarrierLabel;
256    private boolean mCarrierLabelVisible = false;
257    private int mCarrierLabelHeight;
258    private TextView mEmergencyCallLabel;
259    private int mStatusBarHeaderHeight;
260
261    private boolean mShowCarrierInPanel = false;
262
263    // position
264    int[] mPositionTmp = new int[2];
265    boolean mExpandedVisible;
266
267    // the date view
268    DateView mDateView;
269
270    // for heads up notifications
271    private HeadsUpNotificationView mHeadsUpNotificationView;
272    private int mHeadsUpNotificationDecay;
273
274    // on-screen navigation buttons
275    private NavigationBarView mNavigationBarView = null;
276    private int mNavigationBarWindowState = WINDOW_STATE_SHOWING;
277
278    // the tracker view
279    int mTrackingPosition; // the position of the top of the tracking view.
280
281    // ticker
282    private Ticker mTicker;
283    private View mTickerView;
284    private boolean mTicking;
285
286    // Tracking finger for opening/closing.
287    int mEdgeBorder; // corresponds to R.dimen.status_bar_edge_ignore
288    boolean mTracking;
289    VelocityTracker mVelocityTracker;
290
291    int[] mAbsPos = new int[2];
292    Runnable mPostCollapseCleanup = null;
293
294    // for disabling the status bar
295    int mDisabled = 0;
296
297    // tracking calls to View.setSystemUiVisibility()
298    int mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE;
299
300    DisplayMetrics mDisplayMetrics = new DisplayMetrics();
301
302    // XXX: gesture research
303    private final GestureRecorder mGestureRec = DEBUG_GESTURES
304        ? new GestureRecorder("/sdcard/statusbar_gestures.dat")
305        : null;
306
307    private int mNavigationIconHints = 0;
308    private final Animator.AnimatorListener mMakeIconsInvisible = new AnimatorListenerAdapter() {
309        @Override
310        public void onAnimationEnd(Animator animation) {
311            // double-check to avoid races
312            if (mStatusBarContents.getAlpha() == 0) {
313                if (DEBUG) Log.d(TAG, "makeIconsInvisible");
314                mStatusBarContents.setVisibility(View.INVISIBLE);
315            }
316        }
317    };
318
319    // ensure quick settings is disabled until the current user makes it through the setup wizard
320    private boolean mUserSetup = false;
321    private ContentObserver mUserSetupObserver = new ContentObserver(new Handler()) {
322        @Override
323        public void onChange(boolean selfChange) {
324            final boolean userSetup = 0 != Settings.Secure.getIntForUser(
325                    mContext.getContentResolver(),
326                    Settings.Secure.USER_SETUP_COMPLETE,
327                    0 /*default */,
328                    mCurrentUserId);
329            if (MULTIUSER_DEBUG) Log.d(TAG, String.format("User setup changed: " +
330                    "selfChange=%s userSetup=%s mUserSetup=%s",
331                    selfChange, userSetup, mUserSetup));
332
333            if (userSetup != mUserSetup) {
334                mUserSetup = userSetup;
335                if (mNotificationPanel != null) {
336                    mNotificationPanel.setQsExpansionEnabled(isDeviceProvisioned() && userSetup);
337                }
338                if (!mUserSetup && mStatusBarView != null)
339                    animateCollapseQuickSettings();
340            }
341        }
342    };
343
344    final private ContentObserver mHeadsUpObserver = new ContentObserver(mHandler) {
345        @Override
346        public void onChange(boolean selfChange) {
347            boolean wasUsing = mUseHeadsUp;
348            mUseHeadsUp = ENABLE_HEADS_UP && Settings.Global.HEADS_UP_OFF != Settings.Global.getInt(
349                    mContext.getContentResolver(), Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED,
350                    Settings.Global.HEADS_UP_OFF);
351            mHeadsUpTicker = mUseHeadsUp && 0 != Settings.Global.getInt(
352                    mContext.getContentResolver(), SETTING_HEADS_UP_TICKER, 0);
353            Log.d(TAG, "heads up is " + (mUseHeadsUp ? "enabled" : "disabled"));
354            if (wasUsing != mUseHeadsUp) {
355                if (!mUseHeadsUp) {
356                    Log.d(TAG, "dismissing any existing heads up notification on disable event");
357                    setHeadsUpVisibility(false);
358                    mHeadsUpNotificationView.setNotification(null);
359                    removeHeadsUpView();
360                } else {
361                    addHeadsUpView();
362                }
363            }
364        }
365    };
366
367    private int mInteractingWindows;
368    private boolean mAutohideSuspended;
369    private int mStatusBarMode;
370    private int mNavigationBarMode;
371    private Boolean mScreenOn;
372
373    private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
374    private ViewMediatorCallback mKeyguardViewMediatorCallback;
375    private ScrimController mScrimController;
376
377    private final Runnable mAutohide = new Runnable() {
378        @Override
379        public void run() {
380            int requested = mSystemUiVisibility & ~STATUS_OR_NAV_TRANSIENT;
381            if (mSystemUiVisibility != requested) {
382                notifyUiVisibilityChanged(requested);
383            }
384        }};
385
386    private Runnable mOnFlipRunnable;
387    private InterceptedNotifications mIntercepted;
388    private VelocityTracker mSettingsTracker;
389    private float mSettingsDownY;
390    private boolean mSettingsStarted;
391    private boolean mSettingsCancelled;
392    private boolean mSettingsClosing;
393    private boolean mVisible;
394
395    private final OnChildLocationsChangedListener mOnChildLocationsChangedListener =
396            new OnChildLocationsChangedListener() {
397        @Override
398        public void onChildLocationsChanged(NotificationStackScrollLayout stackScrollLayout) {
399            userActivity();
400        }
401    };
402
403    public void setOnFlipRunnable(Runnable onFlipRunnable) {
404        mOnFlipRunnable = onFlipRunnable;
405    }
406
407    /** Keys of notifications currently visible to the user. */
408    private final ArraySet<String> mCurrentlyVisibleNotifications = new ArraySet<String>();
409    private long mLastVisibilityReportUptimeMs;
410
411    private static final int VISIBLE_LOCATIONS = ViewState.LOCATION_FIRST_CARD
412            | ViewState.LOCATION_TOP_STACK_PEEKING
413            | ViewState.LOCATION_MAIN_AREA
414            | ViewState.LOCATION_BOTTOM_STACK_PEEKING;
415
416    private final OnChildLocationsChangedListener mNotificationLocationsChangedListener =
417            new OnChildLocationsChangedListener() {
418                @Override
419                public void onChildLocationsChanged(
420                        NotificationStackScrollLayout stackScrollLayout) {
421                    if (mHandler.hasCallbacks(mVisibilityReporter)) {
422                        // Visibilities will be reported when the existing
423                        // callback is executed.
424                        return;
425                    }
426                    // Calculate when we're allowed to run the visibility
427                    // reporter. Note that this timestamp might already have
428                    // passed. That's OK, the callback will just be executed
429                    // ASAP.
430                    long nextReportUptimeMs =
431                            mLastVisibilityReportUptimeMs + VISIBILITY_REPORT_MIN_DELAY_MS;
432                    mHandler.postAtTime(mVisibilityReporter, nextReportUptimeMs);
433                }
434            };
435
436    // Tracks notifications currently visible in mNotificationStackScroller and
437    // emits visibility events via NoMan on changes.
438    private final Runnable mVisibilityReporter = new Runnable() {
439        private final ArrayList<String> mTmpNewlyVisibleNotifications = new ArrayList<String>();
440        private final ArrayList<String> mTmpCurrentlyVisibleNotifications = new ArrayList<String>();
441
442        @Override
443        public void run() {
444            mLastVisibilityReportUptimeMs = SystemClock.uptimeMillis();
445
446            // 1. Loop over mNotificationData entries:
447            //   A. Keep list of visible notifications.
448            //   B. Keep list of previously hidden, now visible notifications.
449            // 2. Compute no-longer visible notifications by removing currently
450            //    visible notifications from the set of previously visible
451            //    notifications.
452            // 3. Report newly visible and no-longer visible notifications.
453            // 4. Keep currently visible notifications for next report.
454            int N = mNotificationData.size();
455            for (int i = 0; i < N; i++) {
456                Entry entry = mNotificationData.get(i);
457                String key = entry.notification.getKey();
458                boolean previouslyVisible = mCurrentlyVisibleNotifications.contains(key);
459                boolean currentlyVisible =
460                        (mStackScroller.getChildLocation(entry.row) & VISIBLE_LOCATIONS) != 0;
461                if (currentlyVisible) {
462                    // Build new set of visible notifications.
463                    mTmpCurrentlyVisibleNotifications.add(key);
464                }
465                if (!previouslyVisible && currentlyVisible) {
466                    mTmpNewlyVisibleNotifications.add(key);
467                }
468            }
469            ArraySet<String> noLongerVisibleNotifications = mCurrentlyVisibleNotifications;
470            noLongerVisibleNotifications.removeAll(mTmpCurrentlyVisibleNotifications);
471
472            logNotificationVisibilityChanges(
473                    mTmpNewlyVisibleNotifications, noLongerVisibleNotifications);
474
475            mCurrentlyVisibleNotifications.clear();
476            mCurrentlyVisibleNotifications.addAll(mTmpCurrentlyVisibleNotifications);
477
478            mTmpNewlyVisibleNotifications.clear();
479            mTmpCurrentlyVisibleNotifications.clear();
480        }
481    };
482
483    private final View.OnClickListener mOverflowClickListener = new View.OnClickListener() {
484        @Override
485        public void onClick(View v) {
486            goToLockedShade(null);
487        }
488    };
489
490    @Override
491    public void setZenMode(int mode) {
492        super.setZenMode(mode);
493        if (!isDeviceProvisioned()) return;
494        final boolean zen = mode != Settings.Global.ZEN_MODE_OFF;
495        if (!zen) {
496            mIntercepted.releaseIntercepted();
497        }
498        if (mIconPolicy != null) {
499            mIconPolicy.setZenMode(zen);
500        }
501    }
502
503    @Override
504    public void start() {
505        mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
506                .getDefaultDisplay();
507        updateDisplaySize();
508        mIntercepted = new InterceptedNotifications(mContext, this);
509        super.start(); // calls createAndAddWindows()
510
511        addNavigationBar();
512
513        // Lastly, call to the icon policy to install/update all the icons.
514        mIconPolicy = new PhoneStatusBarPolicy(mContext);
515        mSettingsObserver.onChange(false); // set up
516
517        mHeadsUpObserver.onChange(true); // set up
518        if (ENABLE_HEADS_UP) {
519            mContext.getContentResolver().registerContentObserver(
520                    Settings.Global.getUriFor(Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED), true,
521                    mHeadsUpObserver);
522            mContext.getContentResolver().registerContentObserver(
523                    Settings.Global.getUriFor(SETTING_HEADS_UP_TICKER), true,
524                    mHeadsUpObserver);
525        }
526        startKeyguard();
527    }
528
529    // ================================================================================
530    // Constructing the view
531    // ================================================================================
532    protected PhoneStatusBarView makeStatusBarView() {
533        final Context context = mContext;
534
535        Resources res = context.getResources();
536
537        updateDisplaySize(); // populates mDisplayMetrics
538        loadDimens();
539
540        mIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size);
541
542        mStatusBarWindow = (StatusBarWindowView) View.inflate(context,
543                R.layout.super_status_bar, null);
544        mStatusBarWindow.mService = this;
545        mStatusBarWindow.setOnTouchListener(new View.OnTouchListener() {
546            @Override
547            public boolean onTouch(View v, MotionEvent event) {
548                checkUserAutohide(v, event);
549                if (event.getAction() == MotionEvent.ACTION_DOWN) {
550                    if (mExpandedVisible) {
551                        animateCollapsePanels();
552                    }
553                }
554                return mStatusBarWindow.onTouchEvent(event);
555            }});
556
557        mStatusBarView = (PhoneStatusBarView) mStatusBarWindow.findViewById(R.id.status_bar);
558        mStatusBarView.setBar(this);
559
560        PanelHolder holder = (PanelHolder) mStatusBarWindow.findViewById(R.id.panel_holder);
561        mStatusBarView.setPanelHolder(holder);
562
563        mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById(
564                R.id.notification_panel);
565        mNotificationPanel.setStatusBar(this);
566
567        // make the header non-responsive to clicks
568        mNotificationPanel.findViewById(R.id.header).setOnTouchListener(
569                new View.OnTouchListener() {
570                    @Override
571                    public boolean onTouch(View v, MotionEvent event) {
572                        return true; // e eats everything
573                    }
574                });
575
576        if (!ActivityManager.isHighEndGfx()) {
577            mStatusBarWindow.setBackground(null);
578            mNotificationPanel.setBackground(new FastColorDrawable(context.getResources().getColor(
579                    R.color.notification_panel_solid_background)));
580        }
581        if (ENABLE_HEADS_UP) {
582            mHeadsUpNotificationView =
583                    (HeadsUpNotificationView) View.inflate(context, R.layout.heads_up, null);
584            mHeadsUpNotificationView.setVisibility(View.GONE);
585            mHeadsUpNotificationView.setBar(this);
586        }
587        if (MULTIUSER_DEBUG) {
588            mNotificationPanelDebugText = (TextView) mNotificationPanel.findViewById(
589                    R.id.header_debug_info);
590            mNotificationPanelDebugText.setVisibility(View.VISIBLE);
591        }
592
593        updateShowSearchHoldoff();
594
595        try {
596            boolean showNav = mWindowManagerService.hasNavigationBar();
597            if (DEBUG) Log.v(TAG, "hasNavigationBar=" + showNav);
598            if (showNav) {
599                mNavigationBarView =
600                    (NavigationBarView) View.inflate(context, R.layout.navigation_bar, null);
601
602                mNavigationBarView.setDisabledFlags(mDisabled);
603                mNavigationBarView.setBar(this);
604                mNavigationBarView.setOnTouchListener(new View.OnTouchListener() {
605                    @Override
606                    public boolean onTouch(View v, MotionEvent event) {
607                        checkUserAutohide(v, event);
608                        return false;
609                    }});
610            }
611        } catch (RemoteException ex) {
612            // no window manager? good luck with that
613        }
614
615        // figure out which pixel-format to use for the status bar.
616        mPixelFormat = PixelFormat.OPAQUE;
617
618        mSystemIconArea = (LinearLayout) mStatusBarView.findViewById(R.id.system_icon_area);
619        mSystemIcons = (LinearLayout) mStatusBarView.findViewById(R.id.system_icons);
620        mStatusIcons = (LinearLayout)mStatusBarView.findViewById(R.id.statusIcons);
621        mNotificationIcons = (IconMerger)mStatusBarView.findViewById(R.id.notificationIcons);
622        mMoreIcon = mStatusBarView.findViewById(R.id.moreIcon);
623        mNotificationIcons.setOverflowIndicator(mMoreIcon);
624        mStatusBarContents = (LinearLayout)mStatusBarView.findViewById(R.id.status_bar_contents);
625        mTickerView = mStatusBarView.findViewById(R.id.ticker);
626
627        mStackScroller = (NotificationStackScrollLayout) mStatusBarWindow.findViewById(
628                R.id.notification_stack_scroller);
629        mStackScroller.setLongPressListener(getNotificationLongClicker());
630        mStackScroller.setChildLocationsChangedListener(mOnChildLocationsChangedListener);
631
632        mKeyguardIconOverflowContainer =
633                (NotificationOverflowContainer) LayoutInflater.from(mContext).inflate(
634                        R.layout.status_bar_notification_keyguard_overflow, mStackScroller, false);
635        mKeyguardIconOverflowContainer.setOnActivatedListener(this);
636        mKeyguardIconOverflowContainer.setOnClickListener(mOverflowClickListener);
637        mStackScroller.addView(mKeyguardIconOverflowContainer);
638
639        SpeedBumpView speedBump = (SpeedBumpView) LayoutInflater.from(mContext).inflate(
640                        R.layout.status_bar_notification_speed_bump, mStackScroller, false);
641        mStackScroller.setSpeedBumpView(speedBump);
642        mExpandedContents = mStackScroller;
643
644        mScrimController = new ScrimController(mStatusBarWindow.findViewById(R.id.scrim_behind),
645                mStatusBarWindow.findViewById(R.id.scrim_in_front));
646        mStatusBarView.setScrimController(mScrimController);
647
648        mHeader = (StatusBarHeaderView) mStatusBarWindow.findViewById(R.id.header);
649        mHeader.setActivityStarter(this);
650        mKeyguardStatusView = mStatusBarWindow.findViewById(R.id.keyguard_status_view);
651        mKeyguardBottomArea =
652                (KeyguardBottomAreaView) mStatusBarWindow.findViewById(R.id.keyguard_bottom_area);
653        mKeyguardBottomArea.setActivityStarter(this);
654        mKeyguardIndicationTextView = (KeyguardIndicationTextView) mStatusBarWindow.findViewById(
655                R.id.keyguard_indication_text);
656        mDateView = (DateView)mStatusBarWindow.findViewById(R.id.date);
657
658        mDateTimeView = mHeader.findViewById(R.id.datetime);
659        if (mDateTimeView != null) {
660            mDateTimeView.setOnClickListener(mClockClickListener);
661            mDateTimeView.setEnabled(true);
662        }
663
664        mNotificationPanel.setSystemUiVisibility(
665                View.STATUS_BAR_DISABLE_NOTIFICATION_ICONS |
666                View.STATUS_BAR_DISABLE_CLOCK);
667
668        mTicker = new MyTicker(context, mStatusBarView);
669
670        TickerView tickerView = (TickerView)mStatusBarView.findViewById(R.id.tickerText);
671        tickerView.mTicker = mTicker;
672
673        mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore);
674
675        // set the inital view visibility
676        setAreThereNotifications();
677
678        // Other icons
679        mLocationController = new LocationControllerImpl(mContext); // will post a notification
680        mBatteryController = new BatteryController(mContext);
681        mNetworkController = new NetworkControllerImpl(mContext);
682        mBluetoothController = new BluetoothControllerImpl(mContext);
683        if (mContext.getResources().getBoolean(R.bool.config_showRotationLock)) {
684            mRotationLockController = new RotationLockControllerImpl(mContext);
685        }
686        mUserInfoController = new UserInfoController(mContext);
687        mZenModeController = new ZenModeControllerImpl(mContext, mHandler);
688        mCastController = new CastControllerImpl(mContext);
689        final SignalClusterView signalCluster =
690                (SignalClusterView)mStatusBarView.findViewById(R.id.signal_cluster);
691
692
693        mNetworkController.addSignalCluster(signalCluster);
694        signalCluster.setNetworkController(mNetworkController);
695
696        final boolean isAPhone = mNetworkController.hasVoiceCallingFeature();
697        if (isAPhone) {
698            mEmergencyCallLabel =
699                    (TextView) mStatusBarWindow.findViewById(R.id.emergency_calls_only);
700            // TODO: Uncomment when correctly positioned
701//            if (mEmergencyCallLabel != null) {
702//                mNetworkController.addEmergencyLabelView(mEmergencyCallLabel);
703//                mEmergencyCallLabel.setOnClickListener(new View.OnClickListener() {
704//                    public void onClick(View v) { }});
705//                mEmergencyCallLabel.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
706//                    @Override
707//                    public void onLayoutChange(View v, int left, int top, int right, int bottom,
708//                            int oldLeft, int oldTop, int oldRight, int oldBottom) {
709//                        updateCarrierLabelVisibility(false);
710//                    }});
711//            }
712        }
713
714        mCarrierLabel = (TextView)mStatusBarWindow.findViewById(R.id.carrier_label);
715        mShowCarrierInPanel = (mCarrierLabel != null);
716        if (DEBUG) Log.v(TAG, "carrierlabel=" + mCarrierLabel + " show=" + mShowCarrierInPanel);
717        if (mShowCarrierInPanel) {
718            mCarrierLabel.setVisibility(mCarrierLabelVisible ? View.VISIBLE : View.INVISIBLE);
719
720            // for mobile devices, we always show mobile connection info here (SPN/PLMN)
721            // for other devices, we show whatever network is connected
722            if (mNetworkController.hasMobileDataFeature()) {
723                mNetworkController.addMobileLabelView(mCarrierLabel);
724            } else {
725                mNetworkController.addCombinedLabelView(mCarrierLabel);
726            }
727
728            // set up the dynamic hide/show of the label
729            // TODO: uncomment, handle this for the Stack scroller aswell
730//                ((NotificationRowLayout) mStackScroller)
731// .setOnSizeChangedListener(new OnSizeChangedListener() {
732//                @Override
733//                public void onSizeChanged(View view, int w, int h, int oldw, int oldh) {
734//                    updateCarrierLabelVisibility(false);
735        }
736
737        // Set up the quick settings tile panel
738        mQSPanel = (QSPanel) mStatusBarWindow.findViewById(R.id.quick_settings_panel);
739        if (mQSPanel != null) {
740            mQSPanel.setUtils(new CircularClipper.Utils() {
741                @Override
742                public ValueAnimator createRevealAnimator(View v, int centerX, int centerY,
743                        float startRadius, float endRadius) {
744                    return v.createRevealAnimator(centerX, centerY, startRadius, endRadius);
745                }
746            });
747            final QSTileHost qsh = new QSTileHost(mContext, this,
748                    mBluetoothController, mLocationController, mRotationLockController,
749                    mNetworkController, mZenModeController, null /*tethering*/,
750                    mCastController);
751            for (QSTile<?> tile : qsh.getTiles()) {
752                mQSPanel.addTile(tile);
753            }
754            mHeader.setQSPanel(mQSPanel);
755        }
756
757        // User info. Trigger first load.
758        mHeader.setUserInfoController(mUserInfoController);
759        mUserInfoController.reloadUserInfo();
760
761        PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
762        mBroadcastReceiver.onReceive(mContext,
763                new Intent(pm.isScreenOn() ? Intent.ACTION_SCREEN_ON : Intent.ACTION_SCREEN_OFF));
764
765        // receive broadcasts
766        IntentFilter filter = new IntentFilter();
767        filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
768        filter.addAction(Intent.ACTION_SCREEN_OFF);
769        filter.addAction(Intent.ACTION_SCREEN_ON);
770        filter.addAction(ACTION_DEMO);
771        context.registerReceiver(mBroadcastReceiver, filter);
772
773        // listen for USER_SETUP_COMPLETE setting (per-user)
774        resetUserSetupObserver();
775
776        return mStatusBarView;
777    }
778
779    private void startKeyguard() {
780        KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class);
781        mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this,
782                mStatusBarWindow, mStatusBarWindowManager, mScrimController);
783        mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback();
784    }
785
786    @Override
787    protected void onShowSearchPanel() {
788        if (mNavigationBarView != null) {
789            mNavigationBarView.getBarTransitions().setContentVisible(false);
790        }
791    }
792
793    @Override
794    protected void onHideSearchPanel() {
795        if (mNavigationBarView != null) {
796            mNavigationBarView.getBarTransitions().setContentVisible(true);
797        }
798    }
799
800    @Override
801    protected View getStatusBarView() {
802        return mStatusBarView;
803    }
804
805    @Override
806    protected WindowManager.LayoutParams getSearchLayoutParams(LayoutParams layoutParams) {
807        boolean opaque = false;
808        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
809                LayoutParams.MATCH_PARENT,
810                LayoutParams.MATCH_PARENT,
811                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
812                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
813                | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
814                | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
815                (opaque ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT));
816        if (ActivityManager.isHighEndGfx()) {
817            lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
818        }
819        lp.gravity = Gravity.BOTTOM | Gravity.START;
820        lp.setTitle("SearchPanel");
821        // TODO: Define custom animation for Search panel
822        lp.windowAnimations = com.android.internal.R.style.Animation_RecentApplications;
823        lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED
824        | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
825        return lp;
826    }
827
828    @Override
829    protected void updateSearchPanel() {
830        super.updateSearchPanel();
831        if (mNavigationBarView != null) {
832            mNavigationBarView.setDelegateView(mSearchPanelView);
833        }
834    }
835
836    @Override
837    public void showSearchPanel() {
838        super.showSearchPanel();
839        mHandler.removeCallbacks(mShowSearchPanel);
840
841        // we want to freeze the sysui state wherever it is
842        mSearchPanelView.setSystemUiVisibility(mSystemUiVisibility);
843
844        if (mNavigationBarView != null) {
845            WindowManager.LayoutParams lp =
846                (android.view.WindowManager.LayoutParams) mNavigationBarView.getLayoutParams();
847            lp.flags &= ~WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
848            mWindowManager.updateViewLayout(mNavigationBarView, lp);
849        }
850    }
851
852    @Override
853    public void hideSearchPanel() {
854        super.hideSearchPanel();
855        if (mNavigationBarView != null) {
856            WindowManager.LayoutParams lp =
857                (android.view.WindowManager.LayoutParams) mNavigationBarView.getLayoutParams();
858            lp.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
859            mWindowManager.updateViewLayout(mNavigationBarView, lp);
860        }
861    }
862
863    public int getStatusBarHeight() {
864        if (mNaturalBarHeight < 0) {
865            final Resources res = mContext.getResources();
866            mNaturalBarHeight =
867                    res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
868        }
869        return mNaturalBarHeight;
870    }
871
872    private View.OnClickListener mRecentsClickListener = new View.OnClickListener() {
873        public void onClick(View v) {
874            awakenDreams();
875            toggleRecentApps();
876        }
877    };
878
879    private int mShowSearchHoldoff = 0;
880    private Runnable mShowSearchPanel = new Runnable() {
881        public void run() {
882            showSearchPanel();
883            awakenDreams();
884        }
885    };
886
887    View.OnTouchListener mHomeSearchActionListener = new View.OnTouchListener() {
888        public boolean onTouch(View v, MotionEvent event) {
889            switch(event.getAction()) {
890            case MotionEvent.ACTION_DOWN:
891                if (!shouldDisableNavbarGestures()) {
892                    mHandler.removeCallbacks(mShowSearchPanel);
893                    mHandler.postDelayed(mShowSearchPanel, mShowSearchHoldoff);
894                }
895            break;
896
897            case MotionEvent.ACTION_UP:
898            case MotionEvent.ACTION_CANCEL:
899                mHandler.removeCallbacks(mShowSearchPanel);
900                awakenDreams();
901            break;
902        }
903        return false;
904        }
905    };
906
907    private void awakenDreams() {
908        if (mDreamManager != null) {
909            try {
910                mDreamManager.awaken();
911            } catch (RemoteException e) {
912                // fine, stay asleep then
913            }
914        }
915    }
916
917    private void prepareNavigationBarView() {
918        mNavigationBarView.reorient();
919
920        mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener);
921        mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPreloadOnTouchListener);
922        mNavigationBarView.getHomeButton().setOnTouchListener(mHomeSearchActionListener);
923        mNavigationBarView.getSearchLight().setOnTouchListener(mHomeSearchActionListener);
924        updateSearchPanel();
925    }
926
927    // For small-screen devices (read: phones) that lack hardware navigation buttons
928    private void addNavigationBar() {
929        if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + mNavigationBarView);
930        if (mNavigationBarView == null) return;
931
932        prepareNavigationBarView();
933
934        mWindowManager.addView(mNavigationBarView, getNavigationBarLayoutParams());
935    }
936
937    private void repositionNavigationBar() {
938        if (mNavigationBarView == null || !mNavigationBarView.isAttachedToWindow()) return;
939
940        prepareNavigationBarView();
941
942        mWindowManager.updateViewLayout(mNavigationBarView, getNavigationBarLayoutParams());
943    }
944
945    private void notifyNavigationBarScreenOn(boolean screenOn) {
946        if (mNavigationBarView == null) return;
947        mNavigationBarView.notifyScreenOn(screenOn);
948    }
949
950    private WindowManager.LayoutParams getNavigationBarLayoutParams() {
951        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
952                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
953                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
954                    0
955                    | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
956                    | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
957                    | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
958                    | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
959                    | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
960                PixelFormat.TRANSLUCENT);
961        // this will allow the navbar to run in an overlay on devices that support this
962        if (ActivityManager.isHighEndGfx()) {
963            lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
964        }
965
966        lp.setTitle("NavigationBar");
967        lp.windowAnimations = 0;
968        return lp;
969    }
970
971    private void addHeadsUpView() {
972        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
973                LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT,
974                WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL, // above the status bar!
975                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
976                    | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
977                    | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
978                    | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
979                    | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
980                    | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
981                PixelFormat.TRANSLUCENT);
982        lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
983        lp.gravity = Gravity.TOP;
984        lp.setTitle("Heads Up");
985        lp.packageName = mContext.getPackageName();
986        lp.windowAnimations = R.style.Animation_StatusBar_HeadsUp;
987
988        mWindowManager.addView(mHeadsUpNotificationView, lp);
989    }
990
991    private void removeHeadsUpView() {
992        mWindowManager.removeView(mHeadsUpNotificationView);
993    }
994
995    public void refreshAllStatusBarIcons() {
996        refreshAllIconsForLayout(mStatusIcons);
997        refreshAllIconsForLayout(mNotificationIcons);
998    }
999
1000    private void refreshAllIconsForLayout(LinearLayout ll) {
1001        final int count = ll.getChildCount();
1002        for (int n = 0; n < count; n++) {
1003            View child = ll.getChildAt(n);
1004            if (child instanceof StatusBarIconView) {
1005                ((StatusBarIconView) child).updateDrawable();
1006            }
1007        }
1008    }
1009
1010    public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) {
1011        if (SPEW) Log.d(TAG, "addIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex
1012                + " icon=" + icon);
1013        StatusBarIconView view = new StatusBarIconView(mContext, slot, null);
1014        view.set(icon);
1015        mStatusIcons.addView(view, viewIndex, new LinearLayout.LayoutParams(mIconSize, mIconSize));
1016    }
1017
1018    public void updateIcon(String slot, int index, int viewIndex,
1019            StatusBarIcon old, StatusBarIcon icon) {
1020        if (SPEW) Log.d(TAG, "updateIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex
1021                + " old=" + old + " icon=" + icon);
1022        StatusBarIconView view = (StatusBarIconView)mStatusIcons.getChildAt(viewIndex);
1023        view.set(icon);
1024    }
1025
1026    public void removeIcon(String slot, int index, int viewIndex) {
1027        if (SPEW) Log.d(TAG, "removeIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex);
1028        mStatusIcons.removeViewAt(viewIndex);
1029    }
1030
1031    public UserHandle getCurrentUserHandle() {
1032        return new UserHandle(mCurrentUserId);
1033    }
1034
1035    @Override
1036    public void addNotificationInternal(StatusBarNotification notification) {
1037        if (DEBUG) Log.d(TAG, "addNotification score=" + notification.getScore());
1038        Entry shadeEntry = createNotificationViews(notification);
1039        if (shadeEntry == null) {
1040            return;
1041        }
1042        if (mZenMode != Global.ZEN_MODE_OFF && mIntercepted.tryIntercept(notification)) {
1043            return;
1044        }
1045        if (mUseHeadsUp && shouldInterrupt(notification)) {
1046            if (DEBUG) Log.d(TAG, "launching notification in heads up mode");
1047            Entry interruptionCandidate = new Entry(notification, null);
1048            ViewGroup holder = mHeadsUpNotificationView.getHolder();
1049            if (inflateViewsForHeadsUp(interruptionCandidate, holder)) {
1050                mInterruptingNotificationTime = System.currentTimeMillis();
1051                mInterruptingNotificationEntry = interruptionCandidate;
1052                shadeEntry.setInterruption();
1053
1054                // 1. Populate mHeadsUpNotificationView
1055                mHeadsUpNotificationView.setNotification(mInterruptingNotificationEntry);
1056
1057                // 2. Animate mHeadsUpNotificationView in
1058                mHandler.sendEmptyMessage(MSG_SHOW_HEADS_UP);
1059
1060                // 3. Set alarm to age the notification off
1061                resetHeadsUpDecayTimer();
1062            }
1063        } else if (notification.getNotification().fullScreenIntent != null) {
1064            // Stop screensaver if the notification has a full-screen intent.
1065            // (like an incoming phone call)
1066            awakenDreams();
1067
1068            // not immersive & a full-screen alert should be shown
1069            if (DEBUG) Log.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent");
1070            try {
1071                notification.getNotification().fullScreenIntent.send();
1072            } catch (PendingIntent.CanceledException e) {
1073            }
1074        } else {
1075            // usual case: status bar visible & not immersive
1076
1077            // show the ticker if there isn't already a heads up
1078            if (mInterruptingNotificationEntry == null) {
1079                tick(notification, true);
1080            }
1081        }
1082        addNotificationViews(shadeEntry);
1083        // Recalculate the position of the sliding windows and the titles.
1084        setAreThereNotifications();
1085        updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
1086    }
1087
1088    @Override
1089    public void resetHeadsUpDecayTimer() {
1090        mHandler.removeMessages(MSG_HIDE_HEADS_UP);
1091        if (mUseHeadsUp && mHeadsUpNotificationDecay > 0
1092                && mHeadsUpNotificationView.isClearable()) {
1093            mHandler.sendEmptyMessageDelayed(MSG_HIDE_HEADS_UP, mHeadsUpNotificationDecay);
1094        }
1095    }
1096
1097    @Override
1098    public void updateNotification(StatusBarNotification notification) {
1099        super.updateNotification(notification);
1100        mIntercepted.update(notification);
1101    }
1102
1103    @Override
1104    public void removeNotificationInternal(String key) {
1105        StatusBarNotification old = removeNotificationViews(key);
1106        if (SPEW) Log.d(TAG, "removeNotification key=" + key + " old=" + old);
1107
1108        if (old != null) {
1109            // Cancel the ticker if it's still running
1110            mTicker.removeEntry(old);
1111
1112            // Recalculate the position of the sliding windows and the titles.
1113            updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
1114
1115            if (ENABLE_HEADS_UP && mInterruptingNotificationEntry != null
1116                    && old == mInterruptingNotificationEntry.notification) {
1117                mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
1118            }
1119
1120            if (CLOSE_PANEL_WHEN_EMPTIED && mNotificationData.size() == 0
1121                    && !mNotificationPanel.isTracking() && mState != StatusBarState.KEYGUARD) {
1122                animateCollapsePanels();
1123            }
1124        }
1125        mIntercepted.remove(key);
1126        setAreThereNotifications();
1127    }
1128
1129    @Override
1130    protected void refreshLayout(int layoutDirection) {
1131        if (mNavigationBarView != null) {
1132            mNavigationBarView.setLayoutDirection(layoutDirection);
1133        }
1134        refreshAllStatusBarIcons();
1135    }
1136
1137    private void updateShowSearchHoldoff() {
1138        mShowSearchHoldoff = mContext.getResources().getInteger(
1139            R.integer.config_show_search_delay);
1140    }
1141
1142    private void loadNotificationShade() {
1143        if (mStackScroller == null) return;
1144
1145        int N = mNotificationData.size();
1146
1147        ArrayList<View> toShow = new ArrayList<View>();
1148
1149        final boolean provisioned = isDeviceProvisioned();
1150        // If the device hasn't been through Setup, we only show system notifications
1151        for (int i=0; i<N; i++) {
1152            Entry ent = mNotificationData.get(N-i-1);
1153            if (!(provisioned || showNotificationEvenIfUnprovisioned(ent.notification))) continue;
1154
1155            // TODO How do we want to badge notifcations from profiles.
1156            if (!notificationIsForCurrentProfiles(ent.notification)) continue;
1157
1158            final int vis = ent.notification.getNotification().visibility;
1159            if (vis != Notification.VISIBILITY_SECRET) {
1160                // when isLockscreenPublicMode() we show the public form of VISIBILITY_PRIVATE notifications
1161                ent.row.setShowingPublic(isLockscreenPublicMode()
1162                        && vis == Notification.VISIBILITY_PRIVATE
1163                        && !userAllowsPrivateNotificationsInPublic(ent.notification.getUserId()));
1164                toShow.add(ent.row);
1165            }
1166        }
1167
1168        ArrayList<View> toRemove = new ArrayList<View>();
1169        for (int i=0; i< mStackScroller.getChildCount(); i++) {
1170            View child = mStackScroller.getChildAt(i);
1171            if (!toShow.contains(child) && child instanceof ExpandableNotificationRow) {
1172                toRemove.add(child);
1173            }
1174        }
1175
1176        for (View remove : toRemove) {
1177            mStackScroller.removeView(remove);
1178        }
1179
1180        for (int i=0; i<toShow.size(); i++) {
1181            View v = toShow.get(i);
1182            if (v.getParent() == null) {
1183                mStackScroller.addView(v, i);
1184            }
1185        }
1186
1187        mNotificationPanel.setQsExpansionEnabled(provisioned && mUserSetup);
1188    }
1189
1190    @Override
1191    protected void updateNotificationIcons() {
1192        if (mNotificationIcons == null) return;
1193
1194        loadNotificationShade();
1195
1196        final LinearLayout.LayoutParams params
1197            = new LinearLayout.LayoutParams(mIconSize + 2*mIconHPadding, mNaturalBarHeight);
1198
1199        int N = mNotificationData.size();
1200
1201        if (DEBUG) {
1202            Log.d(TAG, "refreshing icons: " + N + " notifications, mNotificationIcons=" + mNotificationIcons);
1203        }
1204
1205        ArrayList<View> toShow = new ArrayList<View>();
1206
1207        final boolean provisioned = isDeviceProvisioned();
1208        // If the device hasn't been through Setup, we only show system notifications
1209        for (int i=0; i<N; i++) {
1210            Entry ent = mNotificationData.get(N-i-1);
1211            if (!((provisioned && ent.notification.getScore() >= HIDE_ICONS_BELOW_SCORE)
1212                    || showNotificationEvenIfUnprovisioned(ent.notification))) continue;
1213            if (!notificationIsForCurrentProfiles(ent.notification)) continue;
1214            if (isLockscreenPublicMode()
1215                    && ent.notification.getNotification().visibility
1216                            == Notification.VISIBILITY_SECRET
1217                    && !userAllowsPrivateNotificationsInPublic(ent.notification.getUserId())) {
1218                // in "public" mode (atop a secure keyguard), secret notifs are totally hidden
1219                continue;
1220            }
1221            if (mIntercepted.isSyntheticEntry(ent)) {
1222                continue;
1223            }
1224            toShow.add(ent.icon);
1225        }
1226
1227        ArrayList<View> toRemove = new ArrayList<View>();
1228        for (int i=0; i<mNotificationIcons.getChildCount(); i++) {
1229            View child = mNotificationIcons.getChildAt(i);
1230            if (!toShow.contains(child)) {
1231                toRemove.add(child);
1232            }
1233        }
1234
1235        for (View remove : toRemove) {
1236            mNotificationIcons.removeView(remove);
1237        }
1238
1239        for (int i=0; i<toShow.size(); i++) {
1240            View v = toShow.get(i);
1241            if (v.getParent() == null) {
1242                mNotificationIcons.addView(v, i, params);
1243            }
1244        }
1245    }
1246
1247    protected void updateCarrierLabelVisibility(boolean force) {
1248        // TODO: Handle this for the notification stack scroller as well
1249        if (!mShowCarrierInPanel) return;
1250        // The idea here is to only show the carrier label when there is enough room to see it,
1251        // i.e. when there aren't enough notifications to fill the panel.
1252        if (SPEW) {
1253            Log.d(TAG, String.format("stackScrollerh=%d scrollh=%d carrierh=%d",
1254                    mStackScroller.getHeight(), mStackScroller.getHeight(),
1255                    mCarrierLabelHeight));
1256        }
1257
1258        final boolean emergencyCallsShownElsewhere = mEmergencyCallLabel != null;
1259        final boolean makeVisible =
1260            !(emergencyCallsShownElsewhere && mNetworkController.isEmergencyOnly())
1261            && mStackScroller.getHeight() < (mNotificationPanel.getHeight()
1262                    - mCarrierLabelHeight - mStatusBarHeaderHeight)
1263            && mStackScroller.getVisibility() == View.VISIBLE
1264            && mState != StatusBarState.KEYGUARD;
1265
1266        if (force || mCarrierLabelVisible != makeVisible) {
1267            mCarrierLabelVisible = makeVisible;
1268            if (DEBUG) {
1269                Log.d(TAG, "making carrier label " + (makeVisible?"visible":"invisible"));
1270            }
1271            mCarrierLabel.animate().cancel();
1272            if (makeVisible) {
1273                mCarrierLabel.setVisibility(View.VISIBLE);
1274            }
1275            mCarrierLabel.animate()
1276                .alpha(makeVisible ? 1f : 0f)
1277                //.setStartDelay(makeVisible ? 500 : 0)
1278                //.setDuration(makeVisible ? 750 : 100)
1279                .setDuration(150)
1280                .setListener(makeVisible ? null : new AnimatorListenerAdapter() {
1281                    @Override
1282                    public void onAnimationEnd(Animator animation) {
1283                        if (!mCarrierLabelVisible) { // race
1284                            mCarrierLabel.setVisibility(View.INVISIBLE);
1285                            mCarrierLabel.setAlpha(0f);
1286                        }
1287                    }
1288                })
1289                .start();
1290        }
1291    }
1292
1293    @Override
1294    protected void setAreThereNotifications() {
1295        final boolean any = mNotificationData.size() > 0;
1296
1297        final boolean clearable = any && mNotificationData.hasClearableItems();
1298
1299        if (SPEW) {
1300            Log.d(TAG, "setAreThereNotifications: N=" + mNotificationData.size()
1301                    + " any=" + any + " clearable=" + clearable);
1302        }
1303
1304        final View nlo = mStatusBarView.findViewById(R.id.notification_lights_out);
1305        final boolean showDot = (any&&!areLightsOn());
1306        if (showDot != (nlo.getAlpha() == 1.0f)) {
1307            if (showDot) {
1308                nlo.setAlpha(0f);
1309                nlo.setVisibility(View.VISIBLE);
1310            }
1311            nlo.animate()
1312                .alpha(showDot?1:0)
1313                .setDuration(showDot?750:250)
1314                .setInterpolator(new AccelerateInterpolator(2.0f))
1315                .setListener(showDot ? null : new AnimatorListenerAdapter() {
1316                    @Override
1317                    public void onAnimationEnd(Animator _a) {
1318                        nlo.setVisibility(View.GONE);
1319                    }
1320                })
1321                .start();
1322        }
1323
1324        updateCarrierLabelVisibility(false);
1325    }
1326
1327    public void showClock(boolean show) {
1328        if (mStatusBarView == null) return;
1329        View clock = mStatusBarView.findViewById(R.id.clock);
1330        if (clock != null) {
1331            clock.setVisibility(show ? View.VISIBLE : View.GONE);
1332        }
1333    }
1334
1335    /**
1336     * State is one or more of the DISABLE constants from StatusBarManager.
1337     */
1338    public void disable(int state) {
1339        final int old = mDisabled;
1340        final int diff = state ^ old;
1341        mDisabled = state;
1342
1343        if (DEBUG) {
1344            Log.d(TAG, String.format("disable: 0x%08x -> 0x%08x (diff: 0x%08x)",
1345                old, state, diff));
1346        }
1347
1348        StringBuilder flagdbg = new StringBuilder();
1349        flagdbg.append("disable: < ");
1350        flagdbg.append(((state & StatusBarManager.DISABLE_EXPAND) != 0) ? "EXPAND" : "expand");
1351        flagdbg.append(((diff  & StatusBarManager.DISABLE_EXPAND) != 0) ? "* " : " ");
1352        flagdbg.append(((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) ? "ICONS" : "icons");
1353        flagdbg.append(((diff  & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) ? "* " : " ");
1354        flagdbg.append(((state & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) ? "ALERTS" : "alerts");
1355        flagdbg.append(((diff  & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) ? "* " : " ");
1356        flagdbg.append(((state & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) ? "SYSTEM_INFO" : "system_info");
1357        flagdbg.append(((diff  & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) ? "* " : " ");
1358        flagdbg.append(((state & StatusBarManager.DISABLE_BACK) != 0) ? "BACK" : "back");
1359        flagdbg.append(((diff  & StatusBarManager.DISABLE_BACK) != 0) ? "* " : " ");
1360        flagdbg.append(((state & StatusBarManager.DISABLE_HOME) != 0) ? "HOME" : "home");
1361        flagdbg.append(((diff  & StatusBarManager.DISABLE_HOME) != 0) ? "* " : " ");
1362        flagdbg.append(((state & StatusBarManager.DISABLE_RECENT) != 0) ? "RECENT" : "recent");
1363        flagdbg.append(((diff  & StatusBarManager.DISABLE_RECENT) != 0) ? "* " : " ");
1364        flagdbg.append(((state & StatusBarManager.DISABLE_CLOCK) != 0) ? "CLOCK" : "clock");
1365        flagdbg.append(((diff  & StatusBarManager.DISABLE_CLOCK) != 0) ? "* " : " ");
1366        flagdbg.append(((state & StatusBarManager.DISABLE_SEARCH) != 0) ? "SEARCH" : "search");
1367        flagdbg.append(((diff  & StatusBarManager.DISABLE_SEARCH) != 0) ? "* " : " ");
1368        flagdbg.append(">");
1369        Log.d(TAG, flagdbg.toString());
1370
1371        if ((diff & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
1372            mSystemIconArea.animate().cancel();
1373            if ((state & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
1374                mSystemIconArea.animate()
1375                    .alpha(0f)
1376                    .translationY(mNaturalBarHeight*0.5f)
1377                    .setDuration(175)
1378                    .setInterpolator(new DecelerateInterpolator(1.5f))
1379                    .setListener(mMakeIconsInvisible)
1380                    .start();
1381            } else {
1382                mSystemIconArea.setVisibility(View.VISIBLE);
1383                mSystemIconArea.animate()
1384                    .alpha(1f)
1385                    .translationY(0)
1386                    .setStartDelay(0)
1387                    .setInterpolator(new DecelerateInterpolator(1.5f))
1388                    .setDuration(175)
1389                    .start();
1390            }
1391        }
1392
1393        if ((diff & StatusBarManager.DISABLE_CLOCK) != 0) {
1394            boolean show = (state & StatusBarManager.DISABLE_CLOCK) == 0;
1395            showClock(show);
1396        }
1397        if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
1398            if ((state & StatusBarManager.DISABLE_EXPAND) != 0) {
1399                animateCollapsePanels();
1400            }
1401        }
1402
1403        if ((diff & (StatusBarManager.DISABLE_HOME
1404                        | StatusBarManager.DISABLE_RECENT
1405                        | StatusBarManager.DISABLE_BACK
1406                        | StatusBarManager.DISABLE_SEARCH)) != 0) {
1407            // the nav bar will take care of these
1408            if (mNavigationBarView != null) mNavigationBarView.setDisabledFlags(state);
1409
1410            if ((state & StatusBarManager.DISABLE_RECENT) != 0) {
1411                // close recents if it's visible
1412                mHandler.removeMessages(MSG_HIDE_RECENT_APPS);
1413                mHandler.sendEmptyMessage(MSG_HIDE_RECENT_APPS);
1414            }
1415        }
1416
1417        if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
1418            if ((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
1419                if (mTicking) {
1420                    haltTicker();
1421                }
1422
1423                mNotificationIcons.animate()
1424                    .alpha(0f)
1425                    .translationY(mNaturalBarHeight*0.5f)
1426                    .setDuration(175)
1427                    .setInterpolator(new DecelerateInterpolator(1.5f))
1428                    .setListener(mMakeIconsInvisible)
1429                    .start();
1430            } else {
1431                mNotificationIcons.setVisibility(View.VISIBLE);
1432                mNotificationIcons.animate()
1433                    .alpha(1f)
1434                    .translationY(0)
1435                    .setStartDelay(0)
1436                    .setInterpolator(new DecelerateInterpolator(1.5f))
1437                    .setDuration(175)
1438                    .start();
1439            }
1440        }
1441    }
1442
1443    @Override
1444    protected BaseStatusBar.H createHandler() {
1445        return new PhoneStatusBar.H();
1446    }
1447
1448    @Override
1449    public void startActivity(Intent intent) {
1450        startActivityDismissingKeyguard(intent, false);
1451    }
1452
1453    public ScrimController getScrimController() {
1454        return mScrimController;
1455    }
1456
1457    /**
1458     * All changes to the status bar and notifications funnel through here and are batched.
1459     */
1460    private class H extends BaseStatusBar.H {
1461        public void handleMessage(Message m) {
1462            super.handleMessage(m);
1463            switch (m.what) {
1464                case MSG_OPEN_NOTIFICATION_PANEL:
1465                    animateExpandNotificationsPanel();
1466                    break;
1467                case MSG_OPEN_SETTINGS_PANEL:
1468                    animateExpandSettingsPanel();
1469                    break;
1470                case MSG_CLOSE_PANELS:
1471                    animateCollapsePanels();
1472                    break;
1473                case MSG_SHOW_HEADS_UP:
1474                    setHeadsUpVisibility(true);
1475                    break;
1476                case MSG_HIDE_HEADS_UP:
1477                    setHeadsUpVisibility(false);
1478                    break;
1479                case MSG_ESCALATE_HEADS_UP:
1480                    escalateHeadsUp();
1481                    setHeadsUpVisibility(false);
1482                    break;
1483            }
1484        }
1485    }
1486
1487    /**  if the interrupting notification had a fullscreen intent, fire it now.  */
1488    private void escalateHeadsUp() {
1489        if (mInterruptingNotificationEntry != null) {
1490            final StatusBarNotification sbn = mInterruptingNotificationEntry.notification;
1491            final Notification notification = sbn.getNotification();
1492            if (notification.fullScreenIntent != null) {
1493                if (DEBUG)
1494                    Log.d(TAG, "converting a heads up to fullScreen");
1495                try {
1496                    notification.fullScreenIntent.send();
1497                } catch (PendingIntent.CanceledException e) {
1498                }
1499            }
1500        }
1501    }
1502
1503    private Handler getHandler() {
1504        return mHandler;
1505    }
1506
1507    View.OnFocusChangeListener mFocusChangeListener = new View.OnFocusChangeListener() {
1508        public void onFocusChange(View v, boolean hasFocus) {
1509            // Because 'v' is a ViewGroup, all its children will be (un)selected
1510            // too, which allows marqueeing to work.
1511            v.setSelected(hasFocus);
1512        }
1513    };
1514
1515    boolean panelsEnabled() {
1516        return (mDisabled & StatusBarManager.DISABLE_EXPAND) == 0;
1517    }
1518
1519    void makeExpandedVisible(boolean force) {
1520        if (SPEW) Log.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible);
1521        if (!force && (mExpandedVisible || !panelsEnabled())) {
1522            return;
1523        }
1524
1525        mExpandedVisible = true;
1526        if (mNavigationBarView != null)
1527            mNavigationBarView.setSlippery(true);
1528
1529        updateCarrierLabelVisibility(true);
1530
1531        updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
1532
1533        // Expand the window to encompass the full screen in anticipation of the drag.
1534        // This is only possible to do atomically because the status bar is at the top of the screen!
1535        mStatusBarWindowManager.setStatusBarExpanded(true);
1536
1537        visibilityChanged(true);
1538
1539        setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true);
1540    }
1541
1542    public void animateCollapsePanels() {
1543        animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
1544    }
1545
1546    private final Runnable mAnimateCollapsePanels = new Runnable() {
1547        @Override
1548        public void run() {
1549            animateCollapsePanels();
1550        }
1551    };
1552
1553    public void postAnimateCollapsePanels() {
1554        mHandler.post(mAnimateCollapsePanels);
1555    }
1556
1557    public void animateCollapsePanels(int flags) {
1558        if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
1559            return;
1560        }
1561        if (SPEW) {
1562            Log.d(TAG, "animateCollapse():"
1563                    + " mExpandedVisible=" + mExpandedVisible
1564                    + " flags=" + flags);
1565        }
1566
1567        if ((flags & CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL) == 0) {
1568            mHandler.removeMessages(MSG_HIDE_RECENT_APPS);
1569            mHandler.sendEmptyMessage(MSG_HIDE_RECENT_APPS);
1570        }
1571
1572        if ((flags & CommandQueue.FLAG_EXCLUDE_SEARCH_PANEL) == 0) {
1573            mHandler.removeMessages(MSG_CLOSE_SEARCH_PANEL);
1574            mHandler.sendEmptyMessage(MSG_CLOSE_SEARCH_PANEL);
1575        }
1576
1577        if (mStatusBarWindow != null) {
1578
1579            // release focus immediately to kick off focus change transition
1580            mStatusBarWindowManager.setStatusBarFocusable(false);
1581
1582            mStatusBarWindow.cancelExpandHelper();
1583            mStatusBarView.collapseAllPanels(true);
1584            if (isFlippedToSettings()) {
1585                flipToNotifications(true /*animate*/);
1586            }
1587        }
1588    }
1589
1590    public ViewPropertyAnimator setVisibilityWhenDone(
1591            final ViewPropertyAnimator a, final View v, final int vis) {
1592        a.setListener(new AnimatorListenerAdapter() {
1593            @Override
1594            public void onAnimationEnd(Animator animation) {
1595                v.setVisibility(vis);
1596                a.setListener(null); // oneshot
1597            }
1598        });
1599        return a;
1600    }
1601
1602    public Animator setVisibilityWhenDone(
1603            final Animator a, final View v, final int vis) {
1604        a.addListener(new AnimatorListenerAdapter() {
1605            @Override
1606            public void onAnimationEnd(Animator animation) {
1607                v.setVisibility(vis);
1608            }
1609        });
1610        return a;
1611    }
1612
1613    public Animator interpolator(TimeInterpolator ti, Animator a) {
1614        a.setInterpolator(ti);
1615        return a;
1616    }
1617
1618    public Animator startDelay(int d, Animator a) {
1619        a.setStartDelay(d);
1620        return a;
1621    }
1622
1623    public Animator start(Animator a) {
1624        a.start();
1625        return a;
1626    }
1627
1628    final TimeInterpolator mAccelerateInterpolator = new AccelerateInterpolator();
1629    final TimeInterpolator mDecelerateInterpolator = new DecelerateInterpolator();
1630    final int FLIP_DURATION_OUT = 125;
1631    final int FLIP_DURATION_IN = 225;
1632    final int FLIP_DURATION = (FLIP_DURATION_IN + FLIP_DURATION_OUT);
1633
1634    Animator mScrollViewAnim, mClearButtonAnim;
1635
1636    @Override
1637    public void animateExpandNotificationsPanel() {
1638        if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible);
1639        if (!panelsEnabled()) {
1640            return ;
1641        }
1642
1643        mNotificationPanel.expand();
1644        if (mStackScroller.getVisibility() != View.VISIBLE) {
1645            flipToNotifications(true /*animate*/);
1646        }
1647
1648        if (false) postStartTracing();
1649    }
1650
1651    private static void cancelAnim(Animator anim) {
1652        if (anim != null) {
1653            anim.cancel();
1654        }
1655    }
1656
1657    public void flipToNotifications(boolean animate) {
1658        // TODO: Animation
1659        mNotificationPanel.closeQs();
1660    }
1661
1662    @Override
1663    public void animateExpandSettingsPanel() {
1664        if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible);
1665        if (!panelsEnabled()) {
1666            return;
1667        }
1668
1669        // Settings are not available in setup
1670        if (!mUserSetup) return;
1671
1672        mNotificationPanel.expand();
1673        mNotificationPanel.openQs();
1674
1675        if (false) postStartTracing();
1676    }
1677
1678    public boolean isFlippedToSettings() {
1679        if (mNotificationPanel != null) {
1680            return mNotificationPanel.isQsExpanded();
1681        }
1682        return false;
1683    }
1684
1685    public void animateCollapseQuickSettings() {
1686        mStatusBarView.collapseAllPanels(true);
1687    }
1688
1689    void makeExpandedInvisibleSoon() {
1690        mHandler.postDelayed(new Runnable() { public void run() { makeExpandedInvisible(); }}, 50);
1691    }
1692
1693    void makeExpandedInvisible() {
1694        if (SPEW) Log.d(TAG, "makeExpandedInvisible: mExpandedVisible=" + mExpandedVisible
1695                + " mExpandedVisible=" + mExpandedVisible);
1696
1697        if (!mExpandedVisible || mStatusBarWindow == null) {
1698            return;
1699        }
1700
1701        // Ensure the panel is fully collapsed (just in case; bug 6765842, 7260868)
1702        mStatusBarView.collapseAllPanels(/*animate=*/ false);
1703
1704        // reset things to their proper state
1705        if (mScrollViewAnim != null) mScrollViewAnim.cancel();
1706        if (mClearButtonAnim != null) mClearButtonAnim.cancel();
1707
1708        mStackScroller.setVisibility(View.VISIBLE);
1709        mNotificationPanel.setVisibility(View.GONE);
1710
1711        setAreThereNotifications(); // show the clear button
1712
1713        mNotificationPanel.closeQs();
1714
1715        mExpandedVisible = false;
1716        if (mNavigationBarView != null)
1717            mNavigationBarView.setSlippery(false);
1718        visibilityChanged(false);
1719
1720        // Shrink the window to the size of the status bar only
1721        mStatusBarWindowManager.setStatusBarExpanded(false);
1722
1723        if ((mDisabled & StatusBarManager.DISABLE_NOTIFICATION_ICONS) == 0) {
1724            setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
1725        }
1726
1727        // Close any "App info" popups that might have snuck on-screen
1728        dismissPopups();
1729
1730        if (mPostCollapseCleanup != null) {
1731            mPostCollapseCleanup.run();
1732            mPostCollapseCleanup = null;
1733        }
1734
1735        setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
1736
1737        showBouncer();
1738    }
1739
1740    public boolean interceptTouchEvent(MotionEvent event) {
1741        if (DEBUG_GESTURES) {
1742            if (event.getActionMasked() != MotionEvent.ACTION_MOVE) {
1743                EventLog.writeEvent(EventLogTags.SYSUI_STATUSBAR_TOUCH,
1744                        event.getActionMasked(), (int) event.getX(), (int) event.getY(), mDisabled);
1745            }
1746
1747        }
1748
1749        if (SPEW) {
1750            Log.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled="
1751                + mDisabled + " mTracking=" + mTracking);
1752        } else if (CHATTY) {
1753            if (event.getAction() != MotionEvent.ACTION_MOVE) {
1754                Log.d(TAG, String.format(
1755                            "panel: %s at (%f, %f) mDisabled=0x%08x",
1756                            MotionEvent.actionToString(event.getAction()),
1757                            event.getRawX(), event.getRawY(), mDisabled));
1758            }
1759        }
1760
1761        if (DEBUG_GESTURES) {
1762            mGestureRec.add(event);
1763        }
1764
1765        if (mStatusBarWindowState == WINDOW_STATE_SHOWING) {
1766            final boolean upOrCancel =
1767                    event.getAction() == MotionEvent.ACTION_UP ||
1768                    event.getAction() == MotionEvent.ACTION_CANCEL;
1769            if (upOrCancel && !mExpandedVisible) {
1770                setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
1771            } else {
1772                setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true);
1773            }
1774        }
1775        return false;
1776    }
1777
1778    public GestureRecorder getGestureRecorder() {
1779        return mGestureRec;
1780    }
1781
1782    private void setNavigationIconHints(int hints) {
1783        if (hints == mNavigationIconHints) return;
1784
1785        mNavigationIconHints = hints;
1786
1787        if (mNavigationBarView != null) {
1788            mNavigationBarView.setNavigationIconHints(hints);
1789        }
1790        checkBarModes();
1791    }
1792
1793    @Override // CommandQueue
1794    public void setWindowState(int window, int state) {
1795        boolean showing = state == WINDOW_STATE_SHOWING;
1796        if (mStatusBarWindow != null
1797                && window == StatusBarManager.WINDOW_STATUS_BAR
1798                && mStatusBarWindowState != state) {
1799            mStatusBarWindowState = state;
1800            if (DEBUG_WINDOW_STATE) Log.d(TAG, "Status bar " + windowStateToString(state));
1801            if (!showing) {
1802                mStatusBarView.collapseAllPanels(false);
1803            }
1804        }
1805        if (mNavigationBarView != null
1806                && window == StatusBarManager.WINDOW_NAVIGATION_BAR
1807                && mNavigationBarWindowState != state) {
1808            mNavigationBarWindowState = state;
1809            if (DEBUG_WINDOW_STATE) Log.d(TAG, "Navigation bar " + windowStateToString(state));
1810        }
1811    }
1812
1813    @Override // CommandQueue
1814    public void setSystemUiVisibility(int vis, int mask) {
1815        final int oldVal = mSystemUiVisibility;
1816        final int newVal = (oldVal&~mask) | (vis&mask);
1817        final int diff = newVal ^ oldVal;
1818        if (DEBUG) Log.d(TAG, String.format(
1819                "setSystemUiVisibility vis=%s mask=%s oldVal=%s newVal=%s diff=%s",
1820                Integer.toHexString(vis), Integer.toHexString(mask),
1821                Integer.toHexString(oldVal), Integer.toHexString(newVal),
1822                Integer.toHexString(diff)));
1823        if (diff != 0) {
1824            mSystemUiVisibility = newVal;
1825
1826            // update low profile
1827            if ((diff & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0) {
1828                final boolean lightsOut = (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0;
1829                if (lightsOut) {
1830                    animateCollapsePanels();
1831                    if (mTicking) {
1832                        haltTicker();
1833                    }
1834                }
1835
1836                setAreThereNotifications();
1837            }
1838
1839            // update status bar mode
1840            final int sbMode = computeBarMode(oldVal, newVal, mStatusBarView.getBarTransitions(),
1841                    View.STATUS_BAR_TRANSIENT, View.STATUS_BAR_TRANSLUCENT);
1842
1843            // update navigation bar mode
1844            final int nbMode = mNavigationBarView == null ? -1 : computeBarMode(
1845                    oldVal, newVal, mNavigationBarView.getBarTransitions(),
1846                    View.NAVIGATION_BAR_TRANSIENT, View.NAVIGATION_BAR_TRANSLUCENT);
1847            final boolean sbModeChanged = sbMode != -1;
1848            final boolean nbModeChanged = nbMode != -1;
1849            boolean checkBarModes = false;
1850            if (sbModeChanged && sbMode != mStatusBarMode) {
1851                mStatusBarMode = sbMode;
1852                checkBarModes = true;
1853            }
1854            if (nbModeChanged && nbMode != mNavigationBarMode) {
1855                mNavigationBarMode = nbMode;
1856                checkBarModes = true;
1857            }
1858            if (checkBarModes) {
1859                checkBarModes();
1860            }
1861            if (sbModeChanged || nbModeChanged) {
1862                // update transient bar autohide
1863                if (mStatusBarMode == MODE_SEMI_TRANSPARENT || mNavigationBarMode == MODE_SEMI_TRANSPARENT) {
1864                    scheduleAutohide();
1865                } else {
1866                    cancelAutohide();
1867                }
1868            }
1869
1870            // ready to unhide
1871            if ((vis & View.STATUS_BAR_UNHIDE) != 0) {
1872                mSystemUiVisibility &= ~View.STATUS_BAR_UNHIDE;
1873            }
1874            if ((vis & View.NAVIGATION_BAR_UNHIDE) != 0) {
1875                mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE;
1876            }
1877
1878            // send updated sysui visibility to window manager
1879            notifyUiVisibilityChanged(mSystemUiVisibility);
1880        }
1881    }
1882
1883    private int computeBarMode(int oldVis, int newVis, BarTransitions transitions,
1884            int transientFlag, int translucentFlag) {
1885        final int oldMode = barMode(oldVis, transientFlag, translucentFlag);
1886        final int newMode = barMode(newVis, transientFlag, translucentFlag);
1887        if (oldMode == newMode) {
1888            return -1; // no mode change
1889        }
1890        return newMode;
1891    }
1892
1893    private int barMode(int vis, int transientFlag, int translucentFlag) {
1894        return (vis & transientFlag) != 0 ? MODE_SEMI_TRANSPARENT
1895                : (vis & translucentFlag) != 0 ? MODE_TRANSLUCENT
1896                : (vis & View.SYSTEM_UI_TRANSPARENT) != 0 ? MODE_TRANSPARENT
1897                : (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0 ? MODE_LIGHTS_OUT
1898                : MODE_OPAQUE;
1899    }
1900
1901    private void checkBarModes() {
1902        if (mDemoMode) return;
1903        checkBarMode(mStatusBarMode, mStatusBarWindowState, mStatusBarView.getBarTransitions());
1904        if (mNavigationBarView != null) {
1905            checkBarMode(mNavigationBarMode,
1906                    mNavigationBarWindowState, mNavigationBarView.getBarTransitions());
1907        }
1908    }
1909
1910    private void checkBarMode(int mode, int windowState, BarTransitions transitions) {
1911        final boolean anim = (mScreenOn == null || mScreenOn) && windowState != WINDOW_STATE_HIDDEN;
1912        transitions.transitionTo(mode, anim);
1913    }
1914
1915    private void finishBarAnimations() {
1916        mStatusBarView.getBarTransitions().finishAnimations();
1917        if (mNavigationBarView != null) {
1918            mNavigationBarView.getBarTransitions().finishAnimations();
1919        }
1920    }
1921
1922    private final Runnable mCheckBarModes = new Runnable() {
1923        @Override
1924        public void run() {
1925            checkBarModes();
1926        }};
1927
1928    @Override
1929    public void setInteracting(int barWindow, boolean interacting) {
1930        mInteractingWindows = interacting
1931                ? (mInteractingWindows | barWindow)
1932                : (mInteractingWindows & ~barWindow);
1933        if (mInteractingWindows != 0) {
1934            suspendAutohide();
1935        } else {
1936            resumeSuspendedAutohide();
1937        }
1938        checkBarModes();
1939    }
1940
1941    private void resumeSuspendedAutohide() {
1942        if (mAutohideSuspended) {
1943            scheduleAutohide();
1944            mHandler.postDelayed(mCheckBarModes, 500); // longer than home -> launcher
1945        }
1946    }
1947
1948    private void suspendAutohide() {
1949        mHandler.removeCallbacks(mAutohide);
1950        mHandler.removeCallbacks(mCheckBarModes);
1951        mAutohideSuspended = (mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0;
1952    }
1953
1954    private void cancelAutohide() {
1955        mAutohideSuspended = false;
1956        mHandler.removeCallbacks(mAutohide);
1957    }
1958
1959    private void scheduleAutohide() {
1960        cancelAutohide();
1961        mHandler.postDelayed(mAutohide, AUTOHIDE_TIMEOUT_MS);
1962    }
1963
1964    private void checkUserAutohide(View v, MotionEvent event) {
1965        if ((mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0  // a transient bar is revealed
1966                && event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar
1967                && event.getX() == 0 && event.getY() == 0  // a touch outside both bars
1968                ) {
1969            userAutohide();
1970        }
1971    }
1972
1973    private void userAutohide() {
1974        cancelAutohide();
1975        mHandler.postDelayed(mAutohide, 350); // longer than app gesture -> flag clear
1976    }
1977
1978    private boolean areLightsOn() {
1979        return 0 == (mSystemUiVisibility & View.SYSTEM_UI_FLAG_LOW_PROFILE);
1980    }
1981
1982    public void setLightsOn(boolean on) {
1983        Log.v(TAG, "setLightsOn(" + on + ")");
1984        if (on) {
1985            setSystemUiVisibility(0, View.SYSTEM_UI_FLAG_LOW_PROFILE);
1986        } else {
1987            setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE, View.SYSTEM_UI_FLAG_LOW_PROFILE);
1988        }
1989    }
1990
1991    private void notifyUiVisibilityChanged(int vis) {
1992        try {
1993            mWindowManagerService.statusBarVisibilityChanged(vis);
1994        } catch (RemoteException ex) {
1995        }
1996    }
1997
1998    public void topAppWindowChanged(boolean showMenu) {
1999        if (DEBUG) {
2000            Log.d(TAG, (showMenu?"showing":"hiding") + " the MENU button");
2001        }
2002        if (mNavigationBarView != null) {
2003            mNavigationBarView.setMenuVisibility(showMenu);
2004        }
2005
2006        // See above re: lights-out policy for legacy apps.
2007        if (showMenu) setLightsOn(true);
2008    }
2009
2010    @Override
2011    public void setImeWindowStatus(IBinder token, int vis, int backDisposition,
2012            boolean showImeSwitcher) {
2013        boolean imeShown = (vis & InputMethodService.IME_VISIBLE) != 0;
2014        int flags = mNavigationIconHints;
2015        if ((backDisposition == InputMethodService.BACK_DISPOSITION_WILL_DISMISS) || imeShown) {
2016            flags |= NAVIGATION_HINT_BACK_ALT;
2017        } else {
2018            flags &= ~NAVIGATION_HINT_BACK_ALT;
2019        }
2020        if (showImeSwitcher) {
2021            flags |= NAVIGATION_HINT_IME_SHOWN;
2022        } else {
2023            flags &= ~NAVIGATION_HINT_IME_SHOWN;
2024        }
2025
2026        setNavigationIconHints(flags);
2027    }
2028
2029    @Override
2030    public void setHardKeyboardStatus(boolean available, boolean enabled) {}
2031
2032    @Override
2033    protected void tick(StatusBarNotification n, boolean firstTime) {
2034        // no ticking in lights-out mode
2035        if (!areLightsOn()) return;
2036
2037        // no ticking in Setup
2038        if (!isDeviceProvisioned()) return;
2039
2040        // not for you
2041        if (!notificationIsForCurrentProfiles(n)) return;
2042
2043        // Show the ticker if one is requested. Also don't do this
2044        // until status bar window is attached to the window manager,
2045        // because...  well, what's the point otherwise?  And trying to
2046        // run a ticker without being attached will crash!
2047        if (n.getNotification().tickerText != null && mStatusBarWindow != null
2048                && mStatusBarWindow.getWindowToken() != null) {
2049            if (0 == (mDisabled & (StatusBarManager.DISABLE_NOTIFICATION_ICONS
2050                            | StatusBarManager.DISABLE_NOTIFICATION_TICKER))) {
2051                mTicker.addEntry(n);
2052            }
2053        }
2054    }
2055
2056    private class MyTicker extends Ticker {
2057        MyTicker(Context context, View sb) {
2058            super(context, sb);
2059        }
2060
2061        @Override
2062        public void tickerStarting() {
2063            mTicking = true;
2064            mStatusBarContents.setVisibility(View.GONE);
2065            mTickerView.setVisibility(View.VISIBLE);
2066            mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_up_in, null));
2067            mStatusBarContents.startAnimation(loadAnim(com.android.internal.R.anim.push_up_out, null));
2068        }
2069
2070        @Override
2071        public void tickerDone() {
2072            mStatusBarContents.setVisibility(View.VISIBLE);
2073            mTickerView.setVisibility(View.GONE);
2074            mStatusBarContents.startAnimation(loadAnim(com.android.internal.R.anim.push_down_in, null));
2075            mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_down_out,
2076                        mTickingDoneListener));
2077        }
2078
2079        public void tickerHalting() {
2080            if (mStatusBarContents.getVisibility() != View.VISIBLE) {
2081                mStatusBarContents.setVisibility(View.VISIBLE);
2082                mStatusBarContents
2083                        .startAnimation(loadAnim(com.android.internal.R.anim.fade_in, null));
2084            }
2085            mTickerView.setVisibility(View.GONE);
2086            // we do not animate the ticker away at this point, just get rid of it (b/6992707)
2087        }
2088    }
2089
2090    Animation.AnimationListener mTickingDoneListener = new Animation.AnimationListener() {;
2091        public void onAnimationEnd(Animation animation) {
2092            mTicking = false;
2093        }
2094        public void onAnimationRepeat(Animation animation) {
2095        }
2096        public void onAnimationStart(Animation animation) {
2097        }
2098    };
2099
2100    private Animation loadAnim(int id, Animation.AnimationListener listener) {
2101        Animation anim = AnimationUtils.loadAnimation(mContext, id);
2102        if (listener != null) {
2103            anim.setAnimationListener(listener);
2104        }
2105        return anim;
2106    }
2107
2108    public static String viewInfo(View v) {
2109        return "[(" + v.getLeft() + "," + v.getTop() + ")(" + v.getRight() + "," + v.getBottom()
2110                + ") " + v.getWidth() + "x" + v.getHeight() + "]";
2111    }
2112
2113    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2114        synchronized (mQueueLock) {
2115            pw.println("Current Status Bar state:");
2116            pw.println("  mExpandedVisible=" + mExpandedVisible
2117                    + ", mTrackingPosition=" + mTrackingPosition);
2118            pw.println("  mTicking=" + mTicking);
2119            pw.println("  mTracking=" + mTracking);
2120            pw.println("  mDisplayMetrics=" + mDisplayMetrics);
2121            pw.println("  mStackScroller: " + viewInfo(mStackScroller));
2122            pw.println("  mTickerView: " + viewInfo(mTickerView));
2123            pw.println("  mStackScroller: " + viewInfo(mStackScroller)
2124                    + " scroll " + mStackScroller.getScrollX()
2125                    + "," + mStackScroller.getScrollY());
2126        }
2127
2128        pw.print("  mInteractingWindows="); pw.println(mInteractingWindows);
2129        pw.print("  mStatusBarWindowState=");
2130        pw.println(windowStateToString(mStatusBarWindowState));
2131        pw.print("  mStatusBarMode=");
2132        pw.println(BarTransitions.modeToString(mStatusBarMode));
2133        pw.print("  mZenMode=");
2134        pw.println(Settings.Global.zenModeToString(mZenMode));
2135        pw.print("  mUseHeadsUp=");
2136        pw.println(mUseHeadsUp);
2137        pw.print("  interrupting package: ");
2138        pw.println(hunStateToString(mInterruptingNotificationEntry));
2139        dumpBarTransitions(pw, "mStatusBarView", mStatusBarView.getBarTransitions());
2140        if (mNavigationBarView != null) {
2141            pw.print("  mNavigationBarWindowState=");
2142            pw.println(windowStateToString(mNavigationBarWindowState));
2143            pw.print("  mNavigationBarMode=");
2144            pw.println(BarTransitions.modeToString(mNavigationBarMode));
2145            dumpBarTransitions(pw, "mNavigationBarView", mNavigationBarView.getBarTransitions());
2146        }
2147
2148        pw.print("  mNavigationBarView=");
2149        if (mNavigationBarView == null) {
2150            pw.println("null");
2151        } else {
2152            mNavigationBarView.dump(fd, pw, args);
2153        }
2154
2155        pw.println("  Panels: ");
2156        if (mNotificationPanel != null) {
2157            pw.println("    mNotificationPanel=" +
2158                mNotificationPanel + " params=" + mNotificationPanel.getLayoutParams().debug(""));
2159            pw.print  ("      ");
2160            mNotificationPanel.dump(fd, pw, args);
2161        }
2162
2163        if (DUMPTRUCK) {
2164            synchronized (mNotificationData) {
2165                int N = mNotificationData.size();
2166                pw.println("  notification icons: " + N);
2167                for (int i=0; i<N; i++) {
2168                    NotificationData.Entry e = mNotificationData.get(i);
2169                    pw.println("    [" + i + "] key=" + e.key + " icon=" + e.icon);
2170                    StatusBarNotification n = e.notification;
2171                    pw.println("         pkg=" + n.getPackageName() + " id=" + n.getId() + " score=" + n.getScore());
2172                    pw.println("         notification=" + n.getNotification());
2173                    pw.println("         tickerText=\"" + n.getNotification().tickerText + "\"");
2174                }
2175            }
2176
2177            int N = mStatusIcons.getChildCount();
2178            pw.println("  system icons: " + N);
2179            for (int i=0; i<N; i++) {
2180                StatusBarIconView ic = (StatusBarIconView) mStatusIcons.getChildAt(i);
2181                pw.println("    [" + i + "] icon=" + ic);
2182            }
2183
2184            if (false) {
2185                pw.println("see the logcat for a dump of the views we have created.");
2186                // must happen on ui thread
2187                mHandler.post(new Runnable() {
2188                        public void run() {
2189                            mStatusBarView.getLocationOnScreen(mAbsPos);
2190                            Log.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
2191                                    + ") " + mStatusBarView.getWidth() + "x"
2192                                    + getStatusBarHeight());
2193                            mStatusBarView.debug();
2194                        }
2195                    });
2196            }
2197        }
2198
2199        if (DEBUG_GESTURES) {
2200            pw.print("  status bar gestures: ");
2201            mGestureRec.dump(fd, pw, args);
2202        }
2203
2204        mNetworkController.dump(fd, pw, args);
2205    }
2206
2207    private String hunStateToString(Entry entry) {
2208        if (entry == null) return "null";
2209        if (entry.notification == null) return "corrupt";
2210        return entry.notification.getPackageName();
2211    }
2212
2213    private static void dumpBarTransitions(PrintWriter pw, String var, BarTransitions transitions) {
2214        pw.print("  "); pw.print(var); pw.print(".BarTransitions.mMode=");
2215        pw.println(BarTransitions.modeToString(transitions.getMode()));
2216    }
2217
2218    @Override
2219    public void createAndAddWindows() {
2220        addStatusBarWindow();
2221    }
2222
2223    private void addStatusBarWindow() {
2224        makeStatusBarView();
2225        mStatusBarWindowManager = new StatusBarWindowManager(mContext);
2226        mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());
2227    }
2228
2229    void setNotificationIconVisibility(boolean visible, int anim) {
2230        int old = mNotificationIcons.getVisibility();
2231        int v = visible ? View.VISIBLE : View.INVISIBLE;
2232        if (old != v) {
2233            mNotificationIcons.setVisibility(v);
2234            mNotificationIcons.startAnimation(loadAnim(anim, null));
2235        }
2236    }
2237
2238    static final float saturate(float a) {
2239        return a < 0f ? 0f : (a > 1f ? 1f : a);
2240    }
2241
2242    @Override
2243    public void updateExpandedViewPos(int thingy) {
2244        if (SPEW) Log.v(TAG, "updateExpandedViewPos");
2245
2246        // on larger devices, the notification panel is propped open a bit
2247        mNotificationPanel.setMinimumHeight(
2248                (int)(mNotificationPanelMinHeightFrac * mCurrentDisplaySize.y));
2249
2250        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mNotificationPanel.getLayoutParams();
2251        lp.gravity = mNotificationPanelGravity;
2252        mNotificationPanel.setLayoutParams(lp);
2253
2254        updateCarrierLabelVisibility(false);
2255    }
2256
2257    // called by makeStatusbar and also by PhoneStatusBarView
2258    void updateDisplaySize() {
2259        mDisplay.getMetrics(mDisplayMetrics);
2260        mDisplay.getSize(mCurrentDisplaySize);
2261        if (DEBUG_GESTURES) {
2262            mGestureRec.tag("display",
2263                    String.format("%dx%d", mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels));
2264        }
2265    }
2266
2267    private View.OnClickListener mClearButtonListener = new View.OnClickListener() {
2268        public void onClick(View v) {
2269            synchronized (mNotificationData) {
2270                mPostCollapseCleanup = new Runnable() {
2271                    @Override
2272                    public void run() {
2273                        if (DEBUG) {
2274                            Log.v(TAG, "running post-collapse cleanup");
2275                        }
2276                        try {
2277                            mBarService.onClearAllNotifications(mCurrentUserId);
2278                        } catch (Exception ex) { }
2279                    }
2280                };
2281
2282                animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
2283                return;
2284                // TODO: Handle this better with notification stack scroller
2285            }
2286        }
2287    };
2288
2289    public void startActivityDismissingKeyguard(Intent intent, boolean onlyProvisioned) {
2290        if (onlyProvisioned && !isDeviceProvisioned()) return;
2291        try {
2292            // Dismiss the lock screen when Settings starts.
2293            ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
2294        } catch (RemoteException e) {
2295        }
2296        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
2297        mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
2298        animateCollapsePanels();
2299    }
2300
2301    private View.OnClickListener mClockClickListener = new View.OnClickListener() {
2302        public void onClick(View v) {
2303            startActivityDismissingKeyguard(
2304                    new Intent(Intent.ACTION_QUICK_CLOCK), true); // have fun, everyone
2305        }
2306    };
2307
2308    private View.OnClickListener mNotificationButtonListener = new View.OnClickListener() {
2309        public void onClick(View v) {
2310            animateExpandNotificationsPanel();
2311        }
2312    };
2313
2314    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
2315        public void onReceive(Context context, Intent intent) {
2316            if (DEBUG) Log.v(TAG, "onReceive: " + intent);
2317            String action = intent.getAction();
2318            if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
2319                int flags = CommandQueue.FLAG_EXCLUDE_NONE;
2320                if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
2321                    String reason = intent.getStringExtra("reason");
2322                    if (reason != null && reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) {
2323                        flags |= CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL;
2324                    }
2325                }
2326                animateCollapsePanels(flags);
2327            }
2328            else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
2329                mScreenOn = false;
2330                notifyNavigationBarScreenOn(false);
2331                notifyHeadsUpScreenOn(false);
2332                finishBarAnimations();
2333                stopNotificationLogging();
2334            }
2335            else if (Intent.ACTION_SCREEN_ON.equals(action)) {
2336                mScreenOn = true;
2337                // work around problem where mDisplay.getRotation() is not stable while screen is off (bug 7086018)
2338                repositionNavigationBar();
2339                notifyNavigationBarScreenOn(true);
2340                startNotificationLoggingIfScreenOnAndVisible();
2341            }
2342            else if (ACTION_DEMO.equals(action)) {
2343                Bundle bundle = intent.getExtras();
2344                if (bundle != null) {
2345                    String command = bundle.getString("command", "").trim().toLowerCase();
2346                    if (command.length() > 0) {
2347                        try {
2348                            dispatchDemoCommand(command, bundle);
2349                        } catch (Throwable t) {
2350                            Log.w(TAG, "Error running demo command, intent=" + intent, t);
2351                        }
2352                    }
2353                }
2354            }
2355        }
2356    };
2357
2358    @Override
2359    protected void startNotificationActivity(OnDismissAction action) {
2360        if (mStatusBarKeyguardViewManager.isShowing()) {
2361            mStatusBarKeyguardViewManager.dismissWithAction(action);
2362        } else {
2363            action.onDismiss();
2364        }
2365    }
2366
2367    // SystemUIService notifies SystemBars of configuration changes, which then calls down here
2368    @Override
2369    protected void onConfigurationChanged(Configuration newConfig) {
2370        super.onConfigurationChanged(newConfig); // calls refreshLayout
2371
2372        if (DEBUG) {
2373            Log.v(TAG, "configuration changed: " + mContext.getResources().getConfiguration());
2374        }
2375        updateDisplaySize(); // populates mDisplayMetrics
2376
2377        updateResources();
2378        repositionNavigationBar();
2379        updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
2380        updateShowSearchHoldoff();
2381    }
2382
2383    @Override
2384    public void userSwitched(int newUserId) {
2385        if (MULTIUSER_DEBUG) mNotificationPanelDebugText.setText("USER " + newUserId);
2386        animateCollapsePanels();
2387        updateNotificationIcons();
2388        resetUserSetupObserver();
2389    }
2390
2391    private void resetUserSetupObserver() {
2392        mContext.getContentResolver().unregisterContentObserver(mUserSetupObserver);
2393        mUserSetupObserver.onChange(false);
2394        mContext.getContentResolver().registerContentObserver(
2395                Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE), true,
2396                mUserSetupObserver,
2397                mCurrentUserId);
2398    }
2399
2400    private void setHeadsUpVisibility(boolean vis) {
2401        if (!ENABLE_HEADS_UP) return;
2402        if (DEBUG) Log.v(TAG, (vis ? "showing" : "hiding") + " heads up window");
2403        mHeadsUpNotificationView.setVisibility(vis ? View.VISIBLE : View.GONE);
2404        if (!vis) {
2405            if (DEBUG) Log.d(TAG, "setting heads up entry to null");
2406            mInterruptingNotificationEntry = null;
2407        }
2408    }
2409
2410    public void onHeadsUpDismissed() {
2411        if (mInterruptingNotificationEntry == null) return;
2412        mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
2413        if (mHeadsUpNotificationView.isClearable()) {
2414            try {
2415                mBarService.onNotificationClear(
2416                        mInterruptingNotificationEntry.notification.getPackageName(),
2417                        mInterruptingNotificationEntry.notification.getTag(),
2418                        mInterruptingNotificationEntry.notification.getId(),
2419                        mInterruptingNotificationEntry.notification.getUserId());
2420            } catch (android.os.RemoteException ex) {
2421                // oh well
2422            }
2423        }
2424    }
2425
2426    /**
2427     * Reload some of our resources when the configuration changes.
2428     *
2429     * We don't reload everything when the configuration changes -- we probably
2430     * should, but getting that smooth is tough.  Someday we'll fix that.  In the
2431     * meantime, just update the things that we know change.
2432     */
2433    void updateResources() {
2434        // Update the quick setting tiles
2435        if (mQSPanel != null) mQSPanel.updateResources();
2436
2437        loadDimens();
2438    }
2439
2440    protected void loadDimens() {
2441        final Resources res = mContext.getResources();
2442
2443        mNaturalBarHeight = res.getDimensionPixelSize(
2444                com.android.internal.R.dimen.status_bar_height);
2445
2446        int newIconSize = res.getDimensionPixelSize(
2447            com.android.internal.R.dimen.status_bar_icon_size);
2448        int newIconHPadding = res.getDimensionPixelSize(
2449            R.dimen.status_bar_icon_padding);
2450
2451        if (newIconHPadding != mIconHPadding || newIconSize != mIconSize) {
2452//            Log.d(TAG, "size=" + newIconSize + " padding=" + newIconHPadding);
2453            mIconHPadding = newIconHPadding;
2454            mIconSize = newIconSize;
2455            //reloadAllNotificationIcons(); // reload the tray
2456        }
2457
2458        mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore);
2459
2460        mSelfExpandVelocityPx = res.getDimension(R.dimen.self_expand_velocity);
2461        mSelfCollapseVelocityPx = res.getDimension(R.dimen.self_collapse_velocity);
2462        mFlingExpandMinVelocityPx = res.getDimension(R.dimen.fling_expand_min_velocity);
2463        mFlingCollapseMinVelocityPx = res.getDimension(R.dimen.fling_collapse_min_velocity);
2464
2465        mCollapseMinDisplayFraction = res.getFraction(R.dimen.collapse_min_display_fraction, 1, 1);
2466        mExpandMinDisplayFraction = res.getFraction(R.dimen.expand_min_display_fraction, 1, 1);
2467
2468        mExpandAccelPx = res.getDimension(R.dimen.expand_accel);
2469        mCollapseAccelPx = res.getDimension(R.dimen.collapse_accel);
2470
2471        mFlingGestureMaxXVelocityPx = res.getDimension(R.dimen.fling_gesture_max_x_velocity);
2472
2473        mFlingGestureMaxOutputVelocityPx = res.getDimension(R.dimen.fling_gesture_max_output_velocity);
2474
2475        mNotificationPanelGravity = res.getInteger(R.integer.notification_panel_layout_gravity);
2476        if (mNotificationPanelGravity <= 0) {
2477            mNotificationPanelGravity = Gravity.START | Gravity.TOP;
2478        }
2479
2480        mCarrierLabelHeight = res.getDimensionPixelSize(R.dimen.carrier_label_height);
2481        mStatusBarHeaderHeight = res.getDimensionPixelSize(R.dimen.status_bar_header_height);
2482
2483        mNotificationPanelMinHeightFrac = res.getFraction(R.dimen.notification_panel_min_height_frac, 1, 1);
2484        if (mNotificationPanelMinHeightFrac < 0f || mNotificationPanelMinHeightFrac > 1f) {
2485            mNotificationPanelMinHeightFrac = 0f;
2486        }
2487
2488        mHeadsUpNotificationDecay = res.getInteger(R.integer.heads_up_notification_decay);
2489        mRowMinHeight =  res.getDimensionPixelSize(R.dimen.notification_min_height);
2490        mRowMaxHeight =  res.getDimensionPixelSize(R.dimen.notification_max_height);
2491
2492        mKeyguardMaxNotificationCount = res.getInteger(R.integer.keyguard_max_notification_count);
2493
2494        if (false) Log.v(TAG, "updateResources");
2495    }
2496
2497    // Visibility reporting
2498
2499    @Override
2500    protected void visibilityChanged(boolean visible) {
2501        mVisible = visible;
2502        if (visible) {
2503            startNotificationLoggingIfScreenOnAndVisible();
2504        } else {
2505            stopNotificationLogging();
2506        }
2507        super.visibilityChanged(visible);
2508    }
2509
2510    private void stopNotificationLogging() {
2511        // Report all notifications as invisible and turn down the
2512        // reporter.
2513        if (!mCurrentlyVisibleNotifications.isEmpty()) {
2514            logNotificationVisibilityChanges(
2515                    Collections.<String>emptyList(), mCurrentlyVisibleNotifications);
2516            mCurrentlyVisibleNotifications.clear();
2517        }
2518        mHandler.removeCallbacks(mVisibilityReporter);
2519        mStackScroller.setChildLocationsChangedListener(null);
2520    }
2521
2522    private void startNotificationLoggingIfScreenOnAndVisible() {
2523        if (mVisible && mScreenOn) {
2524            mStackScroller.setChildLocationsChangedListener(mNotificationLocationsChangedListener);
2525            // Some transitions like mScreenOn=false -> mScreenOn=true don't
2526            // cause the scroller to emit child location events. Hence generate
2527            // one ourselves to guarantee that we're reporting visible
2528            // notifications.
2529            // (Note that in cases where the scroller does emit events, this
2530            // additional event doesn't break anything.)
2531            mNotificationLocationsChangedListener.onChildLocationsChanged(mStackScroller);
2532        }
2533    }
2534
2535    private void logNotificationVisibilityChanges(
2536            Collection<String> newlyVisible, Collection<String> noLongerVisible) {
2537        if (newlyVisible.isEmpty() && noLongerVisible.isEmpty()) {
2538            return;
2539        }
2540
2541        String[] newlyVisibleAr = newlyVisible.toArray(new String[newlyVisible.size()]);
2542        String[] noLongerVisibleAr = noLongerVisible.toArray(new String[noLongerVisible.size()]);
2543        try {
2544            mBarService.onNotificationVisibilityChanged(newlyVisibleAr, noLongerVisibleAr);
2545        } catch (RemoteException e) {
2546            // Ignore.
2547        }
2548    }
2549
2550    //
2551    // tracing
2552    //
2553
2554    void postStartTracing() {
2555        mHandler.postDelayed(mStartTracing, 3000);
2556    }
2557
2558    void vibrate() {
2559        android.os.Vibrator vib = (android.os.Vibrator)mContext.getSystemService(
2560                Context.VIBRATOR_SERVICE);
2561        vib.vibrate(250, AudioManager.STREAM_SYSTEM);
2562    }
2563
2564    Runnable mStartTracing = new Runnable() {
2565        public void run() {
2566            vibrate();
2567            SystemClock.sleep(250);
2568            Log.d(TAG, "startTracing");
2569            android.os.Debug.startMethodTracing("/data/statusbar-traces/trace");
2570            mHandler.postDelayed(mStopTracing, 10000);
2571        }
2572    };
2573
2574    Runnable mStopTracing = new Runnable() {
2575        public void run() {
2576            android.os.Debug.stopMethodTracing();
2577            Log.d(TAG, "stopTracing");
2578            vibrate();
2579        }
2580    };
2581
2582    @Override
2583    protected void haltTicker() {
2584        mTicker.halt();
2585    }
2586
2587    @Override
2588    protected boolean shouldDisableNavbarGestures() {
2589        return !isDeviceProvisioned()
2590                || mExpandedVisible
2591                || (mDisabled & StatusBarManager.DISABLE_SEARCH) != 0;
2592    }
2593
2594    public void postStartSettingsActivity(final Intent intent, int delay) {
2595        mHandler.postDelayed(new Runnable() {
2596            @Override
2597            public void run() {
2598                handleStartSettingsActivity(intent, true /*onlyProvisioned*/);
2599            }
2600        }, delay);
2601    }
2602
2603    private void handleStartSettingsActivity(Intent intent, boolean onlyProvisioned) {
2604        if (onlyProvisioned && !isDeviceProvisioned()) return;
2605        try {
2606            // Dismiss the lock screen when Settings starts.
2607            ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
2608        } catch (RemoteException e) {
2609        }
2610        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
2611        mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
2612        animateCollapsePanels();
2613    }
2614
2615    public void startSettingsActivity(String action) {
2616        postStartSettingsActivity(new Intent(action), 0);
2617    }
2618
2619    private static class FastColorDrawable extends Drawable {
2620        private final int mColor;
2621
2622        public FastColorDrawable(int color) {
2623            mColor = 0xff000000 | color;
2624        }
2625
2626        @Override
2627        public void draw(Canvas canvas) {
2628            canvas.drawColor(mColor, PorterDuff.Mode.SRC);
2629        }
2630
2631        @Override
2632        public void setAlpha(int alpha) {
2633        }
2634
2635        @Override
2636        public void setColorFilter(ColorFilter cf) {
2637        }
2638
2639        @Override
2640        public int getOpacity() {
2641            return PixelFormat.OPAQUE;
2642        }
2643
2644        @Override
2645        public void setBounds(int left, int top, int right, int bottom) {
2646        }
2647
2648        @Override
2649        public void setBounds(Rect bounds) {
2650        }
2651    }
2652
2653    @Override
2654    public void destroy() {
2655        super.destroy();
2656        if (mStatusBarWindow != null) {
2657            mWindowManager.removeViewImmediate(mStatusBarWindow);
2658            mStatusBarWindow = null;
2659        }
2660        if (mNavigationBarView != null) {
2661            mWindowManager.removeViewImmediate(mNavigationBarView);
2662            mNavigationBarView = null;
2663        }
2664        mContext.unregisterReceiver(mBroadcastReceiver);
2665    }
2666
2667    private boolean mDemoModeAllowed;
2668    private boolean mDemoMode;
2669    private DemoStatusIcons mDemoStatusIcons;
2670
2671    @Override
2672    public void dispatchDemoCommand(String command, Bundle args) {
2673        if (!mDemoModeAllowed) {
2674            mDemoModeAllowed = Settings.Global.getInt(mContext.getContentResolver(),
2675                    "sysui_demo_allowed", 0) != 0;
2676        }
2677        if (!mDemoModeAllowed) return;
2678        if (command.equals(COMMAND_ENTER)) {
2679            mDemoMode = true;
2680        } else if (command.equals(COMMAND_EXIT)) {
2681            mDemoMode = false;
2682            checkBarModes();
2683        } else if (!mDemoMode) {
2684            // automatically enter demo mode on first demo command
2685            dispatchDemoCommand(COMMAND_ENTER, new Bundle());
2686        }
2687        boolean modeChange = command.equals(COMMAND_ENTER) || command.equals(COMMAND_EXIT);
2688        if (modeChange || command.equals(COMMAND_CLOCK)) {
2689            dispatchDemoCommandToView(command, args, R.id.clock);
2690        }
2691        if (modeChange || command.equals(COMMAND_BATTERY)) {
2692            dispatchDemoCommandToView(command, args, R.id.battery);
2693        }
2694        if (modeChange || command.equals(COMMAND_STATUS)) {
2695            if (mDemoStatusIcons == null) {
2696                mDemoStatusIcons = new DemoStatusIcons(mStatusIcons, mIconSize);
2697            }
2698            mDemoStatusIcons.dispatchDemoCommand(command, args);
2699        }
2700        if (mNetworkController != null && (modeChange || command.equals(COMMAND_NETWORK))) {
2701            mNetworkController.dispatchDemoCommand(command, args);
2702        }
2703        if (modeChange || command.equals(COMMAND_NOTIFICATIONS)) {
2704            View notifications = mStatusBarView == null ? null
2705                    : mStatusBarView.findViewById(R.id.notification_icon_area);
2706            if (notifications != null) {
2707                String visible = args.getString("visible");
2708                int vis = mDemoMode && "false".equals(visible) ? View.INVISIBLE : View.VISIBLE;
2709                notifications.setVisibility(vis);
2710            }
2711        }
2712        if (command.equals(COMMAND_BARS)) {
2713            String mode = args.getString("mode");
2714            int barMode = "opaque".equals(mode) ? MODE_OPAQUE :
2715                    "translucent".equals(mode) ? MODE_TRANSLUCENT :
2716                    "semi-transparent".equals(mode) ? MODE_SEMI_TRANSPARENT :
2717                    -1;
2718            if (barMode != -1) {
2719                boolean animate = true;
2720                if (mStatusBarView != null) {
2721                    mStatusBarView.getBarTransitions().transitionTo(barMode, animate);
2722                }
2723                if (mNavigationBarView != null) {
2724                    mNavigationBarView.getBarTransitions().transitionTo(barMode, animate);
2725                }
2726            }
2727        }
2728    }
2729
2730    private void dispatchDemoCommandToView(String command, Bundle args, int id) {
2731        if (mStatusBarView == null) return;
2732        View v = mStatusBarView.findViewById(id);
2733        if (v instanceof DemoMode) {
2734            ((DemoMode)v).dispatchDemoCommand(command, args);
2735        }
2736    }
2737
2738    /**
2739     * @return The {@link StatusBarState} the status bar is in.
2740     */
2741    public int getBarState() {
2742        return mState;
2743    }
2744
2745    public void showKeyguard() {
2746        setBarState(StatusBarState.KEYGUARD);
2747        updateKeyguardState();
2748        instantExpandNotificationsPanel();
2749        mLeaveOpenOnKeyguardHide = false;
2750    }
2751
2752    public void hideKeyguard() {
2753        setBarState(StatusBarState.SHADE);
2754        if (mLeaveOpenOnKeyguardHide) {
2755            mLeaveOpenOnKeyguardHide = false;
2756            mNotificationPanel.animateToFullShade();
2757        } else {
2758            instantCollapseNotificationPanel();
2759        }
2760        updateKeyguardState();
2761    }
2762
2763    private void updatePublicMode() {
2764        setLockscreenPublicMode(mState == StatusBarState.KEYGUARD
2765                && mStatusBarKeyguardViewManager.isSecure());
2766    }
2767
2768    private void updateKeyguardState() {
2769        if (mState == StatusBarState.KEYGUARD) {
2770            mKeyguardStatusView.setVisibility(View.VISIBLE);
2771            mKeyguardIndicationTextView.setVisibility(View.VISIBLE);
2772            mKeyguardIndicationTextView.switchIndication(mKeyguardHotwordPhrase);
2773            mNotificationPanel.closeQs();
2774        } else {
2775            mKeyguardStatusView.setVisibility(View.GONE);
2776            mKeyguardIndicationTextView.setVisibility(View.GONE);
2777        }
2778        if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
2779            mKeyguardBottomArea.setVisibility(View.VISIBLE);
2780            mHeader.setKeyguardShowing(true);
2781            mNotificationPanel.setKeyguardShowing(true);
2782            mScrimController.setKeyguardShowing(true);
2783        } else {
2784            mKeyguardBottomArea.setVisibility(View.GONE);
2785            mHeader.setKeyguardShowing(false);
2786            mNotificationPanel.setKeyguardShowing(false);
2787            mScrimController.setKeyguardShowing(false);
2788        }
2789
2790        updateStackScrollerState();
2791        updatePublicMode();
2792        updateRowStates();
2793        updateSpeedBump();
2794        checkBarModes();
2795        updateNotificationIcons();
2796        updateCarrierLabelVisibility(false);
2797    }
2798
2799    public void updateStackScrollerState() {
2800        mStackScroller.setDimmed(mState == StatusBarState.KEYGUARD, false /* animate */);
2801    }
2802
2803    public void userActivity() {
2804        mHandler.removeCallbacks(mUserActivity);
2805        mHandler.post(mUserActivity);
2806    }
2807
2808    public boolean interceptMediaKey(KeyEvent event) {
2809        return mState == StatusBarState.KEYGUARD
2810                && mStatusBarKeyguardViewManager.interceptMediaKey(event);
2811    }
2812
2813    public boolean onMenuPressed() {
2814        return mState == StatusBarState.KEYGUARD && mStatusBarKeyguardViewManager.onMenuPressed();
2815    }
2816
2817    public boolean onBackPressed() {
2818        if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
2819            return mStatusBarKeyguardViewManager.onBackPressed();
2820        } else {
2821            animateCollapsePanels();
2822            return true;
2823        }
2824    }
2825
2826    private void showBouncer() {
2827        if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
2828            mStatusBarKeyguardViewManager.dismiss();
2829        }
2830    }
2831
2832    private void instantExpandNotificationsPanel() {
2833
2834        // Make our window larger and the panel visible.
2835        makeExpandedVisible(true);
2836        mNotificationPanel.setVisibility(View.VISIBLE);
2837
2838        // Wait for window manager to pickup the change, so we know the maximum height of the panel
2839        // then.
2840        mNotificationPanel.getViewTreeObserver().addOnGlobalLayoutListener(
2841                new ViewTreeObserver.OnGlobalLayoutListener() {
2842            @Override
2843            public void onGlobalLayout() {
2844                if (mStatusBarWindow.getHeight() != getStatusBarHeight()) {
2845                    mNotificationPanel.getViewTreeObserver().removeOnGlobalLayoutListener(this);
2846                    mNotificationPanel.setExpandedFraction(1);
2847                }
2848            }
2849        });
2850    }
2851
2852    private void instantCollapseNotificationPanel() {
2853        mNotificationPanel.setExpandedFraction(0);
2854    }
2855
2856    @Override
2857    public void onActivated(View view) {
2858        userActivity();
2859        mKeyguardIndicationTextView.switchIndication(R.string.notification_tap_again);
2860        mStackScroller.setActivatedChild(view);
2861    }
2862
2863    /**
2864     * @param state The {@link StatusBarState} to set.
2865     */
2866    public void setBarState(int state) {
2867        mState = state;
2868        mStatusBarWindowManager.setStatusBarState(state);
2869    }
2870
2871    @Override
2872    public void onActivationReset(View view) {
2873        if (view == mStackScroller.getActivatedChild()) {
2874            mKeyguardIndicationTextView.switchIndication(mKeyguardHotwordPhrase);
2875            mStackScroller.setActivatedChild(null);
2876        }
2877    }
2878
2879    public void onTrackingStarted() {
2880        if (mState == StatusBarState.KEYGUARD) {
2881            mKeyguardIndicationTextView.switchIndication(R.string.keyguard_unlock);
2882        }
2883    }
2884
2885    public void onTrackingStopped() {
2886        if (mState == StatusBarState.KEYGUARD) {
2887            mKeyguardIndicationTextView.switchIndication(mKeyguardHotwordPhrase);
2888        }
2889    }
2890
2891    @Override
2892    protected int getMaxKeyguardNotifications() {
2893        return mKeyguardMaxNotificationCount;
2894    }
2895
2896    public NavigationBarView getNavigationBarView() {
2897        return mNavigationBarView;
2898    }
2899
2900    // ---------------------- DragDownHelper.OnDragDownListener ------------------------------------
2901
2902    @Override
2903    public void onDraggedDown(View startingChild) {
2904        goToLockedShade(startingChild);
2905    }
2906
2907    @Override
2908    public void onDragDownReset() {
2909        mStackScroller.setDimmed(true /* dimmed */, true /* animated */);
2910    }
2911
2912    public void onThresholdReached() {
2913        mStackScroller.setDimmed(false /* dimmed */, true /* animate */);
2914    }
2915
2916    /**
2917     * If secure with redaction: Show bouncer, go to unlocked shade.
2918     *
2919     * <p>If secure without redaction or no security: Go to {@link StatusBarState#SHADE_LOCKED}.</p>
2920     *
2921     * @param expandView The view to expand after going to the shade.
2922     */
2923    public void goToLockedShade(View expandView) {
2924        if (expandView instanceof ExpandableNotificationRow) {
2925            ExpandableNotificationRow row = (ExpandableNotificationRow) expandView;
2926            row.setUserExpanded(true);
2927        }
2928        if (isLockscreenPublicMode() && !userAllowsPrivateNotificationsInPublic(mCurrentUserId)) {
2929            mLeaveOpenOnKeyguardHide = true;
2930            showBouncer();
2931        } else {
2932            mNotificationPanel.animateToFullShade();
2933            setBarState(StatusBarState.SHADE_LOCKED);
2934            updateKeyguardState();
2935        }
2936    }
2937
2938    /**
2939     * @return a ViewGroup that spans the entire panel which contains the quick settings
2940     */
2941    public ViewGroup getQuickSettingsOverlayParent() {
2942        return mNotificationPanel;
2943    }
2944
2945    public LinearLayout getSystemIcons() {
2946        return mSystemIcons;
2947    }
2948
2949    /**
2950     * Reattaches the system icons to its normal parent in collapsed status bar.
2951     */
2952    public void reattachSystemIcons() {
2953        mSystemIconArea.addView(mSystemIcons, 0);
2954    }
2955
2956    public void onScreenTurnedOff() {
2957        mStackScroller.setAnimationsEnabled(false);
2958    }
2959
2960    public void onScreenTurnedOn() {
2961        mStackScroller.setAnimationsEnabled(true);
2962    }
2963
2964    private final Runnable mUserActivity = new Runnable() {
2965        @Override
2966        public void run() {
2967            if (mState == StatusBarState.KEYGUARD) {
2968                mKeyguardViewMediatorCallback.userActivity();
2969            }
2970        }
2971    };
2972}
2973