2 * Copyright (C) 2008 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.systemui.statusbar.phone;
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.content.Context;
27 import android.content.res.Configuration;
28 import android.graphics.Point;
29 import android.graphics.Rect;
30 import android.graphics.drawable.Drawable;
31 import android.os.Handler;
32 import android.os.Message;
33 import android.os.RemoteException;
34 import android.util.AttributeSet;
35 import android.util.Log;
36 import android.util.SparseArray;
37 import android.view.Display;
38 import android.view.IDockedStackListener.Stub;
39 import android.view.MotionEvent;
40 import android.view.Surface;
41 import android.view.View;
42 import android.view.ViewGroup;
43 import android.view.WindowManager;
44 import android.view.WindowManagerGlobal;
45 import android.view.inputmethod.InputMethodManager;
46 import android.widget.LinearLayout;
47 import com.android.systemui.R;
48 import com.android.systemui.RecentsComponent;
49 import com.android.systemui.stackdivider.Divider;
50 import com.android.systemui.statusbar.policy.DeadZone;
52 import java.io.FileDescriptor;
53 import java.io.PrintWriter;
55 public class NavigationBarView extends LinearLayout {
56 final static boolean DEBUG = false;
57 final static String TAG = "StatusBar/NavBarView";
59 // slippery nav bar when everything is disabled, e.g. during setup
60 final static boolean SLIPPERY_WHEN_DISABLED = true;
62 final static boolean ALTERNATE_CAR_MODE_UI = false;
64 final Display mDisplay;
65 View mCurrentView = null;
66 View[] mRotatedViews = new View[4];
70 private int mCurrentRotation = -1;
73 int mDisabledFlags = 0;
74 int mNavigationIconHints = 0;
76 private Drawable mBackIcon, mBackLandIcon, mBackAltIcon, mBackAltLandIcon;
77 private Drawable mBackCarModeIcon, mBackLandCarModeIcon;
78 private Drawable mBackAltCarModeIcon, mBackAltLandCarModeIcon;
79 private Drawable mHomeDefaultIcon, mHomeCarModeIcon;
80 private Drawable mRecentIcon;
81 private Drawable mDockedIcon;
82 private Drawable mImeIcon;
83 private Drawable mMenuIcon;
85 private NavigationBarGestureHelper mGestureHelper;
86 private DeadZone mDeadZone;
87 private final NavigationBarTransitions mBarTransitions;
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;
93 // performs manual animation in sync with layout transitions
94 private final NavTransitionListener mTransitionListener = new NavTransitionListener();
96 private OnVerticalChangedListener mOnVerticalChangedListener;
97 private boolean mLayoutTransitionsEnabled = true;
98 private boolean mWakeAndUnlocking;
99 private boolean mUseCarModeUi = false;
100 private boolean mInCarMode = false;
101 private boolean mDockedStackExists;
103 private final SparseArray<ButtonDispatcher> mButtonDisatchers = new SparseArray<>();
104 private Configuration mConfiguration;
106 private NavigationBarInflaterView mNavigationInflaterView;
108 private class NavTransitionListener implements TransitionListener {
109 private boolean mBackTransitioning;
110 private boolean mHomeAppearing;
111 private long mStartDelay;
112 private long mDuration;
113 private TimeInterpolator mInterpolator;
116 public void startTransition(LayoutTransition transition, ViewGroup container,
117 View view, int transitionType) {
118 if (view.getId() == R.id.back) {
119 mBackTransitioning = true;
120 } else if (view.getId() == R.id.home && transitionType == LayoutTransition.APPEARING) {
121 mHomeAppearing = true;
122 mStartDelay = transition.getStartDelay(transitionType);
123 mDuration = transition.getDuration(transitionType);
124 mInterpolator = transition.getInterpolator(transitionType);
129 public void endTransition(LayoutTransition transition, ViewGroup container,
130 View view, int transitionType) {
131 if (view.getId() == R.id.back) {
132 mBackTransitioning = false;
133 } else if (view.getId() == R.id.home && transitionType == LayoutTransition.APPEARING) {
134 mHomeAppearing = false;
138 public void onBackAltCleared() {
139 ButtonDispatcher backButton = getBackButton();
141 // When dismissing ime during unlock, force the back button to run the same appearance
142 // animation as home (if we catch this condition early enough).
143 if (!mBackTransitioning && backButton.getVisibility() == VISIBLE
144 && mHomeAppearing && getHomeButton().getAlpha() == 0) {
145 getBackButton().setAlpha(0);
146 ValueAnimator a = ObjectAnimator.ofFloat(backButton, "alpha", 0, 1);
147 a.setStartDelay(mStartDelay);
148 a.setDuration(mDuration);
149 a.setInterpolator(mInterpolator);
155 private final OnClickListener mImeSwitcherClickListener = new OnClickListener() {
157 public void onClick(View view) {
158 mContext.getSystemService(InputMethodManager.class)
159 .showInputMethodPicker(true /* showAuxiliarySubtypes */);
163 private class H extends Handler {
164 public void handleMessage(Message m) {
166 case MSG_CHECK_INVALID_LAYOUT:
167 final String how = "" + m.obj;
168 final int w = getWidth();
169 final int h = getHeight();
170 final int vw = getCurrentView().getWidth();
171 final int vh = getCurrentView().getHeight();
173 if (h != vh || w != vw) {
174 Log.w(TAG, String.format(
175 "*** Invalid layout in navigation bar (%s this=%dx%d cur=%dx%d)",
177 if (WORKAROUND_INVALID_LAYOUT) {
186 public NavigationBarView(Context context, AttributeSet attrs) {
187 super(context, attrs);
189 mDisplay = ((WindowManager) context.getSystemService(
190 Context.WINDOW_SERVICE)).getDefaultDisplay();
194 mGestureHelper = new NavigationBarGestureHelper(context);
196 mConfiguration = new Configuration();
197 mConfiguration.updateFrom(context.getResources().getConfiguration());
198 updateIcons(context, Configuration.EMPTY, mConfiguration);
200 mBarTransitions = new NavigationBarTransitions(this);
202 mButtonDisatchers.put(R.id.back, new ButtonDispatcher(R.id.back));
203 mButtonDisatchers.put(R.id.home, new ButtonDispatcher(R.id.home));
204 mButtonDisatchers.put(R.id.recent_apps, new ButtonDispatcher(R.id.recent_apps));
205 mButtonDisatchers.put(R.id.menu, new ButtonDispatcher(R.id.menu));
206 mButtonDisatchers.put(R.id.ime_switcher, new ButtonDispatcher(R.id.ime_switcher));
209 public BarTransitions getBarTransitions() {
210 return mBarTransitions;
213 public void setComponents(RecentsComponent recentsComponent, Divider divider) {
214 mGestureHelper.setComponents(recentsComponent, divider, this);
217 public void setOnVerticalChangedListener(OnVerticalChangedListener onVerticalChangedListener) {
218 mOnVerticalChangedListener = onVerticalChangedListener;
219 notifyVerticalChangedListener(mVertical);
223 public boolean onTouchEvent(MotionEvent event) {
224 if (mGestureHelper.onTouchEvent(event)) {
227 if (mDeadZone != null && event.getAction() == MotionEvent.ACTION_OUTSIDE) {
228 mDeadZone.poke(event);
230 return super.onTouchEvent(event);
234 public boolean onInterceptTouchEvent(MotionEvent event) {
235 return mGestureHelper.onInterceptTouchEvent(event);
238 public void abortCurrentGesture() {
239 getHomeButton().abortCurrentGesture();
242 private H mHandler = new H();
244 public View getCurrentView() {
248 public View[] getAllViews() {
249 return mRotatedViews;
252 public ButtonDispatcher getRecentsButton() {
253 return mButtonDisatchers.get(R.id.recent_apps);
256 public ButtonDispatcher getMenuButton() {
257 return mButtonDisatchers.get(R.id.menu);
260 public ButtonDispatcher getBackButton() {
261 return mButtonDisatchers.get(R.id.back);
264 public ButtonDispatcher getHomeButton() {
265 return mButtonDisatchers.get(R.id.home);
268 public ButtonDispatcher getImeSwitchButton() {
269 return mButtonDisatchers.get(R.id.ime_switcher);
272 private void updateCarModeIcons(Context ctx) {
273 mBackCarModeIcon = ctx.getDrawable(R.drawable.ic_sysbar_back_carmode);
274 mBackLandCarModeIcon = mBackCarModeIcon;
275 mBackAltCarModeIcon = ctx.getDrawable(R.drawable.ic_sysbar_back_ime_carmode);
276 mBackAltLandCarModeIcon = mBackAltCarModeIcon;
277 mHomeCarModeIcon = ctx.getDrawable(R.drawable.ic_sysbar_home_carmode);
280 private void updateIcons(Context ctx, Configuration oldConfig, Configuration newConfig) {
281 if (oldConfig.orientation != newConfig.orientation
282 || oldConfig.densityDpi != newConfig.densityDpi) {
283 mDockedIcon = ctx.getDrawable(R.drawable.ic_sysbar_docked);
285 if (oldConfig.densityDpi != newConfig.densityDpi) {
286 mBackIcon = ctx.getDrawable(R.drawable.ic_sysbar_back);
287 mBackLandIcon = mBackIcon;
288 mBackAltIcon = ctx.getDrawable(R.drawable.ic_sysbar_back_ime);
289 mBackAltLandIcon = mBackAltIcon;
291 mHomeDefaultIcon = ctx.getDrawable(R.drawable.ic_sysbar_home);
292 mRecentIcon = ctx.getDrawable(R.drawable.ic_sysbar_recent);
293 mMenuIcon = ctx.getDrawable(R.drawable.ic_sysbar_menu);
294 mImeIcon = ctx.getDrawable(R.drawable.ic_ime_switcher_default);
296 if (ALTERNATE_CAR_MODE_UI) {
297 updateCarModeIcons(ctx);
303 public void setLayoutDirection(int layoutDirection) {
304 // Reload all the icons
305 updateIcons(getContext(), Configuration.EMPTY, mConfiguration);
307 super.setLayoutDirection(layoutDirection);
310 public void notifyScreenOn(boolean screenOn) {
311 mScreenOn = screenOn;
312 setDisabledFlags(mDisabledFlags, true);
315 public void setNavigationIconHints(int hints) {
316 setNavigationIconHints(hints, false);
319 private Drawable getBackIconWithAlt(boolean carMode, boolean landscape) {
321 ? carMode ? mBackAltLandCarModeIcon : mBackAltLandIcon
322 : carMode ? mBackAltCarModeIcon : mBackAltIcon;
325 private Drawable getBackIcon(boolean carMode, boolean landscape) {
327 ? carMode ? mBackLandCarModeIcon : mBackLandIcon
328 : carMode ? mBackCarModeIcon : mBackIcon;
331 public void setNavigationIconHints(int hints, boolean force) {
332 if (!force && hints == mNavigationIconHints) return;
333 final boolean backAlt = (hints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
334 if ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0 && !backAlt) {
335 mTransitionListener.onBackAltCleared();
338 android.widget.Toast.makeText(getContext(),
339 "Navigation icon hints = " + hints,
343 mNavigationIconHints = hints;
345 // We have to replace or restore the back and home button icons when exiting or entering
346 // carmode, respectively. Recents are not available in CarMode in nav bar so change
347 // to recent icon is not required.
348 Drawable backIcon = (backAlt)
349 ? getBackIconWithAlt(mUseCarModeUi, mVertical)
350 : getBackIcon(mUseCarModeUi, mVertical);
352 getBackButton().setImageDrawable(backIcon);
357 getHomeButton().setImageDrawable(mHomeCarModeIcon);
359 getHomeButton().setImageDrawable(mHomeDefaultIcon);
362 final boolean showImeButton = ((hints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) != 0);
363 getImeSwitchButton().setVisibility(showImeButton ? View.VISIBLE : View.INVISIBLE);
364 getImeSwitchButton().setImageDrawable(mImeIcon);
366 // Update menu button in case the IME state has changed.
367 setMenuVisibility(mShowMenu, true);
368 getMenuButton().setImageDrawable(mMenuIcon);
370 setDisabledFlags(mDisabledFlags, true);
373 public void setDisabledFlags(int disabledFlags) {
374 setDisabledFlags(disabledFlags, false);
377 public void setDisabledFlags(int disabledFlags, boolean force) {
378 if (!force && mDisabledFlags == disabledFlags) return;
380 mDisabledFlags = disabledFlags;
382 final boolean disableHome = ((disabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0);
384 // Always disable recents when alternate car mode UI is active.
385 boolean disableRecent = mUseCarModeUi
386 || ((disabledFlags & View.STATUS_BAR_DISABLE_RECENT) != 0);
387 final boolean disableBack = ((disabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0)
388 && ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) == 0);
389 final boolean disableSearch = ((disabledFlags & View.STATUS_BAR_DISABLE_SEARCH) != 0);
391 ViewGroup navButtons = (ViewGroup) getCurrentView().findViewById(R.id.nav_buttons);
392 if (navButtons != null) {
393 LayoutTransition lt = navButtons.getLayoutTransition();
395 if (!lt.getTransitionListeners().contains(mTransitionListener)) {
396 lt.addTransitionListener(mTransitionListener);
400 if (inLockTask() && disableRecent && !disableHome) {
401 // Don't hide recents when in lock task, it is used for exiting.
402 // Unless home is hidden, then in DPM locked mode and no exit available.
403 disableRecent = false;
406 getBackButton().setVisibility(disableBack ? View.INVISIBLE : View.VISIBLE);
407 getHomeButton().setVisibility(disableHome ? View.INVISIBLE : View.VISIBLE);
408 getRecentsButton().setVisibility(disableRecent ? View.INVISIBLE : View.VISIBLE);
411 private boolean inLockTask() {
413 return ActivityManagerNative.getDefault().isInLockTaskMode();
414 } catch (RemoteException e) {
419 public void setLayoutTransitionsEnabled(boolean enabled) {
420 mLayoutTransitionsEnabled = enabled;
421 updateLayoutTransitionsEnabled();
424 public void setWakeAndUnlocking(boolean wakeAndUnlocking) {
425 setUseFadingAnimations(wakeAndUnlocking);
426 mWakeAndUnlocking = wakeAndUnlocking;
427 updateLayoutTransitionsEnabled();
430 private void updateLayoutTransitionsEnabled() {
431 boolean enabled = !mWakeAndUnlocking && mLayoutTransitionsEnabled;
432 ViewGroup navButtons = (ViewGroup) getCurrentView().findViewById(R.id.nav_buttons);
433 LayoutTransition lt = navButtons.getLayoutTransition();
436 lt.enableTransitionType(LayoutTransition.APPEARING);
437 lt.enableTransitionType(LayoutTransition.DISAPPEARING);
438 lt.enableTransitionType(LayoutTransition.CHANGE_APPEARING);
439 lt.enableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
441 lt.disableTransitionType(LayoutTransition.APPEARING);
442 lt.disableTransitionType(LayoutTransition.DISAPPEARING);
443 lt.disableTransitionType(LayoutTransition.CHANGE_APPEARING);
444 lt.disableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
449 private void setUseFadingAnimations(boolean useFadingAnimations) {
450 WindowManager.LayoutParams lp = (WindowManager.LayoutParams) getLayoutParams();
452 boolean old = lp.windowAnimations != 0;
453 if (!old && useFadingAnimations) {
454 lp.windowAnimations = R.style.Animation_NavigationBarFadeIn;
455 } else if (old && !useFadingAnimations) {
456 lp.windowAnimations = 0;
460 WindowManager wm = (WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE);
461 wm.updateViewLayout(this, lp);
465 public void setMenuVisibility(final boolean show) {
466 setMenuVisibility(show, false);
469 public void setMenuVisibility(final boolean show, final boolean force) {
470 if (!force && mShowMenu == show) return;
474 // Only show Menu if IME switcher not shown.
475 final boolean shouldShow = mShowMenu &&
476 ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) == 0);
478 getMenuButton().setVisibility(shouldShow ? View.VISIBLE : View.INVISIBLE);
482 public void onFinishInflate() {
483 mNavigationInflaterView = (NavigationBarInflaterView) findViewById(
484 R.id.navigation_inflater);
485 updateRotatedViews();
486 mNavigationInflaterView.setButtonDispatchers(mButtonDisatchers);
488 getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);
491 WindowManagerGlobal.getWindowManagerService().registerDockedStackListener(new Stub() {
493 public void onDividerVisibilityChanged(boolean visible) throws RemoteException {
497 public void onDockedStackExistsChanged(final boolean exists) throws RemoteException {
498 mHandler.post(new Runnable() {
501 mDockedStackExists = exists;
508 public void onDockedStackMinimizedChanged(boolean minimized, long animDuration)
509 throws RemoteException {
513 public void onAdjustedForImeChanged(boolean adjustedForIme, long animDuration)
514 throws RemoteException {
518 public void onDockSideChanged(int newDockSide) throws RemoteException {
521 } catch (RemoteException e) {
522 Log.e(TAG, "Failed registering docked stack exists listener", e);
526 void updateRotatedViews() {
527 mRotatedViews[Surface.ROTATION_0] =
528 mRotatedViews[Surface.ROTATION_180] = findViewById(R.id.rot0);
529 mRotatedViews[Surface.ROTATION_270] =
530 mRotatedViews[Surface.ROTATION_90] = findViewById(R.id.rot90);
535 public boolean needsReorient(int rotation) {
536 return mCurrentRotation != rotation;
539 private void updateCurrentView() {
540 final int rot = mDisplay.getRotation();
541 for (int i=0; i<4; i++) {
542 mRotatedViews[i].setVisibility(View.GONE);
544 mCurrentView = mRotatedViews[rot];
545 mCurrentView.setVisibility(View.VISIBLE);
546 mNavigationInflaterView.setAlternativeOrder(rot == Surface.ROTATION_90);
547 for (int i = 0; i < mButtonDisatchers.size(); i++) {
548 mButtonDisatchers.valueAt(i).setCurrentView(mCurrentView);
550 updateLayoutTransitionsEnabled();
551 mCurrentRotation = rot;
554 private void updateRecentsIcon() {
555 getRecentsButton().setImageDrawable(mDockedStackExists ? mDockedIcon : mRecentIcon);
558 public boolean isVertical() {
562 public void reorient() {
565 getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);
567 mDeadZone = (DeadZone) mCurrentView.findViewById(R.id.deadzone);
568 mDeadZone.setDisplayRotation(mCurrentRotation);
570 // force the low profile & disabled states into compliance
571 mBarTransitions.init();
572 setDisabledFlags(mDisabledFlags, true /* force */);
573 setMenuVisibility(mShowMenu, true /* force */);
576 Log.d(TAG, "reorient(): rot=" + mCurrentRotation);
579 updateTaskSwitchHelper();
580 setNavigationIconHints(mNavigationIconHints, true);
582 getHomeButton().setVertical(mVertical);
585 private void updateTaskSwitchHelper() {
586 boolean isRtl = (getLayoutDirection() == View.LAYOUT_DIRECTION_RTL);
587 mGestureHelper.setBarState(mVertical, isRtl);
591 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
592 if (DEBUG) Log.d(TAG, String.format(
593 "onSizeChanged: (%dx%d) old: (%dx%d)", w, h, oldw, oldh));
595 final boolean newVertical = w > 0 && h > w;
596 if (newVertical != mVertical) {
597 mVertical = newVertical;
598 //Log.v(TAG, String.format("onSizeChanged: h=%d, w=%d, vert=%s", h, w, mVertical?"y":"n"));
600 notifyVerticalChangedListener(newVertical);
603 postCheckForInvalidLayout("sizeChanged");
604 super.onSizeChanged(w, h, oldw, oldh);
607 private void notifyVerticalChangedListener(boolean newVertical) {
608 if (mOnVerticalChangedListener != null) {
609 mOnVerticalChangedListener.onVerticalChanged(newVertical);
614 protected void onConfigurationChanged(Configuration newConfig) {
615 super.onConfigurationChanged(newConfig);
616 boolean uiCarModeChanged = updateCarMode(newConfig);
617 updateTaskSwitchHelper();
618 updateIcons(getContext(), mConfiguration, newConfig);
620 if (uiCarModeChanged || mConfiguration.densityDpi != newConfig.densityDpi) {
621 // If car mode or density changes, we need to reset the icons.
622 setNavigationIconHints(mNavigationIconHints, true);
624 mConfiguration.updateFrom(newConfig);
628 * If the configuration changed, update the carmode and return that it was updated.
630 private boolean updateCarMode(Configuration newConfig) {
631 boolean uiCarModeChanged = false;
632 if (newConfig != null) {
633 int uiMode = newConfig.uiMode & Configuration.UI_MODE_TYPE_MASK;
634 final boolean isCarMode = (uiMode == Configuration.UI_MODE_TYPE_CAR);
636 if (isCarMode != mInCarMode) {
637 mInCarMode = isCarMode;
638 getHomeButton().setCarMode(isCarMode);
640 if (ALTERNATE_CAR_MODE_UI) {
641 mUseCarModeUi = isCarMode;
642 uiCarModeChanged = true;
644 // Don't use car mode behavior if ALTERNATE_CAR_MODE_UI not set.
645 mUseCarModeUi = false;
649 return uiCarModeChanged;
654 protected void onLayout (boolean changed, int left, int top, int right, int bottom) {
655 if (DEBUG) Log.d(TAG, String.format(
656 "onLayout: %s (%d,%d,%d,%d)",
657 changed?"changed":"notchanged", left, top, right, bottom));
658 super.onLayout(changed, left, top, right, bottom);
661 // uncomment this for extra defensiveness in WORKAROUND_INVALID_LAYOUT situations: if all else
662 // fails, any touch on the display will fix the layout.
664 public boolean onInterceptTouchEvent(MotionEvent ev) {
665 if (DEBUG) Log.d(TAG, "onInterceptTouchEvent: " + ev.toString());
666 if (ev.getAction() == MotionEvent.ACTION_DOWN) {
667 postCheckForInvalidLayout("touch");
669 return super.onInterceptTouchEvent(ev);
674 private String getResourceName(int resId) {
676 final android.content.res.Resources res = getContext().getResources();
678 return res.getResourceName(resId);
679 } catch (android.content.res.Resources.NotFoundException ex) {
687 private void postCheckForInvalidLayout(final String how) {
688 mHandler.obtainMessage(MSG_CHECK_INVALID_LAYOUT, 0, 0, how).sendToTarget();
691 private static String visibilityToString(int vis) {
702 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
703 pw.println("NavigationBarView {");
704 final Rect r = new Rect();
705 final Point size = new Point();
706 mDisplay.getRealSize(size);
708 pw.println(String.format(" this: " + PhoneStatusBar.viewInfo(this)
709 + " " + visibilityToString(getVisibility())));
711 getWindowVisibleDisplayFrame(r);
712 final boolean offscreen = r.right > size.x || r.bottom > size.y;
713 pw.println(" window: "
715 + " " + visibilityToString(getWindowVisibility())
716 + (offscreen ? " OFFSCREEN!" : ""));
718 pw.println(String.format(" mCurrentView: id=%s (%dx%d) %s",
719 getResourceName(getCurrentView().getId()),
720 getCurrentView().getWidth(), getCurrentView().getHeight(),
721 visibilityToString(getCurrentView().getVisibility())));
723 pw.println(String.format(" disabled=0x%08x vertical=%s menu=%s",
725 mVertical ? "true" : "false",
726 mShowMenu ? "true" : "false"));
728 dumpButton(pw, "back", getBackButton());
729 dumpButton(pw, "home", getHomeButton());
730 dumpButton(pw, "rcnt", getRecentsButton());
731 dumpButton(pw, "menu", getMenuButton());
736 private static void dumpButton(PrintWriter pw, String caption, ButtonDispatcher button) {
737 pw.print(" " + caption + ": ");
738 if (button == null) {
741 pw.print(visibilityToString(button.getVisibility())
742 + " alpha=" + button.getAlpha()
748 public interface OnVerticalChangedListener {
749 void onVerticalChanged(boolean isVertical);