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