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