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