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