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