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 android.animation.Animator;
     20 import android.animation.Animator.AnimatorListener;
     21 import android.animation.AnimatorListenerAdapter;
     22 import android.animation.AnimatorSet;
     23 import android.animation.ObjectAnimator;
     24 import android.app.ActivityManager;
     25 import android.app.ActivityManagerNative;
     26 import android.app.Dialog;
     27 import android.app.KeyguardManager;
     28 import android.app.Notification;
     29 import android.app.PendingIntent;
     30 import android.app.StatusBarManager;
     31 import android.content.BroadcastReceiver;
     32 import android.content.Context;
     33 import android.content.Intent;
     34 import android.content.IntentFilter;
     35 import android.content.res.Configuration;
     36 import android.content.res.Resources;
     37 import android.graphics.Canvas;
     38 import android.graphics.ColorFilter;
     39 import android.graphics.PixelFormat;
     40 import android.graphics.PorterDuff;
     41 import android.graphics.Rect;
     42 import android.graphics.drawable.Drawable;
     43 import android.graphics.drawable.NinePatchDrawable;
     44 import android.inputmethodservice.InputMethodService;
     45 import android.os.IBinder;
     46 import android.os.Message;
     47 import android.os.RemoteException;
     48 import android.os.ServiceManager;
     49 import android.os.SystemClock;
     50 import android.provider.Settings;
     51 import android.util.DisplayMetrics;
     52 import android.util.Log;
     53 import android.util.Slog;
     54 import android.view.Choreographer;
     55 import android.view.Display;
     56 import android.view.Gravity;
     57 import android.view.IWindowManager;
     58 import android.view.KeyEvent;
     59 import android.view.MotionEvent;
     60 import android.view.VelocityTracker;
     61 import android.view.View;
     62 import android.view.ViewGroup;
     63 import android.view.ViewGroup.LayoutParams;
     64 import android.view.WindowManager;
     65 import android.view.WindowManagerImpl;
     66 import android.view.animation.AccelerateInterpolator;
     67 import android.view.animation.Animation;
     68 import android.view.animation.AnimationUtils;
     69 import android.view.animation.DecelerateInterpolator;
     70 import android.widget.FrameLayout;
     71 import android.widget.ImageView;
     72 import android.widget.LinearLayout;
     73 import android.widget.ScrollView;
     74 import android.widget.TextView;
     75 import com.android.internal.statusbar.StatusBarIcon;
     76 import com.android.internal.statusbar.StatusBarNotification;
     77 import com.android.systemui.R;
     78 import com.android.systemui.recent.RecentTasksLoader;
     79 import com.android.systemui.statusbar.BaseStatusBar;
     80 import com.android.systemui.statusbar.NotificationData;
     81 import com.android.systemui.statusbar.NotificationData.Entry;
     82 import com.android.systemui.statusbar.CommandQueue;
     83 import com.android.systemui.statusbar.RotationToggle;
     84 import com.android.systemui.statusbar.SignalClusterView;
     85 import com.android.systemui.statusbar.StatusBarIconView;
     86 import com.android.systemui.statusbar.policy.BatteryController;
     87 import com.android.systemui.statusbar.policy.DateView;
     88 import com.android.systemui.statusbar.policy.IntruderAlertView;
     89 import com.android.systemui.statusbar.policy.LocationController;
     90 import com.android.systemui.statusbar.policy.OnSizeChangedListener;
     91 import com.android.systemui.statusbar.policy.NetworkController;
     92 import com.android.systemui.statusbar.policy.NotificationRowLayout;
     93 
     94 import java.io.FileDescriptor;
     95 import java.io.PrintWriter;
     96 import java.util.ArrayList;
     97 
     98 public class PhoneStatusBar extends BaseStatusBar {
     99     static final String TAG = "PhoneStatusBar";
    100     public static final boolean DEBUG = false;
    101     public static final boolean SPEW = DEBUG;
    102     public static final boolean DUMPTRUCK = true; // extra dumpsys info
    103 
    104     // additional instrumentation for testing purposes; intended to be left on during development
    105     public static final boolean CHATTY = DEBUG;
    106 
    107     public static final String ACTION_STATUSBAR_START
    108             = "com.android.internal.policy.statusbar.START";
    109 
    110     private static final boolean DIM_BEHIND_EXPANDED_PANEL = true;
    111     private static final boolean SHOW_CARRIER_LABEL = true;
    112 
    113     private static final int MSG_OPEN_NOTIFICATION_PANEL = 1000;
    114     private static final int MSG_CLOSE_NOTIFICATION_PANEL = 1001;
    115     // 1020-1030 reserved for BaseStatusBar
    116 
    117     // will likely move to a resource or other tunable param at some point
    118     private static final int INTRUDER_ALERT_DECAY_MS = 0; // disabled, was 10000;
    119 
    120     private static final boolean CLOSE_PANEL_WHEN_EMPTIED = true;
    121 
    122     private static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10; // see NotificationManagerService
    123     private static final int HIDE_ICONS_BELOW_SCORE = Notification.PRIORITY_LOW * NOTIFICATION_PRIORITY_MULTIPLIER;
    124 
    125     // fling gesture tuning parameters, scaled to display density
    126     private float mSelfExpandVelocityPx; // classic value: 2000px/s
    127     private float mSelfCollapseVelocityPx; // classic value: 2000px/s (will be negated to collapse "up")
    128     private float mFlingExpandMinVelocityPx; // classic value: 200px/s
    129     private float mFlingCollapseMinVelocityPx; // classic value: 200px/s
    130     private float mCollapseMinDisplayFraction; // classic value: 0.08 (25px/min(320px,480px) on G1)
    131     private float mExpandMinDisplayFraction; // classic value: 0.5 (drag open halfway to expand)
    132     private float mFlingGestureMaxXVelocityPx; // classic value: 150px/s
    133 
    134     private float mExpandAccelPx; // classic value: 2000px/s/s
    135     private float mCollapseAccelPx; // classic value: 2000px/s/s (will be negated to collapse "up")
    136 
    137     private float mFlingGestureMaxOutputVelocityPx; // how fast can it really go? (should be a little
    138                                                     // faster than mSelfCollapseVelocityPx)
    139 
    140     PhoneStatusBarPolicy mIconPolicy;
    141 
    142     // These are no longer handled by the policy, because we need custom strategies for them
    143     BatteryController mBatteryController;
    144     LocationController mLocationController;
    145     NetworkController mNetworkController;
    146 
    147     int mNaturalBarHeight = -1;
    148     int mIconSize = -1;
    149     int mIconHPadding = -1;
    150     Display mDisplay;
    151 
    152     IWindowManager mWindowManager;
    153 
    154     StatusBarWindowView mStatusBarWindow;
    155     PhoneStatusBarView mStatusBarView;
    156 
    157     int mPixelFormat;
    158     Object mQueueLock = new Object();
    159 
    160     // icons
    161     LinearLayout mIcons;
    162     IconMerger mNotificationIcons;
    163     View mMoreIcon;
    164     LinearLayout mStatusIcons;
    165 
    166     // expanded notifications
    167     View mNotificationPanel; // the sliding/resizing panel within the notification window
    168     ScrollView mScrollView;
    169     View mExpandedContents;
    170     int mNotificationPanelMarginBottomPx, mNotificationPanelMarginLeftPx;
    171     final Rect mNotificationPanelBackgroundPadding = new Rect();
    172     int mNotificationPanelGravity;
    173     int mNotificationPanelMinHeight;
    174     boolean mNotificationPanelIsFullScreenWidth;
    175 
    176     // top bar
    177     View mClearButton;
    178     View mSettingsButton;
    179     RotationToggle mRotationButton;
    180 
    181     // carrier/wifi label
    182     private TextView mCarrierLabel;
    183     private boolean mCarrierLabelVisible = false;
    184     private int mCarrierLabelHeight;
    185 
    186     // drag bar
    187     CloseDragHandle mCloseView;
    188     private int mCloseViewHeight;
    189 
    190     // position
    191     int[] mPositionTmp = new int[2];
    192     boolean mExpanded;
    193     boolean mExpandedVisible;
    194 
    195     // the date view
    196     DateView mDateView;
    197 
    198     // for immersive activities
    199     private IntruderAlertView mIntruderAlertView;
    200 
    201     // on-screen navigation buttons
    202     private NavigationBarView mNavigationBarView = null;
    203 
    204     // the tracker view
    205     int mTrackingPosition; // the position of the top of the tracking view.
    206     private boolean mPanelSlightlyVisible;
    207 
    208     // ticker
    209     private Ticker mTicker;
    210     private View mTickerView;
    211     private boolean mTicking;
    212 
    213     // Tracking finger for opening/closing.
    214     int mEdgeBorder; // corresponds to R.dimen.status_bar_edge_ignore
    215     boolean mTracking;
    216     VelocityTracker mVelocityTracker;
    217 
    218     Choreographer mChoreographer;
    219     boolean mAnimating;
    220     boolean mClosing; // only valid when mAnimating; indicates the initial acceleration
    221     float mAnimY;
    222     float mAnimVel;
    223     float mAnimAccel;
    224     long mAnimLastTimeNanos;
    225     boolean mAnimatingReveal = false;
    226     int mViewDelta;
    227     float mFlingVelocity;
    228     int mFlingY;
    229     int[] mAbsPos = new int[2];
    230     Runnable mPostCollapseCleanup = null;
    231 
    232     private AnimatorSet mLightsOutAnimation;
    233     private AnimatorSet mLightsOnAnimation;
    234 
    235     // for disabling the status bar
    236     int mDisabled = 0;
    237 
    238     // tracking calls to View.setSystemUiVisibility()
    239     int mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE;
    240 
    241     DisplayMetrics mDisplayMetrics = new DisplayMetrics();
    242 
    243     private int mNavigationIconHints = 0;
    244     private final Animator.AnimatorListener mMakeIconsInvisible = new AnimatorListenerAdapter() {
    245         @Override
    246         public void onAnimationEnd(Animator animation) {
    247             // double-check to avoid races
    248             if (mIcons.getAlpha() == 0) {
    249                 Slog.d(TAG, "makeIconsInvisible");
    250                 mIcons.setVisibility(View.INVISIBLE);
    251             }
    252         }
    253     };
    254 
    255     private final Runnable mStartRevealAnimation = new Runnable() {
    256         @Override
    257         public void run() {
    258             mAnimAccel = mExpandAccelPx;
    259             mAnimVel = mFlingExpandMinVelocityPx;
    260             mAnimY = getStatusBarHeight();
    261             updateExpandedViewPos((int)mAnimY);
    262 
    263             mAnimating = true;
    264             mAnimatingReveal = true;
    265             resetLastAnimTime();
    266             mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION,
    267                 mAnimationCallback, null);
    268             mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION,
    269                 mRevealAnimationCallback, null);
    270             mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION,
    271                 mRevealAnimationCallback, null);
    272         }
    273     };
    274 
    275     private final Runnable mPerformSelfExpandFling = new Runnable() {
    276         @Override
    277         public void run() {
    278             performFling(0, mSelfExpandVelocityPx, true);
    279         }
    280     };
    281 
    282     private final Runnable mPerformFling = new Runnable() {
    283         @Override
    284         public void run() {
    285             performFling(mFlingY + mViewDelta, mFlingVelocity, false);
    286         }
    287     };
    288 
    289     private class ExpandedDialog extends Dialog {
    290         ExpandedDialog(Context context) {
    291             super(context, com.android.internal.R.style.Theme_Translucent_NoTitleBar);
    292         }
    293 
    294         @Override
    295         public boolean dispatchKeyEvent(KeyEvent event) {
    296             boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
    297             switch (event.getKeyCode()) {
    298             case KeyEvent.KEYCODE_BACK:
    299                 if (!down) {
    300                     animateCollapse();
    301                 }
    302                 return true;
    303             }
    304             return super.dispatchKeyEvent(event);
    305         }
    306     }
    307 
    308     @Override
    309     public void start() {
    310         mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
    311                 .getDefaultDisplay();
    312 
    313         mWindowManager = IWindowManager.Stub.asInterface(
    314                 ServiceManager.getService(Context.WINDOW_SERVICE));
    315 
    316         super.start(); // calls createAndAddWindows()
    317 
    318         addNavigationBar();
    319 
    320         if (ENABLE_INTRUDERS) addIntruderView();
    321 
    322         // Lastly, call to the icon policy to install/update all the icons.
    323         mIconPolicy = new PhoneStatusBarPolicy(mContext);
    324     }
    325 
    326     // ================================================================================
    327     // Constructing the view
    328     // ================================================================================
    329     protected PhoneStatusBarView makeStatusBarView() {
    330         final Context context = mContext;
    331 
    332         Resources res = context.getResources();
    333 
    334         updateDisplaySize(); // populates mDisplayMetrics
    335         loadDimens();
    336 
    337         mIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size);
    338 
    339         mStatusBarWindow = (StatusBarWindowView) View.inflate(context,
    340                 R.layout.super_status_bar, null);
    341         if (DEBUG) {
    342             mStatusBarWindow.setBackgroundColor(0x6000FF80);
    343         }
    344         mStatusBarWindow.mService = this;
    345         mStatusBarWindow.setOnTouchListener(new View.OnTouchListener() {
    346             @Override
    347             public boolean onTouch(View v, MotionEvent event) {
    348                 if (event.getAction() == MotionEvent.ACTION_DOWN) {
    349                     if (mExpanded && !mAnimating) {
    350                         animateCollapse();
    351                     }
    352                 }
    353                 return mStatusBarWindow.onTouchEvent(event);
    354             }});
    355 
    356         mStatusBarView = (PhoneStatusBarView) mStatusBarWindow.findViewById(R.id.status_bar);
    357         mNotificationPanel = mStatusBarWindow.findViewById(R.id.notification_panel);
    358         // don't allow clicks on the panel to pass through to the background where they will cause the panel to close
    359         mNotificationPanel.setOnTouchListener(new View.OnTouchListener() {
    360             @Override
    361             public boolean onTouch(View v, MotionEvent event) {
    362                 return true;
    363             }
    364         });
    365         mNotificationPanelIsFullScreenWidth =
    366             (mNotificationPanel.getLayoutParams().width == ViewGroup.LayoutParams.MATCH_PARENT);
    367         mNotificationPanel.setSystemUiVisibility(
    368                   View.STATUS_BAR_DISABLE_NOTIFICATION_TICKER
    369                 | (mNotificationPanelIsFullScreenWidth ? 0 : View.STATUS_BAR_DISABLE_SYSTEM_INFO));
    370 
    371         if (!ActivityManager.isHighEndGfx(mDisplay)) {
    372             mStatusBarWindow.setBackground(null);
    373             mNotificationPanel.setBackground(new FastColorDrawable(context.getResources().getColor(
    374                     R.color.notification_panel_solid_background)));
    375         }
    376         if (ENABLE_INTRUDERS) {
    377             mIntruderAlertView = (IntruderAlertView) View.inflate(context, R.layout.intruder_alert, null);
    378             mIntruderAlertView.setVisibility(View.GONE);
    379             mIntruderAlertView.setBar(this);
    380         }
    381 
    382         updateShowSearchHoldoff();
    383 
    384         mStatusBarView.mService = this;
    385 
    386         mChoreographer = Choreographer.getInstance();
    387 
    388         try {
    389             boolean showNav = mWindowManager.hasNavigationBar();
    390             if (DEBUG) Slog.v(TAG, "hasNavigationBar=" + showNav);
    391             if (showNav) {
    392                 mNavigationBarView =
    393                     (NavigationBarView) View.inflate(context, R.layout.navigation_bar, null);
    394 
    395                 mNavigationBarView.setDisabledFlags(mDisabled);
    396                 mNavigationBarView.setBar(this);
    397             }
    398         } catch (RemoteException ex) {
    399             // no window manager? good luck with that
    400         }
    401 
    402         // figure out which pixel-format to use for the status bar.
    403         mPixelFormat = PixelFormat.OPAQUE;
    404         mStatusIcons = (LinearLayout)mStatusBarView.findViewById(R.id.statusIcons);
    405         mNotificationIcons = (IconMerger)mStatusBarView.findViewById(R.id.notificationIcons);
    406         mNotificationIcons.setOverflowIndicator(mMoreIcon);
    407         mIcons = (LinearLayout)mStatusBarView.findViewById(R.id.icons);
    408         mTickerView = mStatusBarView.findViewById(R.id.ticker);
    409 
    410         mPile = (NotificationRowLayout)mStatusBarWindow.findViewById(R.id.latestItems);
    411         mPile.setLayoutTransitionsEnabled(false);
    412         mPile.setLongPressListener(getNotificationLongClicker());
    413         if (SHOW_CARRIER_LABEL) {
    414             mPile.setOnSizeChangedListener(new OnSizeChangedListener() {
    415                 @Override
    416                 public void onSizeChanged(View view, int w, int h, int oldw, int oldh) {
    417                     updateCarrierLabelVisibility(false);
    418                 }
    419             });
    420         }
    421         mExpandedContents = mPile; // was: expanded.findViewById(R.id.notificationLinearLayout);
    422 
    423         mClearButton = mStatusBarWindow.findViewById(R.id.clear_all_button);
    424         mClearButton.setOnClickListener(mClearButtonListener);
    425         mClearButton.setAlpha(0f);
    426         mClearButton.setVisibility(View.INVISIBLE);
    427         mClearButton.setEnabled(false);
    428         mDateView = (DateView)mStatusBarWindow.findViewById(R.id.date);
    429         mSettingsButton = mStatusBarWindow.findViewById(R.id.settings_button);
    430         mSettingsButton.setOnClickListener(mSettingsButtonListener);
    431         mRotationButton = (RotationToggle) mStatusBarWindow.findViewById(R.id.rotation_lock_button);
    432 
    433         mCarrierLabel = (TextView)mStatusBarWindow.findViewById(R.id.carrier_label);
    434         mCarrierLabel.setVisibility(mCarrierLabelVisible ? View.VISIBLE : View.INVISIBLE);
    435 
    436         mScrollView = (ScrollView)mStatusBarWindow.findViewById(R.id.scroll);
    437         mScrollView.setVerticalScrollBarEnabled(false); // less drawing during pulldowns
    438 
    439         mTicker = new MyTicker(context, mStatusBarView);
    440 
    441         TickerView tickerView = (TickerView)mStatusBarView.findViewById(R.id.tickerText);
    442         tickerView.mTicker = mTicker;
    443 
    444         mCloseView = (CloseDragHandle)mStatusBarWindow.findViewById(R.id.close);
    445         mCloseView.mService = this;
    446         mCloseViewHeight = res.getDimensionPixelSize(R.dimen.close_handle_height);
    447 
    448         mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore);
    449 
    450         // set the inital view visibility
    451         setAreThereNotifications();
    452 
    453         // Other icons
    454         mLocationController = new LocationController(mContext); // will post a notification
    455         mBatteryController = new BatteryController(mContext);
    456         mBatteryController.addIconView((ImageView)mStatusBarView.findViewById(R.id.battery));
    457         mNetworkController = new NetworkController(mContext);
    458         final SignalClusterView signalCluster =
    459                 (SignalClusterView)mStatusBarView.findViewById(R.id.signal_cluster);
    460 
    461         mNetworkController.addSignalCluster(signalCluster);
    462         signalCluster.setNetworkController(mNetworkController);
    463 
    464         if (SHOW_CARRIER_LABEL) {
    465             // for mobile devices, we always show mobile connection info here (SPN/PLMN)
    466             // for other devices, we show whatever network is connected
    467             if (mNetworkController.hasMobileDataFeature()) {
    468                 mNetworkController.addMobileLabelView(mCarrierLabel);
    469             } else {
    470                 mNetworkController.addCombinedLabelView(mCarrierLabel);
    471             }
    472         }
    473 
    474 //        final ImageView wimaxRSSI =
    475 //                (ImageView)sb.findViewById(R.id.wimax_signal);
    476 //        if (wimaxRSSI != null) {
    477 //            mNetworkController.addWimaxIconView(wimaxRSSI);
    478 //        }
    479         // Recents Panel
    480         mRecentTasksLoader = new RecentTasksLoader(context);
    481         updateRecentsPanel();
    482 
    483         // receive broadcasts
    484         IntentFilter filter = new IntentFilter();
    485         filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
    486         filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
    487         filter.addAction(Intent.ACTION_SCREEN_OFF);
    488         context.registerReceiver(mBroadcastReceiver, filter);
    489 
    490         return mStatusBarView;
    491     }
    492 
    493     @Override
    494     protected WindowManager.LayoutParams getRecentsLayoutParams(LayoutParams layoutParams) {
    495         boolean opaque = false;
    496         WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
    497                 layoutParams.width,
    498                 layoutParams.height,
    499                 WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
    500                 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
    501                 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
    502                 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
    503                 (opaque ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT));
    504         if (ActivityManager.isHighEndGfx(mDisplay)) {
    505             lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
    506         } else {
    507             lp.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND;
    508             lp.dimAmount = 0.75f;
    509         }
    510         lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
    511         lp.setTitle("RecentsPanel");
    512         lp.windowAnimations = com.android.internal.R.style.Animation_RecentApplications;
    513         lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED
    514         | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
    515         return lp;
    516     }
    517 
    518     @Override
    519     protected WindowManager.LayoutParams getSearchLayoutParams(LayoutParams layoutParams) {
    520         boolean opaque = false;
    521         WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
    522                 LayoutParams.MATCH_PARENT,
    523                 LayoutParams.MATCH_PARENT,
    524                 WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
    525                 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
    526                 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
    527                 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
    528                 (opaque ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT));
    529         if (ActivityManager.isHighEndGfx(mDisplay)) {
    530             lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
    531         }
    532         lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
    533         lp.setTitle("SearchPanel");
    534         // TODO: Define custom animation for Search panel
    535         lp.windowAnimations = com.android.internal.R.style.Animation_RecentApplications;
    536         lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED
    537         | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
    538         return lp;
    539     }
    540 
    541     protected void updateRecentsPanel() {
    542         super.updateRecentsPanel(R.layout.status_bar_recent_panel);
    543         // Make .03 alpha the minimum so you always see the item a bit-- slightly below
    544         // .03, the item disappears entirely (as if alpha = 0) and that discontinuity looks
    545         // a bit jarring
    546         mRecentsPanel.setMinSwipeAlpha(0.03f);
    547         if (mNavigationBarView != null) {
    548             mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPanel);
    549         }
    550     }
    551 
    552     @Override
    553     protected void updateSearchPanel() {
    554         super.updateSearchPanel();
    555         mSearchPanelView.setStatusBarView(mNavigationBarView);
    556         mNavigationBarView.setDelegateView(mSearchPanelView);
    557     }
    558 
    559     @Override
    560     public void showSearchPanel() {
    561         super.showSearchPanel();
    562         WindowManager.LayoutParams lp =
    563             (android.view.WindowManager.LayoutParams) mNavigationBarView.getLayoutParams();
    564         lp.flags &= ~WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
    565         WindowManagerImpl.getDefault().updateViewLayout(mNavigationBarView, lp);
    566     }
    567 
    568     @Override
    569     public void hideSearchPanel() {
    570         super.hideSearchPanel();
    571         WindowManager.LayoutParams lp =
    572             (android.view.WindowManager.LayoutParams) mNavigationBarView.getLayoutParams();
    573         lp.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
    574         WindowManagerImpl.getDefault().updateViewLayout(mNavigationBarView, lp);
    575     }
    576 
    577     protected int getStatusBarGravity() {
    578         return Gravity.TOP | Gravity.FILL_HORIZONTAL;
    579     }
    580 
    581     public int getStatusBarHeight() {
    582         if (mNaturalBarHeight < 0) {
    583             final Resources res = mContext.getResources();
    584             mNaturalBarHeight =
    585                     res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
    586         }
    587         return mNaturalBarHeight;
    588     }
    589 
    590     private int getCloseViewHeight() {
    591         return mCloseViewHeight;
    592     }
    593 
    594     private View.OnClickListener mRecentsClickListener = new View.OnClickListener() {
    595         public void onClick(View v) {
    596             toggleRecentApps();
    597         }
    598     };
    599 
    600     private int mShowSearchHoldoff = 0;
    601     private Runnable mShowSearchPanel = new Runnable() {
    602         public void run() {
    603             showSearchPanel();
    604         }
    605     };
    606 
    607     View.OnTouchListener mHomeSearchActionListener = new View.OnTouchListener() {
    608         public boolean onTouch(View v, MotionEvent event) {
    609             switch(event.getAction()) {
    610             case MotionEvent.ACTION_DOWN:
    611                 if (!shouldDisableNavbarGestures() && !inKeyguardRestrictedInputMode()) {
    612                     mHandler.removeCallbacks(mShowSearchPanel);
    613                     mHandler.postDelayed(mShowSearchPanel, mShowSearchHoldoff);
    614                 }
    615             break;
    616 
    617             case MotionEvent.ACTION_UP:
    618             case MotionEvent.ACTION_CANCEL:
    619                 mHandler.removeCallbacks(mShowSearchPanel);
    620             break;
    621         }
    622         return false;
    623         }
    624     };
    625 
    626     private void prepareNavigationBarView() {
    627         mNavigationBarView.reorient();
    628 
    629         mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener);
    630         mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPanel);
    631         mNavigationBarView.getHomeButton().setOnTouchListener(mHomeSearchActionListener);
    632         updateSearchPanel();
    633     }
    634 
    635     // For small-screen devices (read: phones) that lack hardware navigation buttons
    636     private void addNavigationBar() {
    637         if (DEBUG) Slog.v(TAG, "addNavigationBar: about to add " + mNavigationBarView);
    638         if (mNavigationBarView == null) return;
    639 
    640         prepareNavigationBarView();
    641 
    642         WindowManagerImpl.getDefault().addView(
    643                 mNavigationBarView, getNavigationBarLayoutParams());
    644     }
    645 
    646     private void repositionNavigationBar() {
    647         if (mNavigationBarView == null) return;
    648 
    649         prepareNavigationBarView();
    650 
    651         WindowManagerImpl.getDefault().updateViewLayout(
    652                 mNavigationBarView, getNavigationBarLayoutParams());
    653     }
    654 
    655     private WindowManager.LayoutParams getNavigationBarLayoutParams() {
    656         WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
    657                 LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
    658                 WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
    659                     0
    660                     | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
    661                     | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
    662                     | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
    663                     | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
    664                 PixelFormat.OPAQUE);
    665         // this will allow the navbar to run in an overlay on devices that support this
    666         if (ActivityManager.isHighEndGfx(mDisplay)) {
    667             lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
    668         }
    669 
    670         lp.setTitle("NavigationBar");
    671         lp.windowAnimations = 0;
    672         return lp;
    673     }
    674 
    675     private void addIntruderView() {
    676         final int height = getStatusBarHeight();
    677 
    678         WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
    679                 ViewGroup.LayoutParams.MATCH_PARENT,
    680                 ViewGroup.LayoutParams.WRAP_CONTENT,
    681                 WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL, // above the status bar!
    682                 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
    683                     | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
    684                     | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
    685                     | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
    686                     | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
    687                     | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
    688                 PixelFormat.TRANSLUCENT);
    689         lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
    690         //lp.y += height * 1.5; // FIXME
    691         lp.setTitle("IntruderAlert");
    692         lp.packageName = mContext.getPackageName();
    693         lp.windowAnimations = R.style.Animation_StatusBar_IntruderAlert;
    694 
    695         WindowManagerImpl.getDefault().addView(mIntruderAlertView, lp);
    696     }
    697 
    698     public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) {
    699         if (SPEW) Slog.d(TAG, "addIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex
    700                 + " icon=" + icon);
    701         StatusBarIconView view = new StatusBarIconView(mContext, slot, null);
    702         view.set(icon);
    703         mStatusIcons.addView(view, viewIndex, new LinearLayout.LayoutParams(mIconSize, mIconSize));
    704     }
    705 
    706     public void updateIcon(String slot, int index, int viewIndex,
    707             StatusBarIcon old, StatusBarIcon icon) {
    708         if (SPEW) Slog.d(TAG, "updateIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex
    709                 + " old=" + old + " icon=" + icon);
    710         StatusBarIconView view = (StatusBarIconView)mStatusIcons.getChildAt(viewIndex);
    711         view.set(icon);
    712     }
    713 
    714     public void removeIcon(String slot, int index, int viewIndex) {
    715         if (SPEW) Slog.d(TAG, "removeIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex);
    716         mStatusIcons.removeViewAt(viewIndex);
    717     }
    718 
    719     public void addNotification(IBinder key, StatusBarNotification notification) {
    720         /* if (DEBUG) */ Slog.d(TAG, "addNotification score=" + notification.score);
    721         StatusBarIconView iconView = addNotificationViews(key, notification);
    722         if (iconView == null) return;
    723 
    724         boolean immersive = false;
    725         try {
    726             immersive = ActivityManagerNative.getDefault().isTopActivityImmersive();
    727             if (DEBUG) {
    728                 Slog.d(TAG, "Top activity is " + (immersive?"immersive":"not immersive"));
    729             }
    730         } catch (RemoteException ex) {
    731         }
    732 
    733         /*
    734          * DISABLED due to missing API
    735         if (ENABLE_INTRUDERS && (
    736                    // TODO(dsandler): Only if the screen is on
    737                 notification.notification.intruderView != null)) {
    738             Slog.d(TAG, "Presenting high-priority notification");
    739             // special new transient ticker mode
    740             // 1. Populate mIntruderAlertView
    741 
    742             if (notification.notification.intruderView == null) {
    743                 Slog.e(TAG, notification.notification.toString() + " wanted to intrude but intruderView was null");
    744                 return;
    745             }
    746 
    747             // bind the click event to the content area
    748             PendingIntent contentIntent = notification.notification.contentIntent;
    749             final View.OnClickListener listener = (contentIntent != null)
    750                     ? new NotificationClicker(contentIntent,
    751                             notification.pkg, notification.tag, notification.id)
    752                     : null;
    753 
    754             mIntruderAlertView.applyIntruderContent(notification.notification.intruderView, listener);
    755 
    756             mCurrentlyIntrudingNotification = notification;
    757 
    758             // 2. Animate mIntruderAlertView in
    759             mHandler.sendEmptyMessage(MSG_SHOW_INTRUDER);
    760 
    761             // 3. Set alarm to age the notification off (TODO)
    762             mHandler.removeMessages(MSG_HIDE_INTRUDER);
    763             if (INTRUDER_ALERT_DECAY_MS > 0) {
    764                 mHandler.sendEmptyMessageDelayed(MSG_HIDE_INTRUDER, INTRUDER_ALERT_DECAY_MS);
    765             }
    766         } else
    767          */
    768 
    769         if (notification.notification.fullScreenIntent != null) {
    770             // not immersive & a full-screen alert should be shown
    771             Slog.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent");
    772             try {
    773                 notification.notification.fullScreenIntent.send();
    774             } catch (PendingIntent.CanceledException e) {
    775             }
    776         } else {
    777             // usual case: status bar visible & not immersive
    778 
    779             // show the ticker if there isn't an intruder too
    780             if (mCurrentlyIntrudingNotification == null) {
    781                 tick(null, notification, true);
    782             }
    783         }
    784 
    785         // Recalculate the position of the sliding windows and the titles.
    786         setAreThereNotifications();
    787         updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
    788     }
    789 
    790     public void removeNotification(IBinder key) {
    791         StatusBarNotification old = removeNotificationViews(key);
    792         if (SPEW) Slog.d(TAG, "removeNotification key=" + key + " old=" + old);
    793 
    794         if (old != null) {
    795             // Cancel the ticker if it's still running
    796             mTicker.removeEntry(old);
    797 
    798             // Recalculate the position of the sliding windows and the titles.
    799             updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
    800 
    801             if (ENABLE_INTRUDERS && old == mCurrentlyIntrudingNotification) {
    802                 mHandler.sendEmptyMessage(MSG_HIDE_INTRUDER);
    803             }
    804 
    805             if (CLOSE_PANEL_WHEN_EMPTIED && mNotificationData.size() == 0 && !mAnimating) {
    806                 animateCollapse();
    807             }
    808         }
    809 
    810         setAreThereNotifications();
    811     }
    812 
    813     @Override
    814     protected void onConfigurationChanged(Configuration newConfig) {
    815         updateRecentsPanel();
    816         updateShowSearchHoldoff();
    817     }
    818 
    819     private void updateShowSearchHoldoff() {
    820         mShowSearchHoldoff = mContext.getResources().getInteger(
    821             R.integer.config_show_search_delay);
    822     }
    823 
    824     private void loadNotificationShade() {
    825         if (mPile == null) return;
    826 
    827         int N = mNotificationData.size();
    828 
    829         ArrayList<View> toShow = new ArrayList<View>();
    830 
    831         final boolean provisioned = isDeviceProvisioned();
    832         // If the device hasn't been through Setup, we only show system notifications
    833         for (int i=0; i<N; i++) {
    834             Entry ent = mNotificationData.get(N-i-1);
    835             if (provisioned || showNotificationEvenIfUnprovisioned(ent.notification)) {
    836                 toShow.add(ent.row);
    837             }
    838         }
    839 
    840         ArrayList<View> toRemove = new ArrayList<View>();
    841         for (int i=0; i<mPile.getChildCount(); i++) {
    842             View child = mPile.getChildAt(i);
    843             if (!toShow.contains(child)) {
    844                 toRemove.add(child);
    845             }
    846         }
    847 
    848         for (View remove : toRemove) {
    849             mPile.removeView(remove);
    850         }
    851 
    852         for (int i=0; i<toShow.size(); i++) {
    853             View v = toShow.get(i);
    854             if (v.getParent() == null) {
    855                 mPile.addView(v, i);
    856             }
    857         }
    858 
    859         mSettingsButton.setEnabled(isDeviceProvisioned());
    860     }
    861 
    862     private void reloadAllNotificationIcons() {
    863         if (mNotificationIcons == null) return;
    864         mNotificationIcons.removeAllViews();
    865         updateNotificationIcons();
    866     }
    867 
    868     @Override
    869     protected void updateNotificationIcons() {
    870         if (mNotificationIcons == null) return;
    871 
    872         loadNotificationShade();
    873 
    874         final LinearLayout.LayoutParams params
    875             = new LinearLayout.LayoutParams(mIconSize + 2*mIconHPadding, mNaturalBarHeight);
    876 
    877         int N = mNotificationData.size();
    878 
    879         if (DEBUG) {
    880             Slog.d(TAG, "refreshing icons: " + N + " notifications, mNotificationIcons=" + mNotificationIcons);
    881         }
    882 
    883         ArrayList<View> toShow = new ArrayList<View>();
    884 
    885         final boolean provisioned = isDeviceProvisioned();
    886         // If the device hasn't been through Setup, we only show system notifications
    887         for (int i=0; i<N; i++) {
    888             Entry ent = mNotificationData.get(N-i-1);
    889             if ((provisioned && ent.notification.score >= HIDE_ICONS_BELOW_SCORE)
    890                     || showNotificationEvenIfUnprovisioned(ent.notification)) {
    891                 toShow.add(ent.icon);
    892             }
    893         }
    894 
    895         ArrayList<View> toRemove = new ArrayList<View>();
    896         for (int i=0; i<mNotificationIcons.getChildCount(); i++) {
    897             View child = mNotificationIcons.getChildAt(i);
    898             if (!toShow.contains(child)) {
    899                 toRemove.add(child);
    900             }
    901         }
    902 
    903         for (View remove : toRemove) {
    904             mNotificationIcons.removeView(remove);
    905         }
    906 
    907         for (int i=0; i<toShow.size(); i++) {
    908             View v = toShow.get(i);
    909             if (v.getParent() == null) {
    910                 mNotificationIcons.addView(v, i, params);
    911             }
    912         }
    913     }
    914 
    915     protected void updateCarrierLabelVisibility(boolean force) {
    916         if (!SHOW_CARRIER_LABEL) return;
    917         // The idea here is to only show the carrier label when there is enough room to see it,
    918         // i.e. when there aren't enough notifications to fill the panel.
    919         if (DEBUG) {
    920             Slog.d(TAG, String.format("pileh=%d scrollh=%d carrierh=%d",
    921                     mPile.getHeight(), mScrollView.getHeight(), mCarrierLabelHeight));
    922         }
    923 
    924         final boolean makeVisible =
    925             mPile.getHeight() < (mScrollView.getHeight() - mCarrierLabelHeight);
    926 
    927         if (force || mCarrierLabelVisible != makeVisible) {
    928             mCarrierLabelVisible = makeVisible;
    929             if (DEBUG) {
    930                 Slog.d(TAG, "making carrier label " + (makeVisible?"visible":"invisible"));
    931             }
    932             mCarrierLabel.animate().cancel();
    933             if (makeVisible) {
    934                 mCarrierLabel.setVisibility(View.VISIBLE);
    935             }
    936             mCarrierLabel.animate()
    937                 .alpha(makeVisible ? 1f : 0f)
    938                 //.setStartDelay(makeVisible ? 500 : 0)
    939                 //.setDuration(makeVisible ? 750 : 100)
    940                 .setDuration(150)
    941                 .setListener(makeVisible ? null : new AnimatorListenerAdapter() {
    942                     @Override
    943                     public void onAnimationEnd(Animator animation) {
    944                         if (!mCarrierLabelVisible) { // race
    945                             mCarrierLabel.setVisibility(View.INVISIBLE);
    946                             mCarrierLabel.setAlpha(0f);
    947                         }
    948                     }
    949                 })
    950                 .start();
    951         }
    952     }
    953 
    954     @Override
    955     protected void setAreThereNotifications() {
    956         final boolean any = mNotificationData.size() > 0;
    957 
    958         final boolean clearable = any && mNotificationData.hasClearableItems();
    959 
    960         if (DEBUG) {
    961             Slog.d(TAG, "setAreThereNotifications: N=" + mNotificationData.size()
    962                     + " any=" + any + " clearable=" + clearable);
    963         }
    964 
    965         if (mClearButton.isShown()) {
    966             if (clearable != (mClearButton.getAlpha() == 1.0f)) {
    967                 ObjectAnimator clearAnimation = ObjectAnimator.ofFloat(
    968                         mClearButton, "alpha", clearable ? 1.0f : 0.0f).setDuration(250);
    969                 clearAnimation.addListener(new AnimatorListenerAdapter() {
    970                     @Override
    971                     public void onAnimationEnd(Animator animation) {
    972                         if (mClearButton.getAlpha() <= 0.0f) {
    973                             mClearButton.setVisibility(View.INVISIBLE);
    974                         }
    975                     }
    976 
    977                     @Override
    978                     public void onAnimationStart(Animator animation) {
    979                         if (mClearButton.getAlpha() <= 0.0f) {
    980                             mClearButton.setVisibility(View.VISIBLE);
    981                         }
    982                     }
    983                 });
    984                 clearAnimation.start();
    985             }
    986         } else {
    987             mClearButton.setAlpha(clearable ? 1.0f : 0.0f);
    988             mClearButton.setVisibility(clearable ? View.VISIBLE : View.INVISIBLE);
    989         }
    990         mClearButton.setEnabled(clearable);
    991 
    992         final View nlo = mStatusBarView.findViewById(R.id.notification_lights_out);
    993         final boolean showDot = (any&&!areLightsOn());
    994         if (showDot != (nlo.getAlpha() == 1.0f)) {
    995             if (showDot) {
    996                 nlo.setAlpha(0f);
    997                 nlo.setVisibility(View.VISIBLE);
    998             }
    999             nlo.animate()
   1000                 .alpha(showDot?1:0)
   1001                 .setDuration(showDot?750:250)
   1002                 .setInterpolator(new AccelerateInterpolator(2.0f))
   1003                 .setListener(showDot ? null : new AnimatorListenerAdapter() {
   1004                     @Override
   1005                     public void onAnimationEnd(Animator _a) {
   1006                         nlo.setVisibility(View.GONE);
   1007                     }
   1008                 })
   1009                 .start();
   1010         }
   1011 
   1012         updateCarrierLabelVisibility(false);
   1013     }
   1014 
   1015     public void showClock(boolean show) {
   1016         if (mStatusBarView == null) return;
   1017         View clock = mStatusBarView.findViewById(R.id.clock);
   1018         if (clock != null) {
   1019             clock.setVisibility(show ? View.VISIBLE : View.GONE);
   1020         }
   1021     }
   1022 
   1023     /**
   1024      * State is one or more of the DISABLE constants from StatusBarManager.
   1025      */
   1026     public void disable(int state) {
   1027         final int old = mDisabled;
   1028         final int diff = state ^ old;
   1029         mDisabled = state;
   1030 
   1031         if (DEBUG) {
   1032             Slog.d(TAG, String.format("disable: 0x%08x -> 0x%08x (diff: 0x%08x)",
   1033                 old, state, diff));
   1034         }
   1035 
   1036         StringBuilder flagdbg = new StringBuilder();
   1037         flagdbg.append("disable: < ");
   1038         flagdbg.append(((state & StatusBarManager.DISABLE_EXPAND) != 0) ? "EXPAND" : "expand");
   1039         flagdbg.append(((diff  & StatusBarManager.DISABLE_EXPAND) != 0) ? "* " : " ");
   1040         flagdbg.append(((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) ? "ICONS" : "icons");
   1041         flagdbg.append(((diff  & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) ? "* " : " ");
   1042         flagdbg.append(((state & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) ? "ALERTS" : "alerts");
   1043         flagdbg.append(((diff  & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) ? "* " : " ");
   1044         flagdbg.append(((state & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) ? "TICKER" : "ticker");
   1045         flagdbg.append(((diff  & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) ? "* " : " ");
   1046         flagdbg.append(((state & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) ? "SYSTEM_INFO" : "system_info");
   1047         flagdbg.append(((diff  & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) ? "* " : " ");
   1048         flagdbg.append(((state & StatusBarManager.DISABLE_BACK) != 0) ? "BACK" : "back");
   1049         flagdbg.append(((diff  & StatusBarManager.DISABLE_BACK) != 0) ? "* " : " ");
   1050         flagdbg.append(((state & StatusBarManager.DISABLE_HOME) != 0) ? "HOME" : "home");
   1051         flagdbg.append(((diff  & StatusBarManager.DISABLE_HOME) != 0) ? "* " : " ");
   1052         flagdbg.append(((state & StatusBarManager.DISABLE_RECENT) != 0) ? "RECENT" : "recent");
   1053         flagdbg.append(((diff  & StatusBarManager.DISABLE_RECENT) != 0) ? "* " : " ");
   1054         flagdbg.append(((state & StatusBarManager.DISABLE_CLOCK) != 0) ? "CLOCK" : "clock");
   1055         flagdbg.append(((diff  & StatusBarManager.DISABLE_CLOCK) != 0) ? "* " : " ");
   1056         flagdbg.append(">");
   1057         Slog.d(TAG, flagdbg.toString());
   1058 
   1059         if ((diff & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
   1060             mIcons.animate().cancel();
   1061             if ((state & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
   1062                 if (mTicking) {
   1063                     mTicker.halt();
   1064                 }
   1065                 mIcons.animate()
   1066                     .alpha(0f)
   1067                     .translationY(mNaturalBarHeight*0.5f)
   1068                     //.setStartDelay(100)
   1069                     .setDuration(175)
   1070                     .setInterpolator(new DecelerateInterpolator(1.5f))
   1071                     .setListener(mMakeIconsInvisible)
   1072                     .start();
   1073             } else {
   1074                 mIcons.setVisibility(View.VISIBLE);
   1075                 mIcons.animate()
   1076                     .alpha(1f)
   1077                     .translationY(0)
   1078                     .setStartDelay(0)
   1079                     .setInterpolator(new DecelerateInterpolator(1.5f))
   1080                     .setDuration(175)
   1081                     .start();
   1082             }
   1083         }
   1084 
   1085         if ((diff & StatusBarManager.DISABLE_CLOCK) != 0) {
   1086             boolean show = (state & StatusBarManager.DISABLE_CLOCK) == 0;
   1087             showClock(show);
   1088         }
   1089         if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
   1090             if ((state & StatusBarManager.DISABLE_EXPAND) != 0) {
   1091                 animateCollapse();
   1092             }
   1093         }
   1094 
   1095         if ((diff & (StatusBarManager.DISABLE_HOME
   1096                         | StatusBarManager.DISABLE_RECENT
   1097                         | StatusBarManager.DISABLE_BACK)) != 0) {
   1098             // the nav bar will take care of these
   1099             if (mNavigationBarView != null) mNavigationBarView.setDisabledFlags(state);
   1100 
   1101             if ((state & StatusBarManager.DISABLE_RECENT) != 0) {
   1102                 // close recents if it's visible
   1103                 mHandler.removeMessages(MSG_CLOSE_RECENTS_PANEL);
   1104                 mHandler.sendEmptyMessage(MSG_CLOSE_RECENTS_PANEL);
   1105             }
   1106         }
   1107 
   1108         if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
   1109             if ((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
   1110                 if (mTicking) {
   1111                     mTicker.halt();
   1112                 } else {
   1113                     setNotificationIconVisibility(false, com.android.internal.R.anim.fade_out);
   1114                 }
   1115             } else {
   1116                 if (!mExpandedVisible) {
   1117                     setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
   1118                 }
   1119             }
   1120         } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
   1121             if (mTicking && (state & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
   1122                 mTicker.halt();
   1123             }
   1124         }
   1125     }
   1126 
   1127     @Override
   1128     protected BaseStatusBar.H createHandler() {
   1129         return new PhoneStatusBar.H();
   1130     }
   1131 
   1132     /**
   1133      * All changes to the status bar and notifications funnel through here and are batched.
   1134      */
   1135     private class H extends BaseStatusBar.H {
   1136         public void handleMessage(Message m) {
   1137             super.handleMessage(m);
   1138             switch (m.what) {
   1139                 case MSG_OPEN_NOTIFICATION_PANEL:
   1140                     animateExpand();
   1141                     break;
   1142                 case MSG_CLOSE_NOTIFICATION_PANEL:
   1143                     animateCollapse();
   1144                     break;
   1145                 case MSG_SHOW_INTRUDER:
   1146                     setIntruderAlertVisibility(true);
   1147                     break;
   1148                 case MSG_HIDE_INTRUDER:
   1149                     setIntruderAlertVisibility(false);
   1150                     mCurrentlyIntrudingNotification = null;
   1151                     break;
   1152             }
   1153         }
   1154     }
   1155 
   1156     final Runnable mAnimationCallback = new Runnable() {
   1157         @Override
   1158         public void run() {
   1159             doAnimation(mChoreographer.getFrameTimeNanos());
   1160         }
   1161     };
   1162 
   1163     final Runnable mRevealAnimationCallback = new Runnable() {
   1164         @Override
   1165         public void run() {
   1166             doRevealAnimation(mChoreographer.getFrameTimeNanos());
   1167         }
   1168     };
   1169 
   1170     View.OnFocusChangeListener mFocusChangeListener = new View.OnFocusChangeListener() {
   1171         public void onFocusChange(View v, boolean hasFocus) {
   1172             // Because 'v' is a ViewGroup, all its children will be (un)selected
   1173             // too, which allows marqueeing to work.
   1174             v.setSelected(hasFocus);
   1175         }
   1176     };
   1177 
   1178     private void makeExpandedVisible(boolean revealAfterDraw) {
   1179         if (SPEW) Slog.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible);
   1180         if (mExpandedVisible) {
   1181             return;
   1182         }
   1183 
   1184         mExpandedVisible = true;
   1185         mPile.setLayoutTransitionsEnabled(true);
   1186         if (mNavigationBarView != null)
   1187             mNavigationBarView.setSlippery(true);
   1188 
   1189         updateCarrierLabelVisibility(true);
   1190 
   1191         updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
   1192 
   1193         // Expand the window to encompass the full screen in anticipation of the drag.
   1194         // This is only possible to do atomically because the status bar is at the top of the screen!
   1195         WindowManager.LayoutParams lp = (WindowManager.LayoutParams) mStatusBarWindow.getLayoutParams();
   1196         lp.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
   1197         lp.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
   1198         lp.height = ViewGroup.LayoutParams.MATCH_PARENT;
   1199         final WindowManager wm = WindowManagerImpl.getDefault();
   1200         wm.updateViewLayout(mStatusBarWindow, lp);
   1201 
   1202         // Updating the window layout will force an expensive traversal/redraw.
   1203         // Kick off the reveal animation after this is complete to avoid animation latency.
   1204         if (revealAfterDraw) {
   1205             mHandler.post(mStartRevealAnimation);
   1206         }
   1207 
   1208         visibilityChanged(true);
   1209     }
   1210 
   1211     public void animateExpand() {
   1212         if (SPEW) Slog.d(TAG, "Animate expand: expanded=" + mExpanded);
   1213         if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
   1214             return ;
   1215         }
   1216         if (mExpanded) {
   1217             return;
   1218         }
   1219 
   1220         prepareTracking(0, true);
   1221         mHandler.post(mPerformSelfExpandFling);
   1222     }
   1223 
   1224     public void animateCollapse() {
   1225         animateCollapse(CommandQueue.FLAG_EXCLUDE_NONE);
   1226     }
   1227 
   1228     public void animateCollapse(int flags) {
   1229         animateCollapse(flags, 1.0f);
   1230     }
   1231 
   1232     public void animateCollapse(int flags, float velocityMultiplier) {
   1233         if (SPEW) {
   1234             Slog.d(TAG, "animateCollapse(): mExpanded=" + mExpanded
   1235                     + " mExpandedVisible=" + mExpandedVisible
   1236                     + " mExpanded=" + mExpanded
   1237                     + " mAnimating=" + mAnimating
   1238                     + " mAnimY=" + mAnimY
   1239                     + " mAnimVel=" + mAnimVel
   1240                     + " flags=" + flags);
   1241         }
   1242 
   1243         if ((flags & CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL) == 0) {
   1244             mHandler.removeMessages(MSG_CLOSE_RECENTS_PANEL);
   1245             mHandler.sendEmptyMessage(MSG_CLOSE_RECENTS_PANEL);
   1246         }
   1247 
   1248         if ((flags & CommandQueue.FLAG_EXCLUDE_SEARCH_PANEL) == 0) {
   1249             mHandler.removeMessages(MSG_CLOSE_SEARCH_PANEL);
   1250             mHandler.sendEmptyMessage(MSG_CLOSE_SEARCH_PANEL);
   1251         }
   1252 
   1253         if (!mExpandedVisible) {
   1254             return;
   1255         }
   1256 
   1257         int y;
   1258         if (mAnimating) {
   1259             y = (int)mAnimY;
   1260         } else {
   1261             y = getExpandedViewMaxHeight()-1;
   1262         }
   1263         // Let the fling think that we're open so it goes in the right direction
   1264         // and doesn't try to re-open the windowshade.
   1265         mExpanded = true;
   1266         prepareTracking(y, false);
   1267         performFling(y, -mSelfCollapseVelocityPx*velocityMultiplier, true);
   1268     }
   1269 
   1270     void performExpand() {
   1271         if (SPEW) Slog.d(TAG, "performExpand: mExpanded=" + mExpanded);
   1272         if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
   1273             return ;
   1274         }
   1275         if (mExpanded) {
   1276             return;
   1277         }
   1278 
   1279         mExpanded = true;
   1280         makeExpandedVisible(false);
   1281         updateExpandedViewPos(EXPANDED_FULL_OPEN);
   1282 
   1283         if (false) postStartTracing();
   1284     }
   1285 
   1286     void performCollapse() {
   1287         if (SPEW) Slog.d(TAG, "performCollapse: mExpanded=" + mExpanded
   1288                 + " mExpandedVisible=" + mExpandedVisible);
   1289 
   1290         if (!mExpandedVisible) {
   1291             return;
   1292         }
   1293         mExpandedVisible = false;
   1294         mPile.setLayoutTransitionsEnabled(false);
   1295         if (mNavigationBarView != null)
   1296             mNavigationBarView.setSlippery(false);
   1297         visibilityChanged(false);
   1298 
   1299         // Shrink the window to the size of the status bar only
   1300         WindowManager.LayoutParams lp = (WindowManager.LayoutParams) mStatusBarWindow.getLayoutParams();
   1301         lp.height = getStatusBarHeight();
   1302         lp.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
   1303         lp.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
   1304         final WindowManager wm = WindowManagerImpl.getDefault();
   1305         wm.updateViewLayout(mStatusBarWindow, lp);
   1306 
   1307         if ((mDisabled & StatusBarManager.DISABLE_NOTIFICATION_ICONS) == 0) {
   1308             setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
   1309         }
   1310 
   1311         if (!mExpanded) {
   1312             return;
   1313         }
   1314         mExpanded = false;
   1315 
   1316         // Close any "App info" popups that might have snuck on-screen
   1317         dismissPopups();
   1318 
   1319         if (mPostCollapseCleanup != null) {
   1320             mPostCollapseCleanup.run();
   1321             mPostCollapseCleanup = null;
   1322         }
   1323     }
   1324 
   1325     void resetLastAnimTime() {
   1326         mAnimLastTimeNanos = System.nanoTime();
   1327         if (SPEW) {
   1328             Throwable t = new Throwable();
   1329             t.fillInStackTrace();
   1330             Slog.d(TAG, "resetting last anim time=" + mAnimLastTimeNanos, t);
   1331         }
   1332     }
   1333 
   1334     void doAnimation(long frameTimeNanos) {
   1335         if (mAnimating) {
   1336             if (SPEW) Slog.d(TAG, "doAnimation dt=" + (frameTimeNanos - mAnimLastTimeNanos));
   1337             if (SPEW) Slog.d(TAG, "doAnimation before mAnimY=" + mAnimY);
   1338             incrementAnim(frameTimeNanos);
   1339             if (SPEW) {
   1340                 Slog.d(TAG, "doAnimation after  mAnimY=" + mAnimY);
   1341                 Slog.d(TAG, "doAnimation expandedViewMax=" + getExpandedViewMaxHeight());
   1342             }
   1343 
   1344             if (mAnimY >= getExpandedViewMaxHeight()-1 && !mClosing) {
   1345                 if (SPEW) Slog.d(TAG, "Animation completed to expanded state.");
   1346                 mAnimating = false;
   1347                 updateExpandedViewPos(EXPANDED_FULL_OPEN);
   1348                 performExpand();
   1349                 return;
   1350             }
   1351 
   1352             if (mAnimY == 0 && mAnimAccel == 0 && mClosing) {
   1353                 if (SPEW) Slog.d(TAG, "Animation completed to collapsed state.");
   1354                 mAnimating = false;
   1355                 performCollapse();
   1356                 return;
   1357             }
   1358 
   1359             if (mAnimY < getStatusBarHeight() && mClosing) {
   1360                 // Draw one more frame with the bar positioned at the top of the screen
   1361                 // before ending the animation so that the user sees the bar in
   1362                 // its final position.  The call to performCollapse() causes a window
   1363                 // relayout which takes time and might cause the animation to skip
   1364                 // on the very last frame before the bar disappears if we did it now.
   1365                 mAnimY = 0;
   1366                 mAnimAccel = 0;
   1367                 mAnimVel = 0;
   1368             }
   1369 
   1370             updateExpandedViewPos((int)mAnimY);
   1371             mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION,
   1372                     mAnimationCallback, null);
   1373         }
   1374     }
   1375 
   1376     void stopTracking() {
   1377         if (!mTracking)
   1378             return;
   1379         mTracking = false;
   1380         setPileLayers(View.LAYER_TYPE_NONE);
   1381         mVelocityTracker.recycle();
   1382         mVelocityTracker = null;
   1383         mCloseView.setPressed(false);
   1384     }
   1385 
   1386     /**
   1387      * Enables or disables layers on the children of the notifications pile.
   1388      *
   1389      * When layers are enabled, this method attempts to enable layers for the minimal
   1390      * number of children. Only children visible when the notification area is fully
   1391      * expanded will receive a layer. The technique used in this method might cause
   1392      * more children than necessary to get a layer (at most one extra child with the
   1393      * current UI.)
   1394      *
   1395      * @param layerType {@link View#LAYER_TYPE_NONE} or {@link View#LAYER_TYPE_HARDWARE}
   1396      */
   1397     private void setPileLayers(int layerType) {
   1398         final int count = mPile.getChildCount();
   1399 
   1400         switch (layerType) {
   1401             case View.LAYER_TYPE_NONE:
   1402                 for (int i = 0; i < count; i++) {
   1403                     mPile.getChildAt(i).setLayerType(layerType, null);
   1404                 }
   1405                 break;
   1406             case View.LAYER_TYPE_HARDWARE:
   1407                 final int[] location = new int[2];
   1408                 mNotificationPanel.getLocationInWindow(location);
   1409 
   1410                 final int left = location[0];
   1411                 final int top = location[1];
   1412                 final int right = left + mNotificationPanel.getWidth();
   1413                 final int bottom = top + getExpandedViewMaxHeight();
   1414 
   1415                 final Rect childBounds = new Rect();
   1416 
   1417                 for (int i = 0; i < count; i++) {
   1418                     final View view = mPile.getChildAt(i);
   1419                     view.getLocationInWindow(location);
   1420 
   1421                     childBounds.set(location[0], location[1],
   1422                             location[0] + view.getWidth(), location[1] + view.getHeight());
   1423 
   1424                     if (childBounds.intersects(left, top, right, bottom)) {
   1425                         view.setLayerType(layerType, null);
   1426                     }
   1427                 }
   1428 
   1429                 break;
   1430         }
   1431     }
   1432 
   1433     void incrementAnim(long frameTimeNanos) {
   1434         final long deltaNanos = Math.max(frameTimeNanos - mAnimLastTimeNanos, 0);
   1435         final float t = deltaNanos * 0.000000001f;                  // ns -> s
   1436         final float y = mAnimY;
   1437         final float v = mAnimVel;                                   // px/s
   1438         final float a = mAnimAccel;                                 // px/s/s
   1439         mAnimY = y + (v*t) + (0.5f*a*t*t);                          // px
   1440         mAnimVel = v + (a*t);                                       // px/s
   1441         mAnimLastTimeNanos = frameTimeNanos;                        // ns
   1442         //Slog.d(TAG, "y=" + y + " v=" + v + " a=" + a + " t=" + t + " mAnimY=" + mAnimY
   1443         //        + " mAnimAccel=" + mAnimAccel);
   1444     }
   1445 
   1446     void doRevealAnimation(long frameTimeNanos) {
   1447         if (SPEW) {
   1448             Slog.d(TAG, "doRevealAnimation: dt=" + (frameTimeNanos - mAnimLastTimeNanos));
   1449         }
   1450         final int h = mNotificationPanelMinHeight;
   1451         if (mAnimatingReveal && mAnimating && mAnimY < h) {
   1452             incrementAnim(frameTimeNanos);
   1453             if (mAnimY >= h) {
   1454                 mAnimY = h;
   1455                 updateExpandedViewPos((int)mAnimY);
   1456             } else {
   1457                 updateExpandedViewPos((int)mAnimY);
   1458                 mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION,
   1459                         mRevealAnimationCallback, null);
   1460             }
   1461         }
   1462     }
   1463 
   1464     void prepareTracking(int y, boolean opening) {
   1465         if (CHATTY) {
   1466             Slog.d(TAG, "panel: beginning to track the user's touch, y=" + y + " opening=" + opening);
   1467         }
   1468 
   1469         mCloseView.setPressed(true);
   1470 
   1471         mTracking = true;
   1472         setPileLayers(View.LAYER_TYPE_HARDWARE);
   1473         mVelocityTracker = VelocityTracker.obtain();
   1474         if (opening) {
   1475             makeExpandedVisible(true);
   1476         } else {
   1477             // it's open, close it?
   1478             if (mAnimating) {
   1479                 mAnimating = false;
   1480                 mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION,
   1481                         mAnimationCallback, null);
   1482             }
   1483             updateExpandedViewPos(y + mViewDelta);
   1484         }
   1485     }
   1486 
   1487     void performFling(int y, float vel, boolean always) {
   1488         if (CHATTY) {
   1489             Slog.d(TAG, "panel: will fling, y=" + y + " vel=" + vel + " mExpanded=" + mExpanded);
   1490         }
   1491 
   1492         mAnimatingReveal = false;
   1493 
   1494         mAnimY = y;
   1495         mAnimVel = vel;
   1496 
   1497         //Slog.d(TAG, "starting with mAnimY=" + mAnimY + " mAnimVel=" + mAnimVel);
   1498 
   1499         if (mExpanded) {
   1500             if (!always && (
   1501                     vel > mFlingCollapseMinVelocityPx
   1502                     || (y > (getExpandedViewMaxHeight()*(1f-mCollapseMinDisplayFraction)) &&
   1503                         vel > -mFlingExpandMinVelocityPx))) {
   1504                 // We are expanded, but they didn't move sufficiently to cause
   1505                 // us to retract.  Animate back to the expanded position.
   1506                 mAnimAccel = mExpandAccelPx;
   1507                 if (vel < 0) {
   1508                     mAnimVel = 0;
   1509                 }
   1510             }
   1511             else {
   1512                 // We are expanded and are now going to animate away.
   1513                 mAnimAccel = -mCollapseAccelPx;
   1514                 if (vel > 0) {
   1515                     mAnimVel = 0;
   1516                 }
   1517             }
   1518         } else {
   1519             if (always || (
   1520                     vel > mFlingExpandMinVelocityPx
   1521                     || (y > (getExpandedViewMaxHeight()*(1f-mExpandMinDisplayFraction)) &&
   1522                         vel > -mFlingCollapseMinVelocityPx))) {
   1523                 // We are collapsed, and they moved enough to allow us to
   1524                 // expand.  Animate in the notifications.
   1525                 mAnimAccel = mExpandAccelPx;
   1526                 if (vel < 0) {
   1527                     mAnimVel = 0;
   1528                 }
   1529             }
   1530             else {
   1531                 // We are collapsed, but they didn't move sufficiently to cause
   1532                 // us to retract.  Animate back to the collapsed position.
   1533                 mAnimAccel = -mCollapseAccelPx;
   1534                 if (vel > 0) {
   1535                     mAnimVel = 0;
   1536                 }
   1537             }
   1538         }
   1539         //Slog.d(TAG, "mAnimY=" + mAnimY + " mAnimVel=" + mAnimVel
   1540         //        + " mAnimAccel=" + mAnimAccel);
   1541 
   1542         resetLastAnimTime();
   1543         mAnimating = true;
   1544         mClosing = mAnimAccel < 0;
   1545 
   1546         mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION,
   1547                 mAnimationCallback, null);
   1548         mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION,
   1549                 mRevealAnimationCallback, null);
   1550         mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION,
   1551                 mAnimationCallback, null);
   1552         stopTracking();
   1553     }
   1554 
   1555     boolean interceptTouchEvent(MotionEvent event) {
   1556         if (SPEW) {
   1557             Slog.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled="
   1558                 + mDisabled + " mTracking=" + mTracking);
   1559         } else if (CHATTY) {
   1560             if (event.getAction() != MotionEvent.ACTION_MOVE) {
   1561                 Slog.d(TAG, String.format(
   1562                             "panel: %s at (%f, %f) mDisabled=0x%08x",
   1563                             MotionEvent.actionToString(event.getAction()),
   1564                             event.getRawX(), event.getRawY(), mDisabled));
   1565             }
   1566         }
   1567 
   1568         if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
   1569             return false;
   1570         }
   1571 
   1572         final int action = event.getAction();
   1573         final int statusBarSize = getStatusBarHeight();
   1574         final int hitSize = statusBarSize*2;
   1575         final int y = (int)event.getRawY();
   1576         if (action == MotionEvent.ACTION_DOWN) {
   1577             if (!areLightsOn()) {
   1578                 setLightsOn(true);
   1579             }
   1580 
   1581             if (!mExpanded) {
   1582                 mViewDelta = statusBarSize - y;
   1583             } else {
   1584                 mCloseView.getLocationOnScreen(mAbsPos);
   1585                 mViewDelta = mAbsPos[1]
   1586                            + getCloseViewHeight() // XXX: not closeViewHeight, but paddingBottom from the 9patch
   1587                            + mNotificationPanelBackgroundPadding.top
   1588                            + mNotificationPanelBackgroundPadding.bottom
   1589                            - y;
   1590             }
   1591             if ((!mExpanded && y < hitSize) ||
   1592                     // @@ add taps outside the panel if it's not full-screen
   1593                     (mExpanded && y > (getExpandedViewMaxHeight()-hitSize))) {
   1594                 // We drop events at the edge of the screen to make the windowshade come
   1595                 // down by accident less, especially when pushing open a device with a keyboard
   1596                 // that rotates (like g1 and droid)
   1597                 int x = (int)event.getRawX();
   1598                 final int edgeBorder = mEdgeBorder;
   1599                 if (x >= edgeBorder && x < mDisplayMetrics.widthPixels - edgeBorder) {
   1600                     prepareTracking(y, !mExpanded);// opening if we're not already fully visible
   1601                     trackMovement(event);
   1602                 }
   1603             }
   1604         } else if (mTracking) {
   1605             trackMovement(event);
   1606             if (action == MotionEvent.ACTION_MOVE) {
   1607                 if (mAnimatingReveal && (y + mViewDelta) < mNotificationPanelMinHeight) {
   1608                     // nothing
   1609                 } else  {
   1610                     mAnimatingReveal = false;
   1611                     updateExpandedViewPos(y + mViewDelta);
   1612                 }
   1613             } else if (action == MotionEvent.ACTION_UP
   1614                     || action == MotionEvent.ACTION_CANCEL) {
   1615                 mVelocityTracker.computeCurrentVelocity(1000);
   1616 
   1617                 float yVel = mVelocityTracker.getYVelocity();
   1618                 boolean negative = yVel < 0;
   1619 
   1620                 float xVel = mVelocityTracker.getXVelocity();
   1621                 if (xVel < 0) {
   1622                     xVel = -xVel;
   1623                 }
   1624                 if (xVel > mFlingGestureMaxXVelocityPx) {
   1625                     xVel = mFlingGestureMaxXVelocityPx; // limit how much we care about the x axis
   1626                 }
   1627 
   1628                 float vel = (float)Math.hypot(yVel, xVel);
   1629                 if (vel > mFlingGestureMaxOutputVelocityPx) {
   1630                     vel = mFlingGestureMaxOutputVelocityPx;
   1631                 }
   1632                 if (negative) {
   1633                     vel = -vel;
   1634                 }
   1635 
   1636                 if (CHATTY) {
   1637                     Slog.d(TAG, String.format("gesture: vraw=(%f,%f) vnorm=(%f,%f) vlinear=%f",
   1638                         mVelocityTracker.getXVelocity(),
   1639                         mVelocityTracker.getYVelocity(),
   1640                         xVel, yVel,
   1641                         vel));
   1642                 }
   1643 
   1644                 if (mTrackingPosition == mNotificationPanelMinHeight) {
   1645                     // start the fling from the tracking position, ignore y and view delta
   1646                     mFlingY = mTrackingPosition;
   1647                     mViewDelta = 0;
   1648                 } else {
   1649                     mFlingY = y;
   1650                 }
   1651                 mFlingVelocity = vel;
   1652                 mHandler.post(mPerformFling);
   1653             }
   1654 
   1655         }
   1656         return false;
   1657     }
   1658 
   1659     private void trackMovement(MotionEvent event) {
   1660         // Add movement to velocity tracker using raw screen X and Y coordinates instead
   1661         // of window coordinates because the window frame may be moving at the same time.
   1662         float deltaX = event.getRawX() - event.getX();
   1663         float deltaY = event.getRawY() - event.getY();
   1664         event.offsetLocation(deltaX, deltaY);
   1665         mVelocityTracker.addMovement(event);
   1666         event.offsetLocation(-deltaX, -deltaY);
   1667     }
   1668 
   1669     @Override // CommandQueue
   1670     public void setNavigationIconHints(int hints) {
   1671         if (hints == mNavigationIconHints) return;
   1672 
   1673         mNavigationIconHints = hints;
   1674 
   1675         if (mNavigationBarView != null) {
   1676             mNavigationBarView.setNavigationIconHints(hints);
   1677         }
   1678     }
   1679 
   1680     @Override // CommandQueue
   1681     public void setSystemUiVisibility(int vis, int mask) {
   1682         final int oldVal = mSystemUiVisibility;
   1683         final int newVal = (oldVal&~mask) | (vis&mask);
   1684         final int diff = newVal ^ oldVal;
   1685 
   1686         if (diff != 0) {
   1687             mSystemUiVisibility = newVal;
   1688 
   1689             if (0 != (diff & View.SYSTEM_UI_FLAG_LOW_PROFILE)) {
   1690                 final boolean lightsOut = (0 != (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE));
   1691                 if (lightsOut) {
   1692                     animateCollapse();
   1693                     if (mTicking) {
   1694                         mTicker.halt();
   1695                     }
   1696                 }
   1697 
   1698                 if (mNavigationBarView != null) {
   1699                     mNavigationBarView.setLowProfile(lightsOut);
   1700                 }
   1701 
   1702                 setStatusBarLowProfile(lightsOut);
   1703             }
   1704 
   1705             notifyUiVisibilityChanged();
   1706         }
   1707     }
   1708 
   1709     private void setStatusBarLowProfile(boolean lightsOut) {
   1710         if (mLightsOutAnimation == null) {
   1711             final View notifications = mStatusBarView.findViewById(R.id.notification_icon_area);
   1712             final View systemIcons = mStatusBarView.findViewById(R.id.statusIcons);
   1713             final View signal = mStatusBarView.findViewById(R.id.signal_cluster);
   1714             final View battery = mStatusBarView.findViewById(R.id.battery);
   1715             final View clock = mStatusBarView.findViewById(R.id.clock);
   1716 
   1717             mLightsOutAnimation = new AnimatorSet();
   1718             mLightsOutAnimation.playTogether(
   1719                     ObjectAnimator.ofFloat(notifications, View.ALPHA, 0),
   1720                     ObjectAnimator.ofFloat(systemIcons, View.ALPHA, 0),
   1721                     ObjectAnimator.ofFloat(signal, View.ALPHA, 0),
   1722                     ObjectAnimator.ofFloat(battery, View.ALPHA, 0.5f),
   1723                     ObjectAnimator.ofFloat(clock, View.ALPHA, 0.5f)
   1724                 );
   1725             mLightsOutAnimation.setDuration(750);
   1726 
   1727             mLightsOnAnimation = new AnimatorSet();
   1728             mLightsOnAnimation.playTogether(
   1729                     ObjectAnimator.ofFloat(notifications, View.ALPHA, 1),
   1730                     ObjectAnimator.ofFloat(systemIcons, View.ALPHA, 1),
   1731                     ObjectAnimator.ofFloat(signal, View.ALPHA, 1),
   1732                     ObjectAnimator.ofFloat(battery, View.ALPHA, 1),
   1733                     ObjectAnimator.ofFloat(clock, View.ALPHA, 1)
   1734                 );
   1735             mLightsOnAnimation.setDuration(250);
   1736         }
   1737 
   1738         mLightsOutAnimation.cancel();
   1739         mLightsOnAnimation.cancel();
   1740 
   1741         final Animator a = lightsOut ? mLightsOutAnimation : mLightsOnAnimation;
   1742         a.start();
   1743 
   1744         setAreThereNotifications();
   1745     }
   1746 
   1747     private boolean areLightsOn() {
   1748         return 0 == (mSystemUiVisibility & View.SYSTEM_UI_FLAG_LOW_PROFILE);
   1749     }
   1750 
   1751     public void setLightsOn(boolean on) {
   1752         Log.v(TAG, "setLightsOn(" + on + ")");
   1753         if (on) {
   1754             setSystemUiVisibility(0, View.SYSTEM_UI_FLAG_LOW_PROFILE);
   1755         } else {
   1756             setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE, View.SYSTEM_UI_FLAG_LOW_PROFILE);
   1757         }
   1758     }
   1759 
   1760     private void notifyUiVisibilityChanged() {
   1761         try {
   1762             mWindowManager.statusBarVisibilityChanged(mSystemUiVisibility);
   1763         } catch (RemoteException ex) {
   1764         }
   1765     }
   1766 
   1767     public void topAppWindowChanged(boolean showMenu) {
   1768         if (DEBUG) {
   1769             Slog.d(TAG, (showMenu?"showing":"hiding") + " the MENU button");
   1770         }
   1771         if (mNavigationBarView != null) {
   1772             mNavigationBarView.setMenuVisibility(showMenu);
   1773         }
   1774 
   1775         // See above re: lights-out policy for legacy apps.
   1776         if (showMenu) setLightsOn(true);
   1777     }
   1778 
   1779     @Override
   1780     public void setImeWindowStatus(IBinder token, int vis, int backDisposition) {
   1781         boolean altBack = (backDisposition == InputMethodService.BACK_DISPOSITION_WILL_DISMISS)
   1782             || ((vis & InputMethodService.IME_VISIBLE) != 0);
   1783 
   1784         mCommandQueue.setNavigationIconHints(
   1785                 altBack ? (mNavigationIconHints | StatusBarManager.NAVIGATION_HINT_BACK_ALT)
   1786                         : (mNavigationIconHints & ~StatusBarManager.NAVIGATION_HINT_BACK_ALT));
   1787     }
   1788 
   1789     @Override
   1790     public void setHardKeyboardStatus(boolean available, boolean enabled) { }
   1791 
   1792     private class NotificationClicker implements View.OnClickListener {
   1793         private PendingIntent mIntent;
   1794         private String mPkg;
   1795         private String mTag;
   1796         private int mId;
   1797 
   1798         NotificationClicker(PendingIntent intent, String pkg, String tag, int id) {
   1799             mIntent = intent;
   1800             mPkg = pkg;
   1801             mTag = tag;
   1802             mId = id;
   1803         }
   1804 
   1805         public void onClick(View v) {
   1806             try {
   1807                 // The intent we are sending is for the application, which
   1808                 // won't have permission to immediately start an activity after
   1809                 // the user switches to home.  We know it is safe to do at this
   1810                 // point, so make sure new activity switches are now allowed.
   1811                 ActivityManagerNative.getDefault().resumeAppSwitches();
   1812                 // Also, notifications can be launched from the lock screen,
   1813                 // so dismiss the lock screen when the activity starts.
   1814                 ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
   1815             } catch (RemoteException e) {
   1816             }
   1817 
   1818             if (mIntent != null) {
   1819                 int[] pos = new int[2];
   1820                 v.getLocationOnScreen(pos);
   1821                 Intent overlay = new Intent();
   1822                 overlay.setSourceBounds(
   1823                         new Rect(pos[0], pos[1], pos[0]+v.getWidth(), pos[1]+v.getHeight()));
   1824                 try {
   1825                     mIntent.send(mContext, 0, overlay);
   1826                 } catch (PendingIntent.CanceledException e) {
   1827                     // the stack trace isn't very helpful here.  Just log the exception message.
   1828                     Slog.w(TAG, "Sending contentIntent failed: " + e);
   1829                 }
   1830 
   1831                 KeyguardManager kgm =
   1832                     (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
   1833                 if (kgm != null) kgm.exitKeyguardSecurely(null);
   1834             }
   1835 
   1836             try {
   1837                 mBarService.onNotificationClick(mPkg, mTag, mId);
   1838             } catch (RemoteException ex) {
   1839                 // system process is dead if we're here.
   1840             }
   1841 
   1842             // close the shade if it was open
   1843             animateCollapse();
   1844 
   1845             // If this click was on the intruder alert, hide that instead
   1846             mHandler.sendEmptyMessage(MSG_HIDE_INTRUDER);
   1847         }
   1848     }
   1849 
   1850     @Override
   1851     protected void tick(IBinder key, StatusBarNotification n, boolean firstTime) {
   1852         // no ticking in lights-out mode
   1853         if (!areLightsOn()) return;
   1854 
   1855         // no ticking in Setup
   1856         if (!isDeviceProvisioned()) return;
   1857 
   1858         // Show the ticker if one is requested. Also don't do this
   1859         // until status bar window is attached to the window manager,
   1860         // because...  well, what's the point otherwise?  And trying to
   1861         // run a ticker without being attached will crash!
   1862         if (n.notification.tickerText != null && mStatusBarWindow.getWindowToken() != null) {
   1863             if (0 == (mDisabled & (StatusBarManager.DISABLE_NOTIFICATION_ICONS
   1864                             | StatusBarManager.DISABLE_NOTIFICATION_TICKER))) {
   1865                 mTicker.addEntry(n);
   1866             }
   1867         }
   1868     }
   1869 
   1870     private class MyTicker extends Ticker {
   1871         MyTicker(Context context, View sb) {
   1872             super(context, sb);
   1873         }
   1874 
   1875         @Override
   1876         public void tickerStarting() {
   1877             mTicking = true;
   1878             mIcons.setVisibility(View.GONE);
   1879             mTickerView.setVisibility(View.VISIBLE);
   1880             mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_up_in, null));
   1881             mIcons.startAnimation(loadAnim(com.android.internal.R.anim.push_up_out, null));
   1882         }
   1883 
   1884         @Override
   1885         public void tickerDone() {
   1886             mIcons.setVisibility(View.VISIBLE);
   1887             mTickerView.setVisibility(View.GONE);
   1888             mIcons.startAnimation(loadAnim(com.android.internal.R.anim.push_down_in, null));
   1889             mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_down_out,
   1890                         mTickingDoneListener));
   1891         }
   1892 
   1893         public void tickerHalting() {
   1894             mIcons.setVisibility(View.VISIBLE);
   1895             mTickerView.setVisibility(View.GONE);
   1896             mIcons.startAnimation(loadAnim(com.android.internal.R.anim.fade_in, null));
   1897             mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.fade_out,
   1898                         mTickingDoneListener));
   1899         }
   1900     }
   1901 
   1902     Animation.AnimationListener mTickingDoneListener = new Animation.AnimationListener() {;
   1903         public void onAnimationEnd(Animation animation) {
   1904             mTicking = false;
   1905         }
   1906         public void onAnimationRepeat(Animation animation) {
   1907         }
   1908         public void onAnimationStart(Animation animation) {
   1909         }
   1910     };
   1911 
   1912     private Animation loadAnim(int id, Animation.AnimationListener listener) {
   1913         Animation anim = AnimationUtils.loadAnimation(mContext, id);
   1914         if (listener != null) {
   1915             anim.setAnimationListener(listener);
   1916         }
   1917         return anim;
   1918     }
   1919 
   1920     public static String viewInfo(View v) {
   1921         return "[(" + v.getLeft() + "," + v.getTop() + ")(" + v.getRight() + "," + v.getBottom()
   1922                 + ") " + v.getWidth() + "x" + v.getHeight() + "]";
   1923     }
   1924 
   1925     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   1926         synchronized (mQueueLock) {
   1927             pw.println("Current Status Bar state:");
   1928             pw.println("  mExpanded=" + mExpanded
   1929                     + ", mExpandedVisible=" + mExpandedVisible
   1930                     + ", mTrackingPosition=" + mTrackingPosition);
   1931             pw.println("  mTicking=" + mTicking);
   1932             pw.println("  mTracking=" + mTracking);
   1933             pw.println("  mNotificationPanel=" +
   1934                     ((mNotificationPanel == null)
   1935                             ? "null"
   1936                             : (mNotificationPanel + " params=" + mNotificationPanel.getLayoutParams().debug(""))));
   1937             pw.println("  mAnimating=" + mAnimating
   1938                     + ", mAnimY=" + mAnimY + ", mAnimVel=" + mAnimVel
   1939                     + ", mAnimAccel=" + mAnimAccel);
   1940             pw.println("  mAnimLastTimeNanos=" + mAnimLastTimeNanos);
   1941             pw.println("  mAnimatingReveal=" + mAnimatingReveal
   1942                     + " mViewDelta=" + mViewDelta);
   1943             pw.println("  mDisplayMetrics=" + mDisplayMetrics);
   1944             pw.println("  mPile: " + viewInfo(mPile));
   1945             pw.println("  mCloseView: " + viewInfo(mCloseView));
   1946             pw.println("  mTickerView: " + viewInfo(mTickerView));
   1947             pw.println("  mScrollView: " + viewInfo(mScrollView)
   1948                     + " scroll " + mScrollView.getScrollX() + "," + mScrollView.getScrollY());
   1949         }
   1950 
   1951         pw.print("  mNavigationBarView=");
   1952         if (mNavigationBarView == null) {
   1953             pw.println("null");
   1954         } else {
   1955             mNavigationBarView.dump(fd, pw, args);
   1956         }
   1957 
   1958         if (DUMPTRUCK) {
   1959             synchronized (mNotificationData) {
   1960                 int N = mNotificationData.size();
   1961                 pw.println("  notification icons: " + N);
   1962                 for (int i=0; i<N; i++) {
   1963                     NotificationData.Entry e = mNotificationData.get(i);
   1964                     pw.println("    [" + i + "] key=" + e.key + " icon=" + e.icon);
   1965                     StatusBarNotification n = e.notification;
   1966                     pw.println("         pkg=" + n.pkg + " id=" + n.id + " score=" + n.score);
   1967                     pw.println("         notification=" + n.notification);
   1968                     pw.println("         tickerText=\"" + n.notification.tickerText + "\"");
   1969                 }
   1970             }
   1971 
   1972             int N = mStatusIcons.getChildCount();
   1973             pw.println("  system icons: " + N);
   1974             for (int i=0; i<N; i++) {
   1975                 StatusBarIconView ic = (StatusBarIconView) mStatusIcons.getChildAt(i);
   1976                 pw.println("    [" + i + "] icon=" + ic);
   1977             }
   1978 
   1979             if (false) {
   1980                 pw.println("see the logcat for a dump of the views we have created.");
   1981                 // must happen on ui thread
   1982                 mHandler.post(new Runnable() {
   1983                         public void run() {
   1984                             mStatusBarView.getLocationOnScreen(mAbsPos);
   1985                             Slog.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
   1986                                     + ") " + mStatusBarView.getWidth() + "x"
   1987                                     + getStatusBarHeight());
   1988                             mStatusBarView.debug();
   1989                         }
   1990                     });
   1991             }
   1992         }
   1993 
   1994         mNetworkController.dump(fd, pw, args);
   1995     }
   1996 
   1997     @Override
   1998     public void createAndAddWindows() {
   1999         addStatusBarWindow();
   2000     }
   2001 
   2002     private void addStatusBarWindow() {
   2003         // Put up the view
   2004         final int height = getStatusBarHeight();
   2005 
   2006         // Now that the status bar window encompasses the sliding panel and its
   2007         // translucent backdrop, the entire thing is made TRANSLUCENT and is
   2008         // hardware-accelerated.
   2009         final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
   2010                 ViewGroup.LayoutParams.MATCH_PARENT,
   2011                 height,
   2012                 WindowManager.LayoutParams.TYPE_STATUS_BAR,
   2013                 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
   2014                     | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
   2015                     | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
   2016                 PixelFormat.TRANSLUCENT);
   2017 
   2018         lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
   2019 
   2020         lp.gravity = getStatusBarGravity();
   2021         lp.setTitle("StatusBar");
   2022         lp.packageName = mContext.getPackageName();
   2023 
   2024         makeStatusBarView();
   2025         WindowManagerImpl.getDefault().addView(mStatusBarWindow, lp);
   2026     }
   2027 
   2028     void setNotificationIconVisibility(boolean visible, int anim) {
   2029         int old = mNotificationIcons.getVisibility();
   2030         int v = visible ? View.VISIBLE : View.INVISIBLE;
   2031         if (old != v) {
   2032             mNotificationIcons.setVisibility(v);
   2033             mNotificationIcons.startAnimation(loadAnim(anim, null));
   2034         }
   2035     }
   2036 
   2037     void updateExpandedInvisiblePosition() {
   2038         mTrackingPosition = -mDisplayMetrics.heightPixels;
   2039     }
   2040 
   2041     static final float saturate(float a) {
   2042         return a < 0f ? 0f : (a > 1f ? 1f : a);
   2043     }
   2044 
   2045     @Override
   2046     protected int getExpandedViewMaxHeight() {
   2047         return mDisplayMetrics.heightPixels - mNotificationPanelMarginBottomPx;
   2048     }
   2049 
   2050     @Override
   2051     protected void updateExpandedViewPos(int expandedPosition) {
   2052         if (SPEW) {
   2053             Slog.d(TAG, "updateExpandedViewPos before expandedPosition=" + expandedPosition
   2054                     //+ " mTrackingParams.y=" + ((mTrackingParams == null) ? "?" : mTrackingParams.y)
   2055                     + " mTrackingPosition=" + mTrackingPosition
   2056                     + " gravity=" + mNotificationPanelGravity);
   2057         }
   2058         int panelh = 0;
   2059         final int disph = getExpandedViewMaxHeight();
   2060 
   2061         // If the expanded view is not visible, make sure they're still off screen.
   2062         // Maybe the view was resized.
   2063         if (!mExpandedVisible) {
   2064             updateExpandedInvisiblePosition();
   2065             return;
   2066         }
   2067 
   2068         // tracking view...
   2069         int pos;
   2070         if (expandedPosition == EXPANDED_FULL_OPEN) {
   2071             panelh = disph;
   2072         }
   2073         else if (expandedPosition == EXPANDED_LEAVE_ALONE) {
   2074             panelh = mTrackingPosition;
   2075         }
   2076         else {
   2077             if (expandedPosition <= disph) {
   2078                 panelh = expandedPosition;
   2079             } else {
   2080                 panelh = disph;
   2081             }
   2082         }
   2083 
   2084         // catch orientation changes and other peculiar cases
   2085         if (panelh > disph || (panelh < disph && !mTracking && !mAnimating)) {
   2086             panelh = disph;
   2087         } else if (panelh < 0) {
   2088             panelh = 0;
   2089         }
   2090 
   2091         if (panelh == mTrackingPosition) return;
   2092 
   2093         mTrackingPosition = panelh;
   2094 
   2095         FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mNotificationPanel.getLayoutParams();
   2096         lp.height = panelh;
   2097         lp.gravity = mNotificationPanelGravity;
   2098         lp.leftMargin = mNotificationPanelMarginLeftPx;
   2099         if (SPEW) {
   2100             Slog.v(TAG, "updated cropView height=" + panelh + " grav=" + lp.gravity);
   2101         }
   2102         mNotificationPanel.setLayoutParams(lp);
   2103 
   2104         final int barh = getCloseViewHeight() + getStatusBarHeight();
   2105         final float frac = saturate((float)(panelh - barh) / (disph - barh));
   2106 
   2107         if (DIM_BEHIND_EXPANDED_PANEL && ActivityManager.isHighEndGfx(mDisplay)) {
   2108             // woo, special effects
   2109             final float k = (float)(1f-0.5f*(1f-Math.cos(3.14159f * Math.pow(1f-frac, 2.2f))));
   2110             final int color = ((int)(0xB0 * k)) << 24;
   2111             mStatusBarWindow.setBackgroundColor(color);
   2112         }
   2113 
   2114         updateCarrierLabelVisibility(false);
   2115     }
   2116 
   2117     void updateDisplaySize() {
   2118         mDisplay.getMetrics(mDisplayMetrics);
   2119     }
   2120 
   2121     void performDisableActions(int net) {
   2122         int old = mDisabled;
   2123         int diff = net ^ old;
   2124         mDisabled = net;
   2125 
   2126         // act accordingly
   2127         if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
   2128             if ((net & StatusBarManager.DISABLE_EXPAND) != 0) {
   2129                 Slog.d(TAG, "DISABLE_EXPAND: yes");
   2130                 animateCollapse();
   2131             }
   2132         }
   2133         if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
   2134             if ((net & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
   2135                 Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: yes");
   2136                 if (mTicking) {
   2137                     mNotificationIcons.setVisibility(View.INVISIBLE);
   2138                     mTicker.halt();
   2139                 } else {
   2140                     setNotificationIconVisibility(false, com.android.internal.R.anim.fade_out);
   2141                 }
   2142             } else {
   2143                 Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: no");
   2144                 if (!mExpandedVisible) {
   2145                     setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
   2146                 }
   2147             }
   2148         } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
   2149             if (mTicking && (net & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
   2150                 mTicker.halt();
   2151             }
   2152         }
   2153     }
   2154 
   2155     private View.OnClickListener mClearButtonListener = new View.OnClickListener() {
   2156         final int mini(int a, int b) {
   2157             return (b>a?a:b);
   2158         }
   2159         public void onClick(View v) {
   2160             synchronized (mNotificationData) {
   2161                 // animate-swipe all dismissable notifications, then animate the shade closed
   2162                 int numChildren = mPile.getChildCount();
   2163 
   2164                 int scrollTop = mScrollView.getScrollY();
   2165                 int scrollBottom = scrollTop + mScrollView.getHeight();
   2166                 final ArrayList<View> snapshot = new ArrayList<View>(numChildren);
   2167                 for (int i=0; i<numChildren; i++) {
   2168                     final View child = mPile.getChildAt(i);
   2169                     if (mPile.canChildBeDismissed(child) && child.getBottom() > scrollTop &&
   2170                             child.getTop() < scrollBottom) {
   2171                         snapshot.add(child);
   2172                     }
   2173                 }
   2174                 if (snapshot.isEmpty()) {
   2175                     animateCollapse(CommandQueue.FLAG_EXCLUDE_NONE);
   2176                     return;
   2177                 }
   2178                 new Thread(new Runnable() {
   2179                     @Override
   2180                     public void run() {
   2181                         // Decrease the delay for every row we animate to give the sense of
   2182                         // accelerating the swipes
   2183                         final int ROW_DELAY_DECREMENT = 10;
   2184                         int currentDelay = 140;
   2185                         int totalDelay = 0;
   2186 
   2187                         // Set the shade-animating state to avoid doing other work during
   2188                         // all of these animations. In particular, avoid layout and
   2189                         // redrawing when collapsing the shade.
   2190                         mPile.setViewRemoval(false);
   2191 
   2192                         mPostCollapseCleanup = new Runnable() {
   2193                             @Override
   2194                             public void run() {
   2195                                 try {
   2196                                     mPile.setViewRemoval(true);
   2197                                     mBarService.onClearAllNotifications();
   2198                                 } catch (Exception ex) { }
   2199                             }
   2200                         };
   2201 
   2202                         View sampleView = snapshot.get(0);
   2203                         int width = sampleView.getWidth();
   2204                         final int velocity = width * 8; // 1000/8 = 125 ms duration
   2205                         for (final View _v : snapshot) {
   2206                             mHandler.postDelayed(new Runnable() {
   2207                                 @Override
   2208                                 public void run() {
   2209                                     mPile.dismissRowAnimated(_v, velocity);
   2210                                 }
   2211                             }, totalDelay);
   2212                             currentDelay = Math.max(50, currentDelay - ROW_DELAY_DECREMENT);
   2213                             totalDelay += currentDelay;
   2214                         }
   2215                         // Delay the collapse animation until after all swipe animations have
   2216                         // finished. Provide some buffer because there may be some extra delay
   2217                         // before actually starting each swipe animation. Ideally, we'd
   2218                         // synchronize the end of those animations with the start of the collaps
   2219                         // exactly.
   2220                         mHandler.postDelayed(new Runnable() {
   2221                             @Override
   2222                             public void run() {
   2223                                 animateCollapse(CommandQueue.FLAG_EXCLUDE_NONE);
   2224                             }
   2225                         }, totalDelay + 225);
   2226                     }
   2227                 }).start();
   2228             }
   2229         }
   2230     };
   2231 
   2232     private View.OnClickListener mSettingsButtonListener = new View.OnClickListener() {
   2233         public void onClick(View v) {
   2234             // We take this as a good indicator that Setup is running and we shouldn't
   2235             // allow you to go somewhere else
   2236             if (!isDeviceProvisioned()) return;
   2237             try {
   2238                 // Dismiss the lock screen when Settings starts.
   2239                 ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
   2240             } catch (RemoteException e) {
   2241             }
   2242             v.getContext().startActivity(new Intent(Settings.ACTION_SETTINGS)
   2243                     .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
   2244             animateCollapse();
   2245         }
   2246     };
   2247 
   2248     private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
   2249         public void onReceive(Context context, Intent intent) {
   2250             String action = intent.getAction();
   2251             if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
   2252                     || Intent.ACTION_SCREEN_OFF.equals(action)) {
   2253                 int flags = CommandQueue.FLAG_EXCLUDE_NONE;
   2254                 if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
   2255                     String reason = intent.getStringExtra("reason");
   2256                     if (reason != null && reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) {
   2257                         flags |= CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL;
   2258                     }
   2259                 }
   2260                 animateCollapse(flags);
   2261             }
   2262             else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
   2263                 updateResources();
   2264                 repositionNavigationBar();
   2265                 updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
   2266             }
   2267         }
   2268     };
   2269 
   2270     private void setIntruderAlertVisibility(boolean vis) {
   2271         if (!ENABLE_INTRUDERS) return;
   2272         if (DEBUG) {
   2273             Slog.v(TAG, (vis ? "showing" : "hiding") + " intruder alert window");
   2274         }
   2275         mIntruderAlertView.setVisibility(vis ? View.VISIBLE : View.GONE);
   2276     }
   2277 
   2278     public void dismissIntruder() {
   2279         if (mCurrentlyIntrudingNotification == null) return;
   2280 
   2281         try {
   2282             mBarService.onNotificationClear(
   2283                     mCurrentlyIntrudingNotification.pkg,
   2284                     mCurrentlyIntrudingNotification.tag,
   2285                     mCurrentlyIntrudingNotification.id);
   2286         } catch (android.os.RemoteException ex) {
   2287             // oh well
   2288         }
   2289     }
   2290 
   2291     /**
   2292      * Reload some of our resources when the configuration changes.
   2293      *
   2294      * We don't reload everything when the configuration changes -- we probably
   2295      * should, but getting that smooth is tough.  Someday we'll fix that.  In the
   2296      * meantime, just update the things that we know change.
   2297      */
   2298     void updateResources() {
   2299         final Context context = mContext;
   2300         final Resources res = context.getResources();
   2301 
   2302         if (mClearButton instanceof TextView) {
   2303             ((TextView)mClearButton).setText(context.getText(R.string.status_bar_clear_all_button));
   2304         }
   2305         loadDimens();
   2306     }
   2307 
   2308     protected void loadDimens() {
   2309         final Resources res = mContext.getResources();
   2310 
   2311         mNaturalBarHeight = res.getDimensionPixelSize(
   2312                 com.android.internal.R.dimen.status_bar_height);
   2313 
   2314         int newIconSize = res.getDimensionPixelSize(
   2315             com.android.internal.R.dimen.status_bar_icon_size);
   2316         int newIconHPadding = res.getDimensionPixelSize(
   2317             R.dimen.status_bar_icon_padding);
   2318 
   2319         if (newIconHPadding != mIconHPadding || newIconSize != mIconSize) {
   2320 //            Slog.d(TAG, "size=" + newIconSize + " padding=" + newIconHPadding);
   2321             mIconHPadding = newIconHPadding;
   2322             mIconSize = newIconSize;
   2323             //reloadAllNotificationIcons(); // reload the tray
   2324         }
   2325 
   2326         mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore);
   2327 
   2328         mSelfExpandVelocityPx = res.getDimension(R.dimen.self_expand_velocity);
   2329         mSelfCollapseVelocityPx = res.getDimension(R.dimen.self_collapse_velocity);
   2330         mFlingExpandMinVelocityPx = res.getDimension(R.dimen.fling_expand_min_velocity);
   2331         mFlingCollapseMinVelocityPx = res.getDimension(R.dimen.fling_collapse_min_velocity);
   2332 
   2333         mCollapseMinDisplayFraction = res.getFraction(R.dimen.collapse_min_display_fraction, 1, 1);
   2334         mExpandMinDisplayFraction = res.getFraction(R.dimen.expand_min_display_fraction, 1, 1);
   2335 
   2336         mExpandAccelPx = res.getDimension(R.dimen.expand_accel);
   2337         mCollapseAccelPx = res.getDimension(R.dimen.collapse_accel);
   2338 
   2339         mFlingGestureMaxXVelocityPx = res.getDimension(R.dimen.fling_gesture_max_x_velocity);
   2340 
   2341         mFlingGestureMaxOutputVelocityPx = res.getDimension(R.dimen.fling_gesture_max_output_velocity);
   2342 
   2343         mNotificationPanelMarginBottomPx
   2344             = (int) res.getDimension(R.dimen.notification_panel_margin_bottom);
   2345         mNotificationPanelMarginLeftPx
   2346             = (int) res.getDimension(R.dimen.notification_panel_margin_left);
   2347         mNotificationPanelGravity = res.getInteger(R.integer.notification_panel_layout_gravity);
   2348         if (mNotificationPanelGravity <= 0) {
   2349             mNotificationPanelGravity = Gravity.CENTER_VERTICAL | Gravity.TOP;
   2350         }
   2351         getNinePatchPadding(res.getDrawable(R.drawable.notification_panel_bg), mNotificationPanelBackgroundPadding);
   2352         final int notificationPanelDecorationHeight =
   2353               res.getDimensionPixelSize(R.dimen.notification_panel_padding_top)
   2354             + res.getDimensionPixelSize(R.dimen.notification_panel_header_height)
   2355             + mNotificationPanelBackgroundPadding.top
   2356             + mNotificationPanelBackgroundPadding.bottom;
   2357         mNotificationPanelMinHeight =
   2358               notificationPanelDecorationHeight
   2359             + res.getDimensionPixelSize(R.dimen.close_handle_underlap);
   2360 
   2361         mCarrierLabelHeight = res.getDimensionPixelSize(R.dimen.carrier_label_height);
   2362 
   2363         if (false) Slog.v(TAG, "updateResources");
   2364     }
   2365 
   2366     private static void getNinePatchPadding(Drawable d, Rect outPadding) {
   2367         if (d instanceof NinePatchDrawable) {
   2368             NinePatchDrawable ninePatch = (NinePatchDrawable) d;
   2369             ninePatch.getPadding(outPadding);
   2370         }
   2371     }
   2372 
   2373     //
   2374     // tracing
   2375     //
   2376 
   2377     void postStartTracing() {
   2378         mHandler.postDelayed(mStartTracing, 3000);
   2379     }
   2380 
   2381     void vibrate() {
   2382         android.os.Vibrator vib = (android.os.Vibrator)mContext.getSystemService(
   2383                 Context.VIBRATOR_SERVICE);
   2384         vib.vibrate(250);
   2385     }
   2386 
   2387     Runnable mStartTracing = new Runnable() {
   2388         public void run() {
   2389             vibrate();
   2390             SystemClock.sleep(250);
   2391             Slog.d(TAG, "startTracing");
   2392             android.os.Debug.startMethodTracing("/data/statusbar-traces/trace");
   2393             mHandler.postDelayed(mStopTracing, 10000);
   2394         }
   2395     };
   2396 
   2397     Runnable mStopTracing = new Runnable() {
   2398         public void run() {
   2399             android.os.Debug.stopMethodTracing();
   2400             Slog.d(TAG, "stopTracing");
   2401             vibrate();
   2402         }
   2403     };
   2404 
   2405     @Override
   2406     protected void haltTicker() {
   2407         mTicker.halt();
   2408     }
   2409 
   2410     @Override
   2411     protected boolean shouldDisableNavbarGestures() {
   2412         return mExpanded || (mDisabled & StatusBarManager.DISABLE_HOME) != 0;
   2413     }
   2414 
   2415     private static class FastColorDrawable extends Drawable {
   2416         private final int mColor;
   2417 
   2418         public FastColorDrawable(int color) {
   2419             mColor = 0xff000000 | color;
   2420         }
   2421 
   2422         @Override
   2423         public void draw(Canvas canvas) {
   2424             canvas.drawColor(mColor, PorterDuff.Mode.SRC);
   2425         }
   2426 
   2427         @Override
   2428         public void setAlpha(int alpha) {
   2429         }
   2430 
   2431         @Override
   2432         public void setColorFilter(ColorFilter cf) {
   2433         }
   2434 
   2435         @Override
   2436         public int getOpacity() {
   2437             return PixelFormat.OPAQUE;
   2438         }
   2439 
   2440         @Override
   2441         public void setBounds(int left, int top, int right, int bottom) {
   2442         }
   2443 
   2444         @Override
   2445         public void setBounds(Rect bounds) {
   2446         }
   2447     }
   2448 }
   2449