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