NavigationBarView.java revision 10e71e014ad730a3960603c4e4706a61168e0b46
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
17package com.android.systemui.statusbar.phone;
18
19import android.animation.LayoutTransition;
20import android.animation.LayoutTransition.TransitionListener;
21import android.animation.ObjectAnimator;
22import android.animation.TimeInterpolator;
23import android.animation.ValueAnimator;
24import android.app.ActivityManagerNative;
25import android.app.StatusBarManager;
26import android.app.admin.DevicePolicyManager;
27import android.content.BroadcastReceiver;
28import android.content.Context;
29import android.content.Intent;
30import android.content.IntentFilter;
31import android.content.res.Resources;
32import android.graphics.Point;
33import android.graphics.Rect;
34import android.graphics.drawable.Drawable;
35import android.os.Handler;
36import android.os.Message;
37import android.os.RemoteException;
38import android.util.AttributeSet;
39import android.util.Log;
40import android.view.Display;
41import android.view.MotionEvent;
42import android.view.Surface;
43import android.view.View;
44import android.view.ViewGroup;
45import android.view.WindowManager;
46import android.view.accessibility.AccessibilityManager;
47import android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener;
48import android.widget.ImageView;
49import android.widget.LinearLayout;
50
51import com.android.systemui.R;
52import com.android.systemui.statusbar.BaseStatusBar;
53import com.android.systemui.statusbar.DelegateViewHelper;
54import com.android.systemui.statusbar.policy.DeadZone;
55import com.android.systemui.statusbar.policy.KeyButtonView;
56
57import java.io.FileDescriptor;
58import java.io.PrintWriter;
59
60public 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        // swap to x coordinate if orientation is not in vertical
525        if (mDelegateHelper != null) {
526            mDelegateHelper.setSwapXY(!mVertical);
527        }
528
529        setNavigationIconHints(mNavigationIconHints, true);
530    }
531
532    @Override
533    protected void onLayout(boolean changed, int l, int t, int r, int b) {
534        super.onLayout(changed, l, t, r, b);
535        mDelegateHelper.setInitialTouchRegion(getHomeButton(), getBackButton(), getRecentsButton());
536    }
537
538    @Override
539    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
540        if (DEBUG) Log.d(TAG, String.format(
541                    "onSizeChanged: (%dx%d) old: (%dx%d)", w, h, oldw, oldh));
542
543        final boolean newVertical = w > 0 && h > w;
544        if (newVertical != mVertical) {
545            mVertical = newVertical;
546            //Log.v(TAG, String.format("onSizeChanged: h=%d, w=%d, vert=%s", h, w, mVertical?"y":"n"));
547            reorient();
548        }
549
550        postCheckForInvalidLayout("sizeChanged");
551        super.onSizeChanged(w, h, oldw, oldh);
552    }
553
554    /*
555    @Override
556    protected void onLayout (boolean changed, int left, int top, int right, int bottom) {
557        if (DEBUG) Log.d(TAG, String.format(
558                    "onLayout: %s (%d,%d,%d,%d)",
559                    changed?"changed":"notchanged", left, top, right, bottom));
560        super.onLayout(changed, left, top, right, bottom);
561    }
562
563    // uncomment this for extra defensiveness in WORKAROUND_INVALID_LAYOUT situations: if all else
564    // fails, any touch on the display will fix the layout.
565    @Override
566    public boolean onInterceptTouchEvent(MotionEvent ev) {
567        if (DEBUG) Log.d(TAG, "onInterceptTouchEvent: " + ev.toString());
568        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
569            postCheckForInvalidLayout("touch");
570        }
571        return super.onInterceptTouchEvent(ev);
572    }
573    */
574
575
576    private String getResourceName(int resId) {
577        if (resId != 0) {
578            final android.content.res.Resources res = mContext.getResources();
579            try {
580                return res.getResourceName(resId);
581            } catch (android.content.res.Resources.NotFoundException ex) {
582                return "(unknown)";
583            }
584        } else {
585            return "(null)";
586        }
587    }
588
589    private void postCheckForInvalidLayout(final String how) {
590        mHandler.obtainMessage(MSG_CHECK_INVALID_LAYOUT, 0, 0, how).sendToTarget();
591    }
592
593    private static String visibilityToString(int vis) {
594        switch (vis) {
595            case View.INVISIBLE:
596                return "INVISIBLE";
597            case View.GONE:
598                return "GONE";
599            default:
600                return "VISIBLE";
601        }
602    }
603
604    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
605        pw.println("NavigationBarView {");
606        final Rect r = new Rect();
607        final Point size = new Point();
608        mDisplay.getRealSize(size);
609
610        pw.println(String.format("      this: " + PhoneStatusBar.viewInfo(this)
611                        + " " + visibilityToString(getVisibility())));
612
613        getWindowVisibleDisplayFrame(r);
614        final boolean offscreen = r.right > size.x || r.bottom > size.y;
615        pw.println("      window: "
616                + r.toShortString()
617                + " " + visibilityToString(getWindowVisibility())
618                + (offscreen ? " OFFSCREEN!" : ""));
619
620        pw.println(String.format("      mCurrentView: id=%s (%dx%d) %s",
621                        getResourceName(mCurrentView.getId()),
622                        mCurrentView.getWidth(), mCurrentView.getHeight(),
623                        visibilityToString(mCurrentView.getVisibility())));
624
625        pw.println(String.format("      disabled=0x%08x vertical=%s menu=%s",
626                        mDisabledFlags,
627                        mVertical ? "true" : "false",
628                        mShowMenu ? "true" : "false"));
629
630        dumpButton(pw, "back", getBackButton());
631        dumpButton(pw, "home", getHomeButton());
632        dumpButton(pw, "rcnt", getRecentsButton());
633        dumpButton(pw, "menu", getMenuButton());
634        dumpButton(pw, "srch", getSearchLight());
635        dumpButton(pw, "cmra", getCameraButton());
636
637        pw.println("    }");
638    }
639
640    private static void dumpButton(PrintWriter pw, String caption, View button) {
641        pw.print("      " + caption + ": ");
642        if (button == null) {
643            pw.print("null");
644        } else {
645            pw.print(PhoneStatusBar.viewInfo(button)
646                    + " " + visibilityToString(button.getVisibility())
647                    + " alpha=" + button.getAlpha()
648                    );
649            if (button instanceof KeyButtonView) {
650                pw.print(" drawingAlpha=" + ((KeyButtonView)button).getDrawingAlpha());
651                pw.print(" quiescentAlpha=" + ((KeyButtonView)button).getQuiescentAlpha());
652            }
653        }
654        pw.println();
655    }
656
657}
658