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 17 package com.android.incallui; 18 19 import android.content.Context; 20 import android.os.Bundle; 21 import android.os.Trace; 22 import android.support.v4.app.Fragment; 23 import android.support.v4.os.UserManagerCompat; 24 import android.telecom.CallAudioState; 25 import android.telecom.PhoneAccountHandle; 26 import com.android.contacts.common.compat.CallCompat; 27 import com.android.dialer.common.Assert; 28 import com.android.dialer.common.LogUtil; 29 import com.android.dialer.common.concurrent.DialerExecutorComponent; 30 import com.android.dialer.logging.DialerImpression; 31 import com.android.dialer.logging.DialerImpression.Type; 32 import com.android.dialer.logging.Logger; 33 import com.android.dialer.telecom.TelecomUtil; 34 import com.android.incallui.InCallCameraManager.Listener; 35 import com.android.incallui.InCallPresenter.CanAddCallListener; 36 import com.android.incallui.InCallPresenter.InCallDetailsListener; 37 import com.android.incallui.InCallPresenter.InCallState; 38 import com.android.incallui.InCallPresenter.InCallStateListener; 39 import com.android.incallui.InCallPresenter.IncomingCallListener; 40 import com.android.incallui.audiomode.AudioModeProvider; 41 import com.android.incallui.audiomode.AudioModeProvider.AudioModeListener; 42 import com.android.incallui.call.CallList; 43 import com.android.incallui.call.DialerCall; 44 import com.android.incallui.call.DialerCall.CameraDirection; 45 import com.android.incallui.call.DialerCallListener; 46 import com.android.incallui.call.TelecomAdapter; 47 import com.android.incallui.call.state.DialerCallState; 48 import com.android.incallui.incall.protocol.InCallButtonIds; 49 import com.android.incallui.incall.protocol.InCallButtonUi; 50 import com.android.incallui.incall.protocol.InCallButtonUiDelegate; 51 import com.android.incallui.multisim.SwapSimWorker; 52 import com.android.incallui.videotech.utils.VideoUtils; 53 54 /** Logic for call buttons. */ 55 public class CallButtonPresenter 56 implements InCallStateListener, 57 AudioModeListener, 58 IncomingCallListener, 59 InCallDetailsListener, 60 CanAddCallListener, 61 Listener, 62 InCallButtonUiDelegate, 63 DialerCallListener { 64 65 private final Context context; 66 private InCallButtonUi inCallButtonUi; 67 private DialerCall call; 68 private boolean isInCallButtonUiReady; 69 private PhoneAccountHandle otherAccount; 70 CallButtonPresenter(Context context)71 public CallButtonPresenter(Context context) { 72 this.context = context.getApplicationContext(); 73 } 74 75 @Override onInCallButtonUiReady(InCallButtonUi ui)76 public void onInCallButtonUiReady(InCallButtonUi ui) { 77 Assert.checkState(!isInCallButtonUiReady); 78 inCallButtonUi = ui; 79 AudioModeProvider.getInstance().addListener(this); 80 81 // register for call state changes last 82 final InCallPresenter inCallPresenter = InCallPresenter.getInstance(); 83 inCallPresenter.addListener(this); 84 inCallPresenter.addIncomingCallListener(this); 85 inCallPresenter.addDetailsListener(this); 86 inCallPresenter.addCanAddCallListener(this); 87 inCallPresenter.getInCallCameraManager().addCameraSelectionListener(this); 88 89 // Update the buttons state immediately for the current call 90 onStateChange(InCallState.NO_CALLS, inCallPresenter.getInCallState(), CallList.getInstance()); 91 isInCallButtonUiReady = true; 92 } 93 94 @Override onInCallButtonUiUnready()95 public void onInCallButtonUiUnready() { 96 Assert.checkState(isInCallButtonUiReady); 97 inCallButtonUi = null; 98 InCallPresenter.getInstance().removeListener(this); 99 AudioModeProvider.getInstance().removeListener(this); 100 InCallPresenter.getInstance().removeIncomingCallListener(this); 101 InCallPresenter.getInstance().removeDetailsListener(this); 102 InCallPresenter.getInstance().getInCallCameraManager().removeCameraSelectionListener(this); 103 InCallPresenter.getInstance().removeCanAddCallListener(this); 104 isInCallButtonUiReady = false; 105 106 if (call != null) { 107 call.removeListener(this); 108 } 109 } 110 111 @Override onStateChange(InCallState oldState, InCallState newState, CallList callList)112 public void onStateChange(InCallState oldState, InCallState newState, CallList callList) { 113 Trace.beginSection("CallButtonPresenter.onStateChange"); 114 if (call != null) { 115 call.removeListener(this); 116 } 117 if (newState == InCallState.OUTGOING) { 118 call = callList.getOutgoingCall(); 119 } else if (newState == InCallState.INCALL) { 120 call = callList.getActiveOrBackgroundCall(); 121 122 // When connected to voice mail, automatically shows the dialpad. 123 // (On previous releases we showed it when in-call shows up, before waiting for 124 // OUTGOING. We may want to do that once we start showing "Voice mail" label on 125 // the dialpad too.) 126 if (oldState == InCallState.OUTGOING && call != null) { 127 if (call.isVoiceMailNumber() && getActivity() != null) { 128 getActivity().showDialpadFragment(true /* show */, true /* animate */); 129 } 130 } 131 } else if (newState == InCallState.INCOMING) { 132 if (getActivity() != null) { 133 getActivity().showDialpadFragment(false /* show */, true /* animate */); 134 } 135 call = callList.getIncomingCall(); 136 } else { 137 call = null; 138 } 139 140 if (call != null) { 141 call.addListener(this); 142 } 143 updateUi(newState, call); 144 Trace.endSection(); 145 } 146 147 /** 148 * Updates the user interface in response to a change in the details of a call. Currently handles 149 * changes to the call buttons in response to a change in the details for a call. This is 150 * important to ensure changes to the active call are reflected in the available buttons. 151 * 152 * @param call The active call. 153 * @param details The call details. 154 */ 155 @Override onDetailsChanged(DialerCall call, android.telecom.Call.Details details)156 public void onDetailsChanged(DialerCall call, android.telecom.Call.Details details) { 157 // Only update if the changes are for the currently active call 158 if (inCallButtonUi != null && call != null && call.equals(this.call)) { 159 updateButtonsState(call); 160 } 161 } 162 163 @Override onIncomingCall(InCallState oldState, InCallState newState, DialerCall call)164 public void onIncomingCall(InCallState oldState, InCallState newState, DialerCall call) { 165 onStateChange(oldState, newState, CallList.getInstance()); 166 } 167 168 @Override onCanAddCallChanged(boolean canAddCall)169 public void onCanAddCallChanged(boolean canAddCall) { 170 if (inCallButtonUi != null && call != null) { 171 updateButtonsState(call); 172 } 173 } 174 175 @Override onAudioStateChanged(CallAudioState audioState)176 public void onAudioStateChanged(CallAudioState audioState) { 177 if (inCallButtonUi != null) { 178 inCallButtonUi.setAudioState(audioState); 179 } 180 } 181 182 @Override getCurrentAudioState()183 public CallAudioState getCurrentAudioState() { 184 return AudioModeProvider.getInstance().getAudioState(); 185 } 186 187 @Override setAudioRoute(int route)188 public void setAudioRoute(int route) { 189 LogUtil.i( 190 "CallButtonPresenter.setAudioRoute", 191 "sending new audio route: " + CallAudioState.audioRouteToString(route)); 192 TelecomAdapter.getInstance().setAudioRoute(route); 193 } 194 195 /** Function assumes that bluetooth is not supported. */ 196 @Override toggleSpeakerphone()197 public void toggleSpeakerphone() { 198 // This function should not be called if bluetooth is available. 199 CallAudioState audioState = getCurrentAudioState(); 200 if (0 != (CallAudioState.ROUTE_BLUETOOTH & audioState.getSupportedRouteMask())) { 201 // It's clear the UI is wrong, so update the supported mode once again. 202 LogUtil.e( 203 "CallButtonPresenter", "toggling speakerphone not allowed when bluetooth supported."); 204 inCallButtonUi.setAudioState(audioState); 205 return; 206 } 207 208 int newRoute; 209 if (audioState.getRoute() == CallAudioState.ROUTE_SPEAKER) { 210 newRoute = CallAudioState.ROUTE_WIRED_OR_EARPIECE; 211 if (call != null) { 212 Logger.get(context) 213 .logCallImpression( 214 DialerImpression.Type.IN_CALL_SCREEN_TURN_ON_WIRED_OR_EARPIECE, 215 call.getUniqueCallId(), 216 call.getTimeAddedMs()); 217 } 218 } else { 219 newRoute = CallAudioState.ROUTE_SPEAKER; 220 if (call != null) { 221 Logger.get(context) 222 .logCallImpression( 223 DialerImpression.Type.IN_CALL_SCREEN_TURN_ON_SPEAKERPHONE, 224 call.getUniqueCallId(), 225 call.getTimeAddedMs()); 226 } 227 } 228 229 setAudioRoute(newRoute); 230 } 231 232 @Override muteClicked(boolean checked, boolean clickedByUser)233 public void muteClicked(boolean checked, boolean clickedByUser) { 234 LogUtil.i( 235 "CallButtonPresenter", "turning on mute: %s, clicked by user: %s", checked, clickedByUser); 236 if (clickedByUser) { 237 Logger.get(context) 238 .logCallImpression( 239 checked 240 ? DialerImpression.Type.IN_CALL_SCREEN_TURN_ON_MUTE 241 : DialerImpression.Type.IN_CALL_SCREEN_TURN_OFF_MUTE, 242 call.getUniqueCallId(), 243 call.getTimeAddedMs()); 244 } 245 TelecomAdapter.getInstance().mute(checked); 246 } 247 248 @Override holdClicked(boolean checked)249 public void holdClicked(boolean checked) { 250 if (call == null) { 251 return; 252 } 253 if (checked) { 254 LogUtil.i("CallButtonPresenter", "putting the call on hold: " + call); 255 call.hold(); 256 } else { 257 LogUtil.i("CallButtonPresenter", "removing the call from hold: " + call); 258 call.unhold(); 259 } 260 } 261 262 @Override swapClicked()263 public void swapClicked() { 264 if (call == null) { 265 return; 266 } 267 268 LogUtil.i("CallButtonPresenter", "swapping the call: " + call); 269 TelecomAdapter.getInstance().swap(call.getId()); 270 } 271 272 @Override mergeClicked()273 public void mergeClicked() { 274 Logger.get(context) 275 .logCallImpression( 276 DialerImpression.Type.IN_CALL_MERGE_BUTTON_PRESSED, 277 call.getUniqueCallId(), 278 call.getTimeAddedMs()); 279 TelecomAdapter.getInstance().merge(call.getId()); 280 } 281 282 @Override addCallClicked()283 public void addCallClicked() { 284 Logger.get(context) 285 .logCallImpression( 286 DialerImpression.Type.IN_CALL_ADD_CALL_BUTTON_PRESSED, 287 call.getUniqueCallId(), 288 call.getTimeAddedMs()); 289 InCallPresenter.getInstance().addCallClicked(); 290 } 291 292 @Override showDialpadClicked(boolean checked)293 public void showDialpadClicked(boolean checked) { 294 Logger.get(context) 295 .logCallImpression( 296 DialerImpression.Type.IN_CALL_SHOW_DIALPAD_BUTTON_PRESSED, 297 call.getUniqueCallId(), 298 call.getTimeAddedMs()); 299 LogUtil.v("CallButtonPresenter", "show dialpad " + String.valueOf(checked)); 300 getActivity().showDialpadFragment(checked /* show */, true /* animate */); 301 } 302 303 @Override changeToVideoClicked()304 public void changeToVideoClicked() { 305 LogUtil.enterBlock("CallButtonPresenter.changeToVideoClicked"); 306 Logger.get(context) 307 .logCallImpression( 308 DialerImpression.Type.VIDEO_CALL_UPGRADE_REQUESTED, 309 call.getUniqueCallId(), 310 call.getTimeAddedMs()); 311 call.getVideoTech().upgradeToVideo(context); 312 } 313 314 @Override changeToRttClicked()315 public void changeToRttClicked() { 316 LogUtil.enterBlock("CallButtonPresenter.changeToRttClicked"); 317 call.sendRttUpgradeRequest(); 318 } 319 320 @Override onEndCallClicked()321 public void onEndCallClicked() { 322 LogUtil.i("CallButtonPresenter.onEndCallClicked", "call: " + call); 323 if (call != null) { 324 call.disconnect(); 325 } 326 } 327 328 @Override showAudioRouteSelector()329 public void showAudioRouteSelector() { 330 inCallButtonUi.showAudioRouteSelector(); 331 } 332 333 @Override swapSimClicked()334 public void swapSimClicked() { 335 LogUtil.enterBlock("CallButtonPresenter.swapSimClicked"); 336 Logger.get(getContext()).logImpression(Type.DUAL_SIM_CHANGE_SIM_PRESSED); 337 SwapSimWorker worker = 338 new SwapSimWorker( 339 getContext(), 340 call, 341 InCallPresenter.getInstance().getCallList(), 342 otherAccount, 343 InCallPresenter.getInstance().acquireInCallUiLock("swapSim")); 344 DialerExecutorComponent.get(getContext()) 345 .dialerExecutorFactory() 346 .createNonUiTaskBuilder(worker) 347 .build() 348 .executeParallel(null); 349 } 350 351 /** 352 * Switches the camera between the front-facing and back-facing camera. 353 * 354 * @param useFrontFacingCamera True if we should switch to using the front-facing camera, or false 355 * if we should switch to using the back-facing camera. 356 */ 357 @Override switchCameraClicked(boolean useFrontFacingCamera)358 public void switchCameraClicked(boolean useFrontFacingCamera) { 359 updateCamera(useFrontFacingCamera); 360 } 361 362 @Override toggleCameraClicked()363 public void toggleCameraClicked() { 364 LogUtil.i("CallButtonPresenter.toggleCameraClicked", ""); 365 if (call == null) { 366 return; 367 } 368 Logger.get(context) 369 .logCallImpression( 370 DialerImpression.Type.IN_CALL_SCREEN_SWAP_CAMERA, 371 call.getUniqueCallId(), 372 call.getTimeAddedMs()); 373 switchCameraClicked( 374 !InCallPresenter.getInstance().getInCallCameraManager().isUsingFrontFacingCamera()); 375 } 376 377 /** 378 * Stop or start client's video transmission. 379 * 380 * @param pause True if pausing the local user's video, or false if starting the local user's 381 * video. 382 */ 383 @Override pauseVideoClicked(boolean pause)384 public void pauseVideoClicked(boolean pause) { 385 LogUtil.i("CallButtonPresenter.pauseVideoClicked", "%s", pause ? "pause" : "unpause"); 386 387 Logger.get(context) 388 .logCallImpression( 389 pause 390 ? DialerImpression.Type.IN_CALL_SCREEN_TURN_OFF_VIDEO 391 : DialerImpression.Type.IN_CALL_SCREEN_TURN_ON_VIDEO, 392 call.getUniqueCallId(), 393 call.getTimeAddedMs()); 394 395 if (pause) { 396 call.getVideoTech().stopTransmission(); 397 } else { 398 updateCamera( 399 InCallPresenter.getInstance().getInCallCameraManager().isUsingFrontFacingCamera()); 400 call.getVideoTech().resumeTransmission(context); 401 } 402 403 inCallButtonUi.setVideoPaused(pause); 404 inCallButtonUi.enableButton(InCallButtonIds.BUTTON_PAUSE_VIDEO, false); 405 } 406 updateCamera(boolean useFrontFacingCamera)407 private void updateCamera(boolean useFrontFacingCamera) { 408 InCallCameraManager cameraManager = InCallPresenter.getInstance().getInCallCameraManager(); 409 cameraManager.setUseFrontFacingCamera(useFrontFacingCamera); 410 411 String cameraId = cameraManager.getActiveCameraId(); 412 if (cameraId != null) { 413 final int cameraDir = 414 cameraManager.isUsingFrontFacingCamera() 415 ? CameraDirection.CAMERA_DIRECTION_FRONT_FACING 416 : CameraDirection.CAMERA_DIRECTION_BACK_FACING; 417 call.setCameraDir(cameraDir); 418 call.getVideoTech().setCamera(cameraId); 419 } 420 } 421 updateUi(InCallState state, DialerCall call)422 private void updateUi(InCallState state, DialerCall call) { 423 LogUtil.v("CallButtonPresenter", "updating call UI for call: %s", call); 424 425 if (inCallButtonUi == null) { 426 return; 427 } 428 429 if (call != null) { 430 inCallButtonUi.updateInCallButtonUiColors( 431 InCallPresenter.getInstance().getThemeColorManager().getSecondaryColor()); 432 } 433 434 final boolean isEnabled = 435 state.isConnectingOrConnected() && !state.isIncoming() && call != null; 436 inCallButtonUi.setEnabled(isEnabled); 437 438 if (call == null) { 439 return; 440 } 441 442 updateButtonsState(call); 443 } 444 445 /** 446 * Updates the buttons applicable for the UI. 447 * 448 * @param call The active call. 449 */ 450 @SuppressWarnings(value = {"MissingPermission"}) updateButtonsState(DialerCall call)451 private void updateButtonsState(DialerCall call) { 452 LogUtil.v("CallButtonPresenter.updateButtonsState", ""); 453 final boolean isVideo = call.isVideoCall(); 454 455 // Common functionality (audio, hold, etc). 456 // Show either HOLD or SWAP, but not both. If neither HOLD or SWAP is available: 457 // (1) If the device normally can hold, show HOLD in a disabled state. 458 // (2) If the device doesn't have the concept of hold/swap, remove the button. 459 final boolean showSwap = call.can(android.telecom.Call.Details.CAPABILITY_SWAP_CONFERENCE); 460 final boolean showHold = 461 !showSwap 462 && call.can(android.telecom.Call.Details.CAPABILITY_SUPPORT_HOLD) 463 && call.can(android.telecom.Call.Details.CAPABILITY_HOLD); 464 final boolean isCallOnHold = call.getState() == DialerCallState.ONHOLD; 465 466 final boolean showAddCall = 467 TelecomAdapter.getInstance().canAddCall() && UserManagerCompat.isUserUnlocked(context); 468 // There can only be two calls so don't show the ability to merge when one of them 469 // is a speak easy call. 470 final boolean showMerge = 471 InCallPresenter.getInstance() 472 .getCallList() 473 .getAllCalls() 474 .stream() 475 .noneMatch(c -> c != null && c.isSpeakEasyCall()) 476 && call.can(android.telecom.Call.Details.CAPABILITY_MERGE_CONFERENCE); 477 final boolean showUpgradeToVideo = !isVideo && (hasVideoCallCapabilities(call)); 478 final boolean showDowngradeToAudio = isVideo && isDowngradeToAudioSupported(call); 479 final boolean showMute = call.can(android.telecom.Call.Details.CAPABILITY_MUTE); 480 481 final boolean hasCameraPermission = 482 isVideo && VideoUtils.hasCameraPermissionAndShownPrivacyToast(context); 483 // Disabling local video doesn't seem to work when dialing. See a bug. 484 final boolean showPauseVideo = 485 isVideo 486 && call.getState() != DialerCallState.DIALING 487 && call.getState() != DialerCallState.CONNECTING; 488 489 otherAccount = TelecomUtil.getOtherAccount(getContext(), call.getAccountHandle()); 490 boolean showSwapSim = 491 !call.isEmergencyCall() 492 && otherAccount != null 493 && !call.isVoiceMailNumber() 494 && DialerCallState.isDialing(call.getState()) 495 // Most devices cannot make calls on 2 SIMs at the same time. 496 && InCallPresenter.getInstance().getCallList().getAllCalls().size() == 1; 497 498 boolean showUpgradeToRtt = call.canUpgradeToRttCall(); 499 boolean enableUpgradeToRtt = showUpgradeToRtt && call.getState() == DialerCallState.ACTIVE; 500 501 inCallButtonUi.showButton(InCallButtonIds.BUTTON_AUDIO, true); 502 inCallButtonUi.showButton(InCallButtonIds.BUTTON_SWAP, showSwap); 503 inCallButtonUi.showButton(InCallButtonIds.BUTTON_HOLD, showHold); 504 inCallButtonUi.setHold(isCallOnHold); 505 inCallButtonUi.showButton(InCallButtonIds.BUTTON_MUTE, showMute); 506 inCallButtonUi.showButton(InCallButtonIds.BUTTON_SWAP_SIM, showSwapSim); 507 inCallButtonUi.showButton(InCallButtonIds.BUTTON_ADD_CALL, true); 508 inCallButtonUi.enableButton(InCallButtonIds.BUTTON_ADD_CALL, showAddCall); 509 inCallButtonUi.showButton(InCallButtonIds.BUTTON_UPGRADE_TO_VIDEO, showUpgradeToVideo); 510 inCallButtonUi.showButton(InCallButtonIds.BUTTON_UPGRADE_TO_RTT, showUpgradeToRtt); 511 inCallButtonUi.enableButton(InCallButtonIds.BUTTON_UPGRADE_TO_RTT, enableUpgradeToRtt); 512 inCallButtonUi.showButton(InCallButtonIds.BUTTON_DOWNGRADE_TO_AUDIO, showDowngradeToAudio); 513 inCallButtonUi.showButton( 514 InCallButtonIds.BUTTON_SWITCH_CAMERA, 515 isVideo && hasCameraPermission && call.getVideoTech().isTransmitting()); 516 inCallButtonUi.showButton(InCallButtonIds.BUTTON_PAUSE_VIDEO, showPauseVideo); 517 if (isVideo) { 518 inCallButtonUi.setVideoPaused(!call.getVideoTech().isTransmitting() || !hasCameraPermission); 519 } 520 inCallButtonUi.showButton(InCallButtonIds.BUTTON_DIALPAD, true); 521 inCallButtonUi.showButton(InCallButtonIds.BUTTON_MERGE, showMerge); 522 523 inCallButtonUi.updateButtonStates(); 524 } 525 hasVideoCallCapabilities(DialerCall call)526 private boolean hasVideoCallCapabilities(DialerCall call) { 527 return call.getVideoTech().isAvailable(context, call.getAccountHandle()); 528 } 529 530 /** 531 * Determines if downgrading from a video call to an audio-only call is supported. In order to 532 * support downgrade to audio, the SDK version must be >= N and the call should NOT have the 533 * {@link android.telecom.Call.Details#CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO}. 534 * 535 * @param call The call. 536 * @return {@code true} if downgrading to an audio-only call from a video call is supported. 537 */ isDowngradeToAudioSupported(DialerCall call)538 private boolean isDowngradeToAudioSupported(DialerCall call) { 539 // TODO(a bug): If there is an RCS video share session, return true here 540 return !call.can(CallCompat.Details.CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO); 541 } 542 543 @Override onSaveInstanceState(Bundle outState)544 public void onSaveInstanceState(Bundle outState) {} 545 546 @Override onRestoreInstanceState(Bundle savedInstanceState)547 public void onRestoreInstanceState(Bundle savedInstanceState) {} 548 549 @Override onCameraPermissionGranted()550 public void onCameraPermissionGranted() { 551 if (call != null) { 552 updateButtonsState(call); 553 } 554 } 555 556 @Override onActiveCameraSelectionChanged(boolean isUsingFrontFacingCamera)557 public void onActiveCameraSelectionChanged(boolean isUsingFrontFacingCamera) { 558 if (inCallButtonUi == null) { 559 return; 560 } 561 inCallButtonUi.setCameraSwitched(!isUsingFrontFacingCamera); 562 } 563 564 @Override onDialerCallSessionModificationStateChange()565 public void onDialerCallSessionModificationStateChange() { 566 if (inCallButtonUi != null && call != null) { 567 inCallButtonUi.enableButton(InCallButtonIds.BUTTON_PAUSE_VIDEO, true); 568 updateButtonsState(call); 569 } 570 } 571 572 @Override onDialerCallDisconnect()573 public void onDialerCallDisconnect() {} 574 575 @Override onDialerCallUpdate()576 public void onDialerCallUpdate() {} 577 578 @Override onDialerCallChildNumberChange()579 public void onDialerCallChildNumberChange() {} 580 581 @Override onDialerCallLastForwardedNumberChange()582 public void onDialerCallLastForwardedNumberChange() {} 583 584 @Override onDialerCallUpgradeToVideo()585 public void onDialerCallUpgradeToVideo() {} 586 587 @Override onWiFiToLteHandover()588 public void onWiFiToLteHandover() {} 589 590 @Override onHandoverToWifiFailure()591 public void onHandoverToWifiFailure() {} 592 593 @Override onInternationalCallOnWifi()594 public void onInternationalCallOnWifi() {} 595 596 @Override onEnrichedCallSessionUpdate()597 public void onEnrichedCallSessionUpdate() {} 598 599 @Override getContext()600 public Context getContext() { 601 return context; 602 } 603 getActivity()604 private InCallActivity getActivity() { 605 if (inCallButtonUi != null) { 606 Fragment fragment = inCallButtonUi.getInCallButtonUiFragment(); 607 if (fragment != null) { 608 return (InCallActivity) fragment.getActivity(); 609 } 610 } 611 return null; 612 } 613 } 614