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