Home | History | Annotate | Download | only in phone
      1 /*
      2  * Copyright (C) 2008 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.LayoutTransition;
     20 import android.animation.LayoutTransition.TransitionListener;
     21 import android.animation.ObjectAnimator;
     22 import android.animation.TimeInterpolator;
     23 import android.animation.ValueAnimator;
     24 import android.app.ActivityManagerNative;
     25 import android.app.StatusBarManager;
     26 import android.app.admin.DevicePolicyManager;
     27 import android.content.BroadcastReceiver;
     28 import android.content.Context;
     29 import android.content.Intent;
     30 import android.content.IntentFilter;
     31 import android.content.res.Resources;
     32 import android.graphics.Point;
     33 import android.graphics.Rect;
     34 import android.graphics.drawable.Drawable;
     35 import android.os.Handler;
     36 import android.os.Message;
     37 import android.os.RemoteException;
     38 import android.util.AttributeSet;
     39 import android.util.Log;
     40 import android.view.Display;
     41 import android.view.MotionEvent;
     42 import android.view.Surface;
     43 import android.view.View;
     44 import android.view.ViewGroup;
     45 import android.view.WindowManager;
     46 import android.view.accessibility.AccessibilityManager;
     47 import android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener;
     48 import android.widget.ImageView;
     49 import android.widget.LinearLayout;
     50 
     51 import com.android.systemui.R;
     52 import com.android.systemui.statusbar.BaseStatusBar;
     53 import com.android.systemui.statusbar.DelegateViewHelper;
     54 import com.android.systemui.statusbar.policy.DeadZone;
     55 import com.android.systemui.statusbar.policy.KeyButtonView;
     56 
     57 import java.io.FileDescriptor;
     58 import java.io.PrintWriter;
     59 
     60 public class NavigationBarView extends LinearLayout {
     61     final static boolean DEBUG = false;
     62     final static String TAG = "PhoneStatusBar/NavigationBarView";
     63 
     64     final static boolean NAVBAR_ALWAYS_AT_RIGHT = true;
     65 
     66     // slippery nav bar when everything is disabled, e.g. during setup
     67     final static boolean SLIPPERY_WHEN_DISABLED = true;
     68 
     69     final Display mDisplay;
     70     View mCurrentView = null;
     71     View[] mRotatedViews = new View[4];
     72 
     73     int mBarSize;
     74     boolean mVertical;
     75     boolean mScreenOn;
     76 
     77     boolean mShowMenu;
     78     int mDisabledFlags = 0;
     79     int mNavigationIconHints = 0;
     80 
     81     private Drawable mBackIcon, mBackLandIcon, mBackAltIcon, mBackAltLandIcon;
     82     private Drawable mRecentIcon;
     83     private Drawable mRecentLandIcon;
     84 
     85     private DelegateViewHelper mDelegateHelper;
     86     private DeadZone mDeadZone;
     87     private final NavigationBarTransitions mBarTransitions;
     88 
     89     // workaround for LayoutTransitions leaving the nav buttons in a weird state (bug 5549288)
     90     final static boolean WORKAROUND_INVALID_LAYOUT = true;
     91     final static int MSG_CHECK_INVALID_LAYOUT = 8686;
     92 
     93     // used to disable the camera icon in navbar when disabled by DPM
     94     private boolean mCameraDisabledByDpm;
     95 
     96     // performs manual animation in sync with layout transitions
     97     private final NavTransitionListener mTransitionListener = new NavTransitionListener();
     98 
     99     private class NavTransitionListener implements TransitionListener {
    100         private boolean mBackTransitioning;
    101         private boolean mHomeAppearing;
    102         private long mStartDelay;
    103         private long mDuration;
    104         private TimeInterpolator mInterpolator;
    105 
    106         @Override
    107         public void startTransition(LayoutTransition transition, ViewGroup container,
    108                 View view, int transitionType) {
    109             if (view.getId() == R.id.back) {
    110                 mBackTransitioning = true;
    111             } else if (view.getId() == R.id.home && transitionType == LayoutTransition.APPEARING) {
    112                 mHomeAppearing = true;
    113                 mStartDelay = transition.getStartDelay(transitionType);
    114                 mDuration = transition.getDuration(transitionType);
    115                 mInterpolator = transition.getInterpolator(transitionType);
    116             }
    117         }
    118 
    119         @Override
    120         public void endTransition(LayoutTransition transition, ViewGroup container,
    121                 View view, int transitionType) {
    122             if (view.getId() == R.id.back) {
    123                 mBackTransitioning = false;
    124             } else if (view.getId() == R.id.home && transitionType == LayoutTransition.APPEARING) {
    125                 mHomeAppearing = false;
    126             }
    127         }
    128 
    129         public void onBackAltCleared() {
    130             // When dismissing ime during unlock, force the back button to run the same appearance
    131             // animation as home (if we catch this condition early enough).
    132             if (!mBackTransitioning && getBackButton().getVisibility() == VISIBLE
    133                     && mHomeAppearing && getHomeButton().getAlpha() == 0) {
    134                 getBackButton().setAlpha(0);
    135                 ValueAnimator a = ObjectAnimator.ofFloat(getBackButton(), "alpha", 0, 1);
    136                 a.setStartDelay(mStartDelay);
    137                 a.setDuration(mDuration);
    138                 a.setInterpolator(mInterpolator);
    139                 a.start();
    140             }
    141         }
    142     }
    143 
    144     // simplified click handler to be used when device is in accessibility mode
    145     private final OnClickListener mAccessibilityClickListener = new OnClickListener() {
    146         @Override
    147         public void onClick(View v) {
    148             if (v.getId() == R.id.camera_button) {
    149                 KeyguardTouchDelegate.getInstance(getContext()).launchCamera();
    150             } else if (v.getId() == R.id.search_light) {
    151                 KeyguardTouchDelegate.getInstance(getContext()).showAssistant();
    152             }
    153         }
    154     };
    155 
    156     private final OnTouchListener mCameraTouchListener = new OnTouchListener() {
    157         @Override
    158         public boolean onTouch(View cameraButtonView, MotionEvent event) {
    159             switch (event.getAction()) {
    160                 case MotionEvent.ACTION_DOWN:
    161                     // disable search gesture while interacting with camera
    162                     mDelegateHelper.setDisabled(true);
    163                     mBarTransitions.setContentVisible(false);
    164                     break;
    165                 case MotionEvent.ACTION_UP:
    166                 case MotionEvent.ACTION_CANCEL:
    167                     mDelegateHelper.setDisabled(false);
    168                     mBarTransitions.setContentVisible(true);
    169                     break;
    170             }
    171             return KeyguardTouchDelegate.getInstance(getContext()).dispatch(event);
    172         }
    173     };
    174 
    175     private class H extends Handler {
    176         public void handleMessage(Message m) {
    177             switch (m.what) {
    178                 case MSG_CHECK_INVALID_LAYOUT:
    179                     final String how = "" + m.obj;
    180                     final int w = getWidth();
    181                     final int h = getHeight();
    182                     final int vw = mCurrentView.getWidth();
    183                     final int vh = mCurrentView.getHeight();
    184 
    185                     if (h != vh || w != vw) {
    186                         Log.w(TAG, String.format(
    187                             "*** Invalid layout in navigation bar (%s this=%dx%d cur=%dx%d)",
    188                             how, w, h, vw, vh));
    189                         if (WORKAROUND_INVALID_LAYOUT) {
    190                             requestLayout();
    191                         }
    192                     }
    193                     break;
    194             }
    195         }
    196     }
    197 
    198     public NavigationBarView(Context context, AttributeSet attrs) {
    199         super(context, attrs);
    200 
    201         mDisplay = ((WindowManager)context.getSystemService(
    202                 Context.WINDOW_SERVICE)).getDefaultDisplay();
    203 
    204         final Resources res = mContext.getResources();
    205         mBarSize = res.getDimensionPixelSize(R.dimen.navigation_bar_size);
    206         mVertical = false;
    207         mShowMenu = false;
    208         mDelegateHelper = new DelegateViewHelper(this);
    209 
    210         getIcons(res);
    211 
    212         mBarTransitions = new NavigationBarTransitions(this);
    213 
    214         mCameraDisabledByDpm = isCameraDisabledByDpm();
    215         watchForDevicePolicyChanges();
    216     }
    217 
    218     private void watchForDevicePolicyChanges() {
    219         final IntentFilter filter = new IntentFilter();
    220         filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
    221         mContext.registerReceiver(new BroadcastReceiver() {
    222             public void onReceive(Context context, Intent intent) {
    223                 post(new Runnable() {
    224                     @Override
    225                     public void run() {
    226                         mCameraDisabledByDpm = isCameraDisabledByDpm();
    227                     }
    228                 });
    229             }
    230         }, filter);
    231     }
    232 
    233     public BarTransitions getBarTransitions() {
    234         return mBarTransitions;
    235     }
    236 
    237     public void setDelegateView(View view) {
    238         mDelegateHelper.setDelegateView(view);
    239     }
    240 
    241     public void setBar(BaseStatusBar phoneStatusBar) {
    242         mDelegateHelper.setBar(phoneStatusBar);
    243     }
    244 
    245     @Override
    246     public boolean onTouchEvent(MotionEvent event) {
    247         if (mDeadZone != null && event.getAction() == MotionEvent.ACTION_OUTSIDE) {
    248             mDeadZone.poke(event);
    249         }
    250         if (mDelegateHelper != null) {
    251             boolean ret = mDelegateHelper.onInterceptTouchEvent(event);
    252             if (ret) return true;
    253         }
    254         return super.onTouchEvent(event);
    255     }
    256 
    257     @Override
    258     public boolean onInterceptTouchEvent(MotionEvent event) {
    259         return mDelegateHelper.onInterceptTouchEvent(event);
    260     }
    261 
    262     private H mHandler = new H();
    263 
    264     public View getCurrentView() {
    265         return mCurrentView;
    266     }
    267 
    268     public View getRecentsButton() {
    269         return mCurrentView.findViewById(R.id.recent_apps);
    270     }
    271 
    272     public View getMenuButton() {
    273         return mCurrentView.findViewById(R.id.menu);
    274     }
    275 
    276     public View getBackButton() {
    277         return mCurrentView.findViewById(R.id.back);
    278     }
    279 
    280     public View getHomeButton() {
    281         return mCurrentView.findViewById(R.id.home);
    282     }
    283 
    284     // for when home is disabled, but search isn't
    285     public View getSearchLight() {
    286         return mCurrentView.findViewById(R.id.search_light);
    287     }
    288 
    289     // shown when keyguard is visible and camera is available
    290     public View getCameraButton() {
    291         return mCurrentView.findViewById(R.id.camera_button);
    292     }
    293 
    294     private void getIcons(Resources res) {
    295         mBackIcon = res.getDrawable(R.drawable.ic_sysbar_back);
    296         mBackLandIcon = res.getDrawable(R.drawable.ic_sysbar_back_land);
    297         mBackAltIcon = res.getDrawable(R.drawable.ic_sysbar_back_ime);
    298         mBackAltLandIcon = res.getDrawable(R.drawable.ic_sysbar_back_ime);
    299         mRecentIcon = res.getDrawable(R.drawable.ic_sysbar_recent);
    300         mRecentLandIcon = res.getDrawable(R.drawable.ic_sysbar_recent_land);
    301     }
    302 
    303     @Override
    304     public void setLayoutDirection(int layoutDirection) {
    305         getIcons(mContext.getResources());
    306 
    307         super.setLayoutDirection(layoutDirection);
    308     }
    309 
    310     public void notifyScreenOn(boolean screenOn) {
    311         mScreenOn = screenOn;
    312         setDisabledFlags(mDisabledFlags, true);
    313     }
    314 
    315     public void setNavigationIconHints(int hints) {
    316         setNavigationIconHints(hints, false);
    317     }
    318 
    319     public void setNavigationIconHints(int hints, boolean force) {
    320         if (!force && hints == mNavigationIconHints) return;
    321         final boolean backAlt = (hints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
    322         if ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0 && !backAlt) {
    323             mTransitionListener.onBackAltCleared();
    324         }
    325         if (DEBUG) {
    326             android.widget.Toast.makeText(mContext,
    327                 "Navigation icon hints = " + hints,
    328                 500).show();
    329         }
    330 
    331         mNavigationIconHints = hints;
    332 
    333         ((ImageView)getBackButton()).setImageDrawable(backAlt
    334                 ? (mVertical ? mBackAltLandIcon : mBackAltIcon)
    335                 : (mVertical ? mBackLandIcon : mBackIcon));
    336 
    337         ((ImageView)getRecentsButton()).setImageDrawable(mVertical ? mRecentLandIcon : mRecentIcon);
    338 
    339         setDisabledFlags(mDisabledFlags, true);
    340     }
    341 
    342     public void setDisabledFlags(int disabledFlags) {
    343         setDisabledFlags(disabledFlags, false);
    344     }
    345 
    346     public void setDisabledFlags(int disabledFlags, boolean force) {
    347         if (!force && mDisabledFlags == disabledFlags) return;
    348 
    349         mDisabledFlags = disabledFlags;
    350 
    351         final boolean disableHome = ((disabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0);
    352         final boolean disableRecent = ((disabledFlags & View.STATUS_BAR_DISABLE_RECENT) != 0);
    353         final boolean disableBack = ((disabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0)
    354                 && ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) == 0);
    355         final boolean disableSearch = ((disabledFlags & View.STATUS_BAR_DISABLE_SEARCH) != 0);
    356 
    357         if (SLIPPERY_WHEN_DISABLED) {
    358             setSlippery(disableHome && disableRecent && disableBack && disableSearch);
    359         }
    360 
    361         ViewGroup navButtons = (ViewGroup) mCurrentView.findViewById(R.id.nav_buttons);
    362         if (navButtons != null) {
    363             LayoutTransition lt = navButtons.getLayoutTransition();
    364             if (lt != null) {
    365                 if (!lt.getTransitionListeners().contains(mTransitionListener)) {
    366                     lt.addTransitionListener(mTransitionListener);
    367                 }
    368                 if (!mScreenOn && mCurrentView != null) {
    369                     lt.disableTransitionType(
    370                             LayoutTransition.CHANGE_APPEARING |
    371                             LayoutTransition.CHANGE_DISAPPEARING |
    372                             LayoutTransition.APPEARING |
    373                             LayoutTransition.DISAPPEARING);
    374                 }
    375             }
    376         }
    377 
    378         getBackButton()   .setVisibility(disableBack       ? View.INVISIBLE : View.VISIBLE);
    379         getHomeButton()   .setVisibility(disableHome       ? View.INVISIBLE : View.VISIBLE);
    380         getRecentsButton().setVisibility(disableRecent     ? View.INVISIBLE : View.VISIBLE);
    381 
    382         final boolean showSearch = disableHome && !disableSearch;
    383         final boolean showCamera = showSearch && !mCameraDisabledByDpm;
    384         setVisibleOrGone(getSearchLight(), showSearch);
    385         setVisibleOrGone(getCameraButton(), showCamera);
    386 
    387         mBarTransitions.applyBackButtonQuiescentAlpha(mBarTransitions.getMode(), true /*animate*/);
    388     }
    389 
    390     private void setVisibleOrGone(View view, boolean visible) {
    391         if (view != null) {
    392             view.setVisibility(visible ? VISIBLE : GONE);
    393         }
    394     }
    395 
    396     private boolean isCameraDisabledByDpm() {
    397         final DevicePolicyManager dpm =
    398                 (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
    399         if (dpm != null) {
    400             try {
    401                 final int userId = ActivityManagerNative.getDefault().getCurrentUser().id;
    402                 final int disabledFlags = dpm.getKeyguardDisabledFeatures(null, userId);
    403                 final  boolean disabledBecauseKeyguardSecure =
    404                         (disabledFlags & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0
    405                         && KeyguardTouchDelegate.getInstance(getContext()).isSecure();
    406                 return dpm.getCameraDisabled(null) || disabledBecauseKeyguardSecure;
    407             } catch (RemoteException e) {
    408                 Log.e(TAG, "Can't get userId", e);
    409             }
    410         }
    411         return false;
    412     }
    413 
    414     public void setSlippery(boolean newSlippery) {
    415         WindowManager.LayoutParams lp = (WindowManager.LayoutParams) getLayoutParams();
    416         if (lp != null) {
    417             boolean oldSlippery = (lp.flags & WindowManager.LayoutParams.FLAG_SLIPPERY) != 0;
    418             if (!oldSlippery && newSlippery) {
    419                 lp.flags |= WindowManager.LayoutParams.FLAG_SLIPPERY;
    420             } else if (oldSlippery && !newSlippery) {
    421                 lp.flags &= ~WindowManager.LayoutParams.FLAG_SLIPPERY;
    422             } else {
    423                 return;
    424             }
    425             WindowManager wm = (WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE);
    426             wm.updateViewLayout(this, lp);
    427         }
    428     }
    429 
    430     public void setMenuVisibility(final boolean show) {
    431         setMenuVisibility(show, false);
    432     }
    433 
    434     public void setMenuVisibility(final boolean show, final boolean force) {
    435         if (!force && mShowMenu == show) return;
    436 
    437         mShowMenu = show;
    438 
    439         getMenuButton().setVisibility(mShowMenu ? View.VISIBLE : View.INVISIBLE);
    440     }
    441 
    442     @Override
    443     public void onFinishInflate() {
    444         mRotatedViews[Surface.ROTATION_0] =
    445         mRotatedViews[Surface.ROTATION_180] = findViewById(R.id.rot0);
    446 
    447         mRotatedViews[Surface.ROTATION_90] = findViewById(R.id.rot90);
    448 
    449         mRotatedViews[Surface.ROTATION_270] = NAVBAR_ALWAYS_AT_RIGHT
    450                                                 ? findViewById(R.id.rot90)
    451                                                 : findViewById(R.id.rot270);
    452 
    453         mCurrentView = mRotatedViews[Surface.ROTATION_0];
    454 
    455         watchForAccessibilityChanges();
    456     }
    457 
    458     private void watchForAccessibilityChanges() {
    459         final AccessibilityManager am =
    460                 (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
    461 
    462         // Set the initial state
    463         enableAccessibility(am.isTouchExplorationEnabled());
    464 
    465         // Watch for changes
    466         am.addTouchExplorationStateChangeListener(new TouchExplorationStateChangeListener() {
    467             @Override
    468             public void onTouchExplorationStateChanged(boolean enabled) {
    469                 enableAccessibility(enabled);
    470             }
    471         });
    472     }
    473 
    474     private void enableAccessibility(boolean touchEnabled) {
    475         Log.v(TAG, "touchEnabled:"  + touchEnabled);
    476 
    477         // Add a touch handler or accessibility click listener for camera and search buttons
    478         // for all view orientations.
    479         final OnClickListener onClickListener = touchEnabled ? mAccessibilityClickListener : null;
    480         final OnTouchListener onTouchListener = touchEnabled ? null : mCameraTouchListener;
    481         boolean hasCamera = false;
    482         for (int i = 0; i < mRotatedViews.length; i++) {
    483             final View cameraButton = mRotatedViews[i].findViewById(R.id.camera_button);
    484             final View searchLight = mRotatedViews[i].findViewById(R.id.search_light);
    485             if (cameraButton != null) {
    486                 hasCamera = true;
    487                 cameraButton.setOnTouchListener(onTouchListener);
    488                 cameraButton.setOnClickListener(onClickListener);
    489             }
    490             if (searchLight != null) {
    491                 searchLight.setOnClickListener(onClickListener);
    492             }
    493         }
    494         if (hasCamera) {
    495             // Warm up KeyguardTouchDelegate so it's ready by the time the camera button is touched.
    496             // This will connect to KeyguardService so that touch events are processed.
    497             KeyguardTouchDelegate.getInstance(mContext);
    498         }
    499     }
    500 
    501     public boolean isVertical() {
    502         return mVertical;
    503     }
    504 
    505     public void reorient() {
    506         final int rot = mDisplay.getRotation();
    507         for (int i=0; i<4; i++) {
    508             mRotatedViews[i].setVisibility(View.GONE);
    509         }
    510         mCurrentView = mRotatedViews[rot];
    511         mCurrentView.setVisibility(View.VISIBLE);
    512 
    513         mDeadZone = (DeadZone) mCurrentView.findViewById(R.id.deadzone);
    514 
    515         // force the low profile & disabled states into compliance
    516         mBarTransitions.init(mVertical);
    517         setDisabledFlags(mDisabledFlags, true /* force */);
    518         setMenuVisibility(mShowMenu, true /* force */);
    519 
    520         if (DEBUG) {
    521             Log.d(TAG, "reorient(): rot=" + mDisplay.getRotation());
    522         }
    523 
    524         setNavigationIconHints(mNavigationIconHints, true);
    525     }
    526 
    527     @Override
    528     protected void onLayout(boolean changed, int l, int t, int r, int b) {
    529         super.onLayout(changed, l, t, r, b);
    530         mDelegateHelper.setInitialTouchRegion(getHomeButton(), getBackButton(), getRecentsButton());
    531     }
    532 
    533     @Override
    534     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    535         if (DEBUG) Log.d(TAG, String.format(
    536                     "onSizeChanged: (%dx%d) old: (%dx%d)", w, h, oldw, oldh));
    537 
    538         final boolean newVertical = w > 0 && h > w;
    539         if (newVertical != mVertical) {
    540             mVertical = newVertical;
    541             //Log.v(TAG, String.format("onSizeChanged: h=%d, w=%d, vert=%s", h, w, mVertical?"y":"n"));
    542             reorient();
    543         }
    544 
    545         postCheckForInvalidLayout("sizeChanged");
    546         super.onSizeChanged(w, h, oldw, oldh);
    547     }
    548 
    549     /*
    550     @Override
    551     protected void onLayout (boolean changed, int left, int top, int right, int bottom) {
    552         if (DEBUG) Log.d(TAG, String.format(
    553                     "onLayout: %s (%d,%d,%d,%d)",
    554                     changed?"changed":"notchanged", left, top, right, bottom));
    555         super.onLayout(changed, left, top, right, bottom);
    556     }
    557 
    558     // uncomment this for extra defensiveness in WORKAROUND_INVALID_LAYOUT situations: if all else
    559     // fails, any touch on the display will fix the layout.
    560     @Override
    561     public boolean onInterceptTouchEvent(MotionEvent ev) {
    562         if (DEBUG) Log.d(TAG, "onInterceptTouchEvent: " + ev.toString());
    563         if (ev.getAction() == MotionEvent.ACTION_DOWN) {
    564             postCheckForInvalidLayout("touch");
    565         }
    566         return super.onInterceptTouchEvent(ev);
    567     }
    568     */
    569 
    570 
    571     private String getResourceName(int resId) {
    572         if (resId != 0) {
    573             final android.content.res.Resources res = mContext.getResources();
    574             try {
    575                 return res.getResourceName(resId);
    576             } catch (android.content.res.Resources.NotFoundException ex) {
    577                 return "(unknown)";
    578             }
    579         } else {
    580             return "(null)";
    581         }
    582     }
    583 
    584     private void postCheckForInvalidLayout(final String how) {
    585         mHandler.obtainMessage(MSG_CHECK_INVALID_LAYOUT, 0, 0, how).sendToTarget();
    586     }
    587 
    588     private static String visibilityToString(int vis) {
    589         switch (vis) {
    590             case View.INVISIBLE:
    591                 return "INVISIBLE";
    592             case View.GONE:
    593                 return "GONE";
    594             default:
    595                 return "VISIBLE";
    596         }
    597     }
    598 
    599     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    600         pw.println("NavigationBarView {");
    601         final Rect r = new Rect();
    602         final Point size = new Point();
    603         mDisplay.getRealSize(size);
    604 
    605         pw.println(String.format("      this: " + PhoneStatusBar.viewInfo(this)
    606                         + " " + visibilityToString(getVisibility())));
    607 
    608         getWindowVisibleDisplayFrame(r);
    609         final boolean offscreen = r.right > size.x || r.bottom > size.y;
    610         pw.println("      window: "
    611                 + r.toShortString()
    612                 + " " + visibilityToString(getWindowVisibility())
    613                 + (offscreen ? " OFFSCREEN!" : ""));
    614 
    615         pw.println(String.format("      mCurrentView: id=%s (%dx%d) %s",
    616                         getResourceName(mCurrentView.getId()),
    617                         mCurrentView.getWidth(), mCurrentView.getHeight(),
    618                         visibilityToString(mCurrentView.getVisibility())));
    619 
    620         pw.println(String.format("      disabled=0x%08x vertical=%s menu=%s",
    621                         mDisabledFlags,
    622                         mVertical ? "true" : "false",
    623                         mShowMenu ? "true" : "false"));
    624 
    625         dumpButton(pw, "back", getBackButton());
    626         dumpButton(pw, "home", getHomeButton());
    627         dumpButton(pw, "rcnt", getRecentsButton());
    628         dumpButton(pw, "menu", getMenuButton());
    629         dumpButton(pw, "srch", getSearchLight());
    630         dumpButton(pw, "cmra", getCameraButton());
    631 
    632         pw.println("    }");
    633     }
    634 
    635     private static void dumpButton(PrintWriter pw, String caption, View button) {
    636         pw.print("      " + caption + ": ");
    637         if (button == null) {
    638             pw.print("null");
    639         } else {
    640             pw.print(PhoneStatusBar.viewInfo(button)
    641                     + " " + visibilityToString(button.getVisibility())
    642                     + " alpha=" + button.getAlpha()
    643                     );
    644             if (button instanceof KeyButtonView) {
    645                 pw.print(" drawingAlpha=" + ((KeyButtonView)button).getDrawingAlpha());
    646                 pw.print(" quiescentAlpha=" + ((KeyButtonView)button).getQuiescentAlpha());
    647             }
    648         }
    649         pw.println();
    650     }
    651 
    652 }
    653