CallButtonFragment.java revision cda81c2ef1ba595c35ae1d4ad72c44f3443e08fd
1/* 2 * Copyright (C) 2013 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.incallui; 18 19import android.content.Context; 20import android.graphics.drawable.LayerDrawable; 21import android.os.Bundle; 22import android.telecomm.AudioState; 23import android.view.ContextThemeWrapper; 24import android.view.LayoutInflater; 25import android.view.Menu; 26import android.view.MenuItem; 27import android.view.View; 28import android.view.ViewGroup; 29import android.view.accessibility.AccessibilityEvent; 30import android.view.accessibility.AccessibilityManager; 31import android.widget.CompoundButton; 32import android.widget.ImageButton; 33import android.widget.PopupMenu; 34import android.widget.PopupMenu.OnDismissListener; 35import android.widget.PopupMenu.OnMenuItemClickListener; 36 37/** 38 * Fragment for call control buttons 39 */ 40public class CallButtonFragment 41 extends BaseFragment<CallButtonPresenter, CallButtonPresenter.CallButtonUi> 42 implements CallButtonPresenter.CallButtonUi, OnMenuItemClickListener, OnDismissListener, 43 View.OnClickListener, CompoundButton.OnCheckedChangeListener { 44 45 private ImageButton mAudioButton; 46 private ImageButton mChangeToVoiceButton; 47 private ImageButton mMuteButton; 48 private ImageButton mShowDialpadButton; 49 private ImageButton mHoldButton; 50 private ImageButton mSwapButton; 51 private ImageButton mChangeToVideoButton; 52 private ImageButton mSwitchCameraButton; 53 private ImageButton mAddCallButton; 54 private ImageButton mMergeButton; 55 private ImageButton mPauseVideoButton; 56 private ImageButton mOverflowButton; 57 58 private PopupMenu mAudioModePopup; 59 private boolean mAudioModePopupVisible; 60 private PopupMenu mOverflowPopup; 61 private View mExtraRowButton; 62 private View mManageConferenceButton; 63 private View mGenericMergeButton; 64 65 private int mPrevAudioMode = 0; 66 67 // Constants for Drawable.setAlpha() 68 private static final int HIDDEN = 0; 69 private static final int VISIBLE = 255; 70 71 private boolean mIsEnabled; 72 73 @Override 74 CallButtonPresenter createPresenter() { 75 // TODO: find a cleaner way to include audio mode provider than having a singleton instance. 76 return new CallButtonPresenter(); 77 } 78 79 @Override 80 CallButtonPresenter.CallButtonUi getUi() { 81 return this; 82 } 83 84 @Override 85 public void onCreate(Bundle savedInstanceState) { 86 super.onCreate(savedInstanceState); 87 } 88 89 @Override 90 public View onCreateView(LayoutInflater inflater, ViewGroup container, 91 Bundle savedInstanceState) { 92 final View parent = inflater.inflate(R.layout.call_button_fragment, container, false); 93 94 mExtraRowButton = parent.findViewById(R.id.extraButtonRow); 95 96 mManageConferenceButton = parent.findViewById(R.id.manageConferenceButton); 97 mManageConferenceButton.setOnClickListener(this); 98 mGenericMergeButton = parent.findViewById(R.id.cdmaMergeButton); 99 mGenericMergeButton.setOnClickListener(this); 100 101 mAudioButton = (ImageButton) parent.findViewById(R.id.audioButton); 102 mAudioButton.setOnClickListener(this); 103 mChangeToVoiceButton = (ImageButton) parent.findViewById(R.id.changeToVoiceButton); 104 mChangeToVoiceButton. setOnClickListener(this); 105 mMuteButton = (ImageButton) parent.findViewById(R.id.muteButton); 106 mMuteButton.setOnClickListener(this); 107 mShowDialpadButton = (ImageButton) parent.findViewById(R.id.dialpadButton); 108 mShowDialpadButton.setOnClickListener(this); 109 mHoldButton = (ImageButton) parent.findViewById(R.id.holdButton); 110 mHoldButton.setOnClickListener(this); 111 mSwapButton = (ImageButton) parent.findViewById(R.id.swapButton); 112 mSwapButton.setOnClickListener(this); 113 mChangeToVideoButton = (ImageButton) parent.findViewById(R.id.changeToVideoButton); 114 mChangeToVideoButton.setOnClickListener(this); 115 mSwitchCameraButton = (ImageButton) parent.findViewById(R.id.switchCameraButton); 116 mSwitchCameraButton.setOnClickListener(this); 117 mAddCallButton = (ImageButton) parent.findViewById(R.id.addButton); 118 mAddCallButton.setOnClickListener(this); 119 mMergeButton = (ImageButton) parent.findViewById(R.id.mergeButton); 120 mMergeButton.setOnClickListener(this); 121 mPauseVideoButton = (ImageButton) parent.findViewById(R.id.pauseVideoButton); 122 mPauseVideoButton.setOnClickListener(this); 123 mOverflowButton = (ImageButton) parent.findViewById(R.id.overflowButton); 124 mOverflowButton.setOnClickListener(this); 125 126 return parent; 127 } 128 129 @Override 130 public void onActivityCreated(Bundle savedInstanceState) { 131 super.onActivityCreated(savedInstanceState); 132 133 // set the buttons 134 updateAudioButtons(getPresenter().getSupportedAudio()); 135 } 136 137 @Override 138 public void onResume() { 139 if (getPresenter() != null) { 140 getPresenter().refreshMuteState(); 141 } 142 super.onResume(); 143 } 144 145 @Override 146 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 147 } 148 149 @Override 150 public void onClick(View view) { 151 int id = view.getId(); 152 Log.d(this, "onClick(View " + view + ", id " + id + ")..."); 153 154 switch(id) { 155 case R.id.audioButton: 156 onAudioButtonClicked(); 157 break; 158 case R.id.addButton: 159 getPresenter().addCallClicked(); 160 break; 161 case R.id.changeToVoiceButton: 162 getPresenter().changeToVoiceClicked(); 163 break; 164 case R.id.muteButton: { 165 final ImageButton button = (ImageButton) view; 166 getPresenter().muteClicked(!button.isSelected()); 167 break; 168 } 169 case R.id.cdmaMergeButton: 170 case R.id.mergeButton: 171 getPresenter().mergeClicked(); 172 break; 173 case R.id.holdButton: { 174 final ImageButton button = (ImageButton) view; 175 getPresenter().holdClicked(!button.isSelected()); 176 break; 177 } 178 case R.id.swapButton: 179 getPresenter().swapClicked(); 180 break; 181 case R.id.dialpadButton: 182 getPresenter().showDialpadClicked(!mShowDialpadButton.isSelected()); 183 break; 184 case R.id.changeToVideoButton: 185 getPresenter().changeToVideoClicked(); 186 break; 187 case R.id.switchCameraButton: 188 getPresenter().switchCameraClicked( 189 mSwitchCameraButton.isSelected() /* useFrontFacingCamera */); 190 break; 191 case R.id.pauseVideoButton: 192 getPresenter().pauseVideoClicked( 193 !mPauseVideoButton.isSelected() /* pause */); 194 break; 195 case R.id.overflowButton: 196 mOverflowPopup.show(); 197 break; 198 case R.id.manageConferenceButton: 199 getPresenter().manageConferenceButtonClicked(); 200 break; 201 default: 202 Log.wtf(this, "onClick: unexpected"); 203 break; 204 } 205 } 206 207 @Override 208 public void setEnabled(boolean isEnabled) { 209 mIsEnabled = isEnabled; 210 View view = getView(); 211 if (view.getVisibility() != View.VISIBLE) { 212 view.setVisibility(View.VISIBLE); 213 } 214 215 mAudioButton.setEnabled(isEnabled); 216 mChangeToVoiceButton.setEnabled(isEnabled); 217 mMuteButton.setEnabled(isEnabled); 218 mShowDialpadButton.setEnabled(isEnabled); 219 mHoldButton.setEnabled(isEnabled); 220 mSwapButton.setEnabled(isEnabled); 221 mChangeToVideoButton.setEnabled(isEnabled); 222 mSwitchCameraButton.setEnabled(isEnabled); 223 mAddCallButton.setEnabled(isEnabled); 224 mMergeButton.setEnabled(isEnabled); 225 mPauseVideoButton.setEnabled(isEnabled); 226 mOverflowButton.setEnabled(isEnabled); 227 } 228 229 @Override 230 public void setMute(boolean value) { 231 if (mMuteButton.isSelected() != value) { 232 mMuteButton.setSelected(value); 233 maybeSendAccessibilityEvent(mMuteButton, value ? R.string.accessibility_call_muted 234 : R.string.accessibility_call_unmuted); 235 } 236 } 237 238 @Override 239 public void showAudioButton(boolean show) { 240 mAudioButton.setVisibility(show ? View.VISIBLE : View.GONE); 241 } 242 243 @Override 244 public void showChangeToVoiceButton(boolean show) { 245 mChangeToVoiceButton.setVisibility(show ? View.VISIBLE : View.GONE); 246 } 247 248 @Override 249 public void enableMute(boolean enabled) { 250 mMuteButton.setEnabled(enabled); 251 } 252 253 @Override 254 public void showDialpadButton(boolean show) { 255 mShowDialpadButton.setVisibility(show ? View.VISIBLE : View.GONE); 256 } 257 258 @Override 259 public void setHold(boolean value) { 260 if (mHoldButton.isSelected() != value) { 261 mHoldButton.setSelected(value); 262 maybeSendAccessibilityEvent(mHoldButton, 263 value ? R.string.accessibility_call_put_on_hold : 264 R.string.accessibility_call_removed_from_hold); 265 } 266 } 267 268 @Override 269 public void showHoldButton(boolean show) { 270 mHoldButton.setVisibility(show ? View.VISIBLE : View.GONE); 271 } 272 273 @Override 274 public void enableHold(boolean enabled) { 275 mHoldButton.setEnabled(enabled); 276 } 277 278 @Override 279 public void showSwapButton(boolean show) { 280 mSwapButton.setVisibility(show ? View.VISIBLE : View.GONE); 281 } 282 283 @Override 284 public void showChangeToVideoButton(boolean show) { 285 mChangeToVideoButton.setVisibility(show ? View.VISIBLE : View.GONE); 286 } 287 288 @Override 289 public void showSwitchCameraButton(boolean show) { 290 mSwitchCameraButton.setVisibility(show ? View.VISIBLE : View.GONE); 291 } 292 293 @Override 294 public void setSwitchCameraButton(boolean isBackFacingCamera) { 295 mSwitchCameraButton.setSelected(isBackFacingCamera); 296 } 297 298 @Override 299 public void showAddCallButton(boolean show) { 300 Log.d(this, "show Add call button: " + show); 301 mAddCallButton.setVisibility(show ? View.VISIBLE : View.GONE); 302 } 303 304 @Override 305 public void enableAddCall(boolean enabled) { 306 mAddCallButton.setEnabled(enabled); 307 } 308 309 @Override 310 public void showMergeButton(boolean show) { 311 mMergeButton.setVisibility(show ? View.VISIBLE : View.GONE); 312 } 313 314 @Override 315 public void showPauseVideoButton(boolean show) { 316 mPauseVideoButton.setVisibility(show ? View.VISIBLE : View.GONE); 317 } 318 319 @Override 320 public void setPauseVideoButton(boolean isPaused) { 321 mPauseVideoButton.setSelected(isPaused); 322 } 323 324 @Override 325 public void showOverflowButton(boolean show) { 326 mOverflowButton.setVisibility(show ? View.VISIBLE : View.GONE); 327 } 328 329 @Override 330 public void configureOverflowMenu(boolean showMergeMenuOption, boolean showAddMenuOption, 331 boolean showHoldMenuOption, boolean showSwapMenuOption) { 332 if (mOverflowPopup == null) { 333 final ContextThemeWrapper contextWrapper = new ContextThemeWrapper(getActivity(), 334 R.style.InCallPopupMenuStyle); 335 mOverflowPopup = new PopupMenu(contextWrapper, mOverflowButton); 336 mOverflowPopup.getMenuInflater().inflate(R.menu.incall_overflow_menu, 337 mOverflowPopup.getMenu()); 338 mOverflowPopup.setOnMenuItemClickListener(new OnMenuItemClickListener() { 339 @Override 340 public boolean onMenuItemClick(MenuItem item) { 341 switch (item.getItemId()) { 342 case R.id.overflow_merge_menu_item: 343 getPresenter().mergeClicked(); 344 break; 345 case R.id.overflow_add_menu_item: 346 getPresenter().addCallClicked(); 347 break; 348 case R.id.overflow_hold_menu_item: 349 getPresenter().holdClicked(true /* checked */); 350 break; 351 case R.id.overflow_resume_menu_item: 352 getPresenter().holdClicked(false /* checked */); 353 break; 354 case R.id.overflow_swap_menu_item: 355 getPresenter().addCallClicked(); 356 break; 357 default: 358 Log.wtf(this, "onMenuItemClick: unexpected overflow menu click"); 359 break; 360 } 361 return true; 362 } 363 }); 364 mOverflowPopup.setOnDismissListener(new OnDismissListener() { 365 @Override 366 public void onDismiss(PopupMenu popupMenu) { 367 popupMenu.dismiss(); 368 } 369 }); 370 } 371 372 final Menu menu = mOverflowPopup.getMenu(); 373 menu.findItem(R.id.overflow_merge_menu_item).setVisible(showMergeMenuOption); 374 menu.findItem(R.id.overflow_add_menu_item).setVisible(showAddMenuOption); 375 menu.findItem(R.id.overflow_hold_menu_item).setVisible( 376 showHoldMenuOption && !mHoldButton.isSelected()); 377 menu.findItem(R.id.overflow_resume_menu_item).setVisible( 378 showHoldMenuOption && mHoldButton.isSelected()); 379 menu.findItem(R.id.overflow_swap_menu_item).setVisible(showSwapMenuOption); 380 381 mOverflowButton.setEnabled(menu.hasVisibleItems()); 382 } 383 384 @Override 385 public void setAudio(int mode) { 386 updateAudioButtons(getPresenter().getSupportedAudio()); 387 refreshAudioModePopup(); 388 389 if (mPrevAudioMode != mode) { 390 if (mPrevAudioMode != 0) { 391 int stringId = 0; 392 switch (mode) { 393 case AudioState.ROUTE_EARPIECE: 394 stringId = R.string.accessibility_earpiece_selected; 395 break; 396 case AudioState.ROUTE_BLUETOOTH: 397 stringId = R.string.accessibility_bluetooth_headset_selected; 398 break; 399 case AudioState.ROUTE_WIRED_HEADSET: 400 stringId = R.string.accessibility_wired_headset_selected; 401 break; 402 case AudioState.ROUTE_SPEAKER: 403 stringId = R.string.accessibility_speakerphone_selected; 404 break; 405 } 406 if (stringId != 0) { 407 maybeSendAccessibilityEvent(mAudioButton, stringId); 408 } 409 } 410 mPrevAudioMode = mode; 411 } 412 } 413 414 @Override 415 public void setSupportedAudio(int modeMask) { 416 updateAudioButtons(modeMask); 417 refreshAudioModePopup(); 418 } 419 420 @Override 421 public boolean onMenuItemClick(MenuItem item) { 422 Log.d(this, "- onMenuItemClick: " + item); 423 Log.d(this, " id: " + item.getItemId()); 424 Log.d(this, " title: '" + item.getTitle() + "'"); 425 426 int mode = AudioState.ROUTE_WIRED_OR_EARPIECE; 427 428 switch (item.getItemId()) { 429 case R.id.audio_mode_speaker: 430 mode = AudioState.ROUTE_SPEAKER; 431 break; 432 case R.id.audio_mode_earpiece: 433 case R.id.audio_mode_wired_headset: 434 // InCallAudioState.ROUTE_EARPIECE means either the handset earpiece, 435 // or the wired headset (if connected.) 436 mode = AudioState.ROUTE_WIRED_OR_EARPIECE; 437 break; 438 case R.id.audio_mode_bluetooth: 439 mode = AudioState.ROUTE_BLUETOOTH; 440 break; 441 default: 442 Log.e(this, "onMenuItemClick: unexpected View ID " + item.getItemId() 443 + " (MenuItem = '" + item + "')"); 444 break; 445 } 446 447 getPresenter().setAudioMode(mode); 448 449 return true; 450 } 451 452 // PopupMenu.OnDismissListener implementation; see showAudioModePopup(). 453 // This gets called when the PopupMenu gets dismissed for *any* reason, like 454 // the user tapping outside its bounds, or pressing Back, or selecting one 455 // of the menu items. 456 @Override 457 public void onDismiss(PopupMenu menu) { 458 Log.d(this, "- onDismiss: " + menu); 459 mAudioModePopupVisible = false; 460 } 461 462 /** 463 * Checks for supporting modes. If bluetooth is supported, it uses the audio 464 * pop up menu. Otherwise, it toggles the speakerphone. 465 */ 466 private void onAudioButtonClicked() { 467 Log.d(this, "onAudioButtonClicked: " + 468 AudioState.audioRouteToString(getPresenter().getSupportedAudio())); 469 470 if (isSupported(AudioState.ROUTE_BLUETOOTH)) { 471 showAudioModePopup(); 472 } else { 473 getPresenter().toggleSpeakerphone(); 474 } 475 } 476 477 /** 478 * Refreshes the "Audio mode" popup if it's visible. This is useful 479 * (for example) when a wired headset is plugged or unplugged, 480 * since we need to switch back and forth between the "earpiece" 481 * and "wired headset" items. 482 * 483 * This is safe to call even if the popup is already dismissed, or even if 484 * you never called showAudioModePopup() in the first place. 485 */ 486 public void refreshAudioModePopup() { 487 if (mAudioModePopup != null && mAudioModePopupVisible) { 488 // Dismiss the previous one 489 mAudioModePopup.dismiss(); // safe even if already dismissed 490 // And bring up a fresh PopupMenu 491 showAudioModePopup(); 492 } 493 } 494 495 /** 496 * Updates the audio button so that the appriopriate visual layers 497 * are visible based on the supported audio formats. 498 */ 499 private void updateAudioButtons(int supportedModes) { 500 final boolean bluetoothSupported = isSupported(AudioState.ROUTE_BLUETOOTH); 501 final boolean speakerSupported = isSupported(AudioState.ROUTE_SPEAKER); 502 503 boolean audioButtonEnabled = false; 504 boolean audioButtonChecked = false; 505 boolean showMoreIndicator = false; 506 507 boolean showBluetoothIcon = false; 508 boolean showSpeakerphoneIcon = false; 509 boolean showHandsetIcon = false; 510 511 boolean showToggleIndicator = false; 512 513 if (bluetoothSupported) { 514 Log.d(this, "updateAudioButtons - popup menu mode"); 515 516 audioButtonEnabled = true; 517 showMoreIndicator = true; 518 // The audio button is NOT a toggle in this state. (And its 519 // setChecked() state is irrelevant since we completely hide the 520 // btn_compound_background layer anyway.) 521 522 // Update desired layers: 523 if (isAudio(AudioState.ROUTE_BLUETOOTH)) { 524 showBluetoothIcon = true; 525 } else if (isAudio(AudioState.ROUTE_SPEAKER)) { 526 showSpeakerphoneIcon = true; 527 } else { 528 showHandsetIcon = true; 529 // TODO: if a wired headset is plugged in, that takes precedence 530 // over the handset earpiece. If so, maybe we should show some 531 // sort of "wired headset" icon here instead of the "handset 532 // earpiece" icon. (Still need an asset for that, though.) 533 } 534 } else if (speakerSupported) { 535 Log.d(this, "updateAudioButtons - speaker toggle mode"); 536 537 audioButtonEnabled = true; 538 539 // The audio button *is* a toggle in this state, and indicated the 540 // current state of the speakerphone. 541 audioButtonChecked = isAudio(AudioState.ROUTE_SPEAKER); 542 543 // update desired layers: 544 showToggleIndicator = true; 545 showSpeakerphoneIcon = true; 546 } else { 547 Log.d(this, "updateAudioButtons - disabled..."); 548 549 // The audio button is a toggle in this state, but that's mostly 550 // irrelevant since it's always disabled and unchecked. 551 audioButtonEnabled = false; 552 audioButtonChecked = false; 553 554 // update desired layers: 555 showToggleIndicator = true; 556 showSpeakerphoneIcon = true; 557 } 558 559 // Finally, update it all! 560 561 Log.v(this, "audioButtonEnabled: " + audioButtonEnabled); 562 Log.v(this, "audioButtonChecked: " + audioButtonChecked); 563 Log.v(this, "showMoreIndicator: " + showMoreIndicator); 564 Log.v(this, "showBluetoothIcon: " + showBluetoothIcon); 565 Log.v(this, "showSpeakerphoneIcon: " + showSpeakerphoneIcon); 566 Log.v(this, "showHandsetIcon: " + showHandsetIcon); 567 568 // Only enable the audio button if the fragment is enabled. 569 mAudioButton.setEnabled(audioButtonEnabled && mIsEnabled); 570 mAudioButton.setSelected(audioButtonChecked); 571 572 final LayerDrawable layers = (LayerDrawable) mAudioButton.getBackground(); 573 Log.d(this, "'layers' drawable: " + layers); 574 575 layers.findDrawableByLayerId(R.id.compoundBackgroundItem) 576 .setAlpha(showToggleIndicator ? VISIBLE : HIDDEN); 577 578 layers.findDrawableByLayerId(R.id.moreIndicatorItem) 579 .setAlpha(showMoreIndicator ? VISIBLE : HIDDEN); 580 581 layers.findDrawableByLayerId(R.id.bluetoothItem) 582 .setAlpha(showBluetoothIcon ? VISIBLE : HIDDEN); 583 584 layers.findDrawableByLayerId(R.id.handsetItem) 585 .setAlpha(showHandsetIcon ? VISIBLE : HIDDEN); 586 587 layers.findDrawableByLayerId(R.id.speakerphoneItem) 588 .setAlpha(showSpeakerphoneIcon ? VISIBLE : HIDDEN); 589 590 } 591 592 private void showAudioModePopup() { 593 Log.d(this, "showAudioPopup()..."); 594 595 final ContextThemeWrapper contextWrapper = new ContextThemeWrapper(getActivity(), 596 R.style.InCallPopupMenuStyle); 597 mAudioModePopup = new PopupMenu(contextWrapper, mAudioButton /* anchorView */); 598 mAudioModePopup.getMenuInflater().inflate(R.menu.incall_audio_mode_menu, 599 mAudioModePopup.getMenu()); 600 mAudioModePopup.setOnMenuItemClickListener(this); 601 mAudioModePopup.setOnDismissListener(this); 602 603 final Menu menu = mAudioModePopup.getMenu(); 604 605 // TODO: Still need to have the "currently active" audio mode come 606 // up pre-selected (or focused?) with a blue highlight. Still 607 // need exact visual design, and possibly framework support for this. 608 // See comments below for the exact logic. 609 610 final MenuItem speakerItem = menu.findItem(R.id.audio_mode_speaker); 611 speakerItem.setEnabled(isSupported(AudioState.ROUTE_SPEAKER)); 612 // TODO: Show speakerItem as initially "selected" if 613 // speaker is on. 614 615 // We display *either* "earpiece" or "wired headset", never both, 616 // depending on whether a wired headset is physically plugged in. 617 final MenuItem earpieceItem = menu.findItem(R.id.audio_mode_earpiece); 618 final MenuItem wiredHeadsetItem = menu.findItem(R.id.audio_mode_wired_headset); 619 620 final boolean usingHeadset = isSupported(AudioState.ROUTE_WIRED_HEADSET); 621 earpieceItem.setVisible(!usingHeadset); 622 earpieceItem.setEnabled(!usingHeadset); 623 wiredHeadsetItem.setVisible(usingHeadset); 624 wiredHeadsetItem.setEnabled(usingHeadset); 625 // TODO: Show the above item (either earpieceItem or wiredHeadsetItem) 626 // as initially "selected" if speakerOn and 627 // bluetoothIndicatorOn are both false. 628 629 final MenuItem bluetoothItem = menu.findItem(R.id.audio_mode_bluetooth); 630 bluetoothItem.setEnabled(isSupported(AudioState.ROUTE_BLUETOOTH)); 631 // TODO: Show bluetoothItem as initially "selected" if 632 // bluetoothIndicatorOn is true. 633 634 mAudioModePopup.show(); 635 636 // Unfortunately we need to manually keep track of the popup menu's 637 // visiblity, since PopupMenu doesn't have an isShowing() method like 638 // Dialogs do. 639 mAudioModePopupVisible = true; 640 } 641 642 private boolean isSupported(int mode) { 643 return (mode == (getPresenter().getSupportedAudio() & mode)); 644 } 645 646 private boolean isAudio(int mode) { 647 return (mode == getPresenter().getAudioMode()); 648 } 649 650 @Override 651 public void displayDialpad(boolean value, boolean animate) { 652 mShowDialpadButton.setSelected(value); 653 if (getActivity() != null && getActivity() instanceof InCallActivity) { 654 ((InCallActivity) getActivity()).displayDialpad(value, animate); 655 } 656 } 657 658 @Override 659 public boolean isDialpadVisible() { 660 if (getActivity() != null && getActivity() instanceof InCallActivity) { 661 return ((InCallActivity) getActivity()).isDialpadVisible(); 662 } 663 return false; 664 } 665 666 @Override 667 public void displayManageConferencePanel(boolean value) { 668 if (getActivity() != null && getActivity() instanceof InCallActivity) { 669 ((InCallActivity) getActivity()).displayManageConferencePanel(value); 670 } 671 } 672 673 @Override 674 public Context getContext() { 675 return getActivity(); 676 } 677 678 @Override 679 public void showManageConferenceCallButton() { 680 mExtraRowButton.setVisibility(View.VISIBLE); 681 mManageConferenceButton.setVisibility(View.VISIBLE); 682 mGenericMergeButton.setVisibility(View.GONE); 683 } 684 685 @Override 686 public void showGenericMergeButton() { 687 mExtraRowButton.setVisibility(View.VISIBLE); 688 mManageConferenceButton.setVisibility(View.GONE); 689 mGenericMergeButton.setVisibility(View.VISIBLE); 690 } 691 692 @Override 693 public void hideExtraRow() { 694 mExtraRowButton.setVisibility(View.GONE); 695 } 696 697 private void maybeSendAccessibilityEvent(View view, int stringId) { 698 final Context context = getActivity(); 699 AccessibilityManager manager = 700 (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE); 701 if (manager != null && manager.isEnabled()) { 702 AccessibilityEvent e = AccessibilityEvent.obtain(); 703 e.setSource(view); 704 e.setEventType(AccessibilityEvent.TYPE_ANNOUNCEMENT); 705 e.setClassName(getClass().getName()); 706 e.setPackageName(context.getPackageName()); 707 e.getText().add(context.getResources().getString(stringId)); 708 manager.sendAccessibilityEvent(e); 709 } 710 } 711} 712