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 Logger.get(context) 212 .logCallImpression( 213 DialerImpression.Type.IN_CALL_SCREEN_TURN_ON_WIRED_OR_EARPIECE, 214 call.getUniqueCallId(), 215 call.getTimeAddedMs()); 216 } else { 217 newRoute = CallAudioState.ROUTE_SPEAKER; 218 Logger.get(context) 219 .logCallImpression( 220 DialerImpression.Type.IN_CALL_SCREEN_TURN_ON_SPEAKERPHONE, 221 call.getUniqueCallId(), 222 call.getTimeAddedMs()); 223 } 224 225 setAudioRoute(newRoute); 226 } 227 228 @Override muteClicked(boolean checked, boolean clickedByUser)229 public void muteClicked(boolean checked, boolean clickedByUser) { 230 LogUtil.i( 231 "CallButtonPresenter", "turning on mute: %s, clicked by user: %s", checked, clickedByUser); 232 if (clickedByUser) { 233 Logger.get(context) 234 .logCallImpression( 235 checked 236 ? DialerImpression.Type.IN_CALL_SCREEN_TURN_ON_MUTE 237 : DialerImpression.Type.IN_CALL_SCREEN_TURN_OFF_MUTE, 238 call.getUniqueCallId(), 239 call.getTimeAddedMs()); 240 } 241 TelecomAdapter.getInstance().mute(checked); 242 } 243 244 @Override holdClicked(boolean checked)245 public void holdClicked(boolean checked) { 246 if (call == null) { 247 return; 248 } 249 if (checked) { 250 LogUtil.i("CallButtonPresenter", "putting the call on hold: " + call); 251 call.hold(); 252 } else { 253 LogUtil.i("CallButtonPresenter", "removing the call from hold: " + call); 254 call.unhold(); 255 } 256 } 257 258 @Override swapClicked()259 public void swapClicked() { 260 if (call == null) { 261 return; 262 } 263 264 LogUtil.i("CallButtonPresenter", "swapping the call: " + call); 265 TelecomAdapter.getInstance().swap(call.getId()); 266 } 267 268 @Override mergeClicked()269 public void mergeClicked() { 270 Logger.get(context) 271 .logCallImpression( 272 DialerImpression.Type.IN_CALL_MERGE_BUTTON_PRESSED, 273 call.getUniqueCallId(), 274 call.getTimeAddedMs()); 275 TelecomAdapter.getInstance().merge(call.getId()); 276 } 277 278 @Override addCallClicked()279 public void addCallClicked() { 280 Logger.get(context) 281 .logCallImpression( 282 DialerImpression.Type.IN_CALL_ADD_CALL_BUTTON_PRESSED, 283 call.getUniqueCallId(), 284 call.getTimeAddedMs()); 285 InCallPresenter.getInstance().addCallClicked(); 286 } 287 288 @Override showDialpadClicked(boolean checked)289 public void showDialpadClicked(boolean checked) { 290 Logger.get(context) 291 .logCallImpression( 292 DialerImpression.Type.IN_CALL_SHOW_DIALPAD_BUTTON_PRESSED, 293 call.getUniqueCallId(), 294 call.getTimeAddedMs()); 295 LogUtil.v("CallButtonPresenter", "show dialpad " + String.valueOf(checked)); 296 getActivity().showDialpadFragment(checked /* show */, true /* animate */); 297 } 298 299 @Override changeToVideoClicked()300 public void changeToVideoClicked() { 301 LogUtil.enterBlock("CallButtonPresenter.changeToVideoClicked"); 302 Logger.get(context) 303 .logCallImpression( 304 DialerImpression.Type.VIDEO_CALL_UPGRADE_REQUESTED, 305 call.getUniqueCallId(), 306 call.getTimeAddedMs()); 307 call.getVideoTech().upgradeToVideo(context); 308 } 309 310 @Override changeToRttClicked()311 public void changeToRttClicked() { 312 LogUtil.enterBlock("CallButtonPresenter.changeToRttClicked"); 313 call.sendRttUpgradeRequest(); 314 } 315 316 @Override onEndCallClicked()317 public void onEndCallClicked() { 318 LogUtil.i("CallButtonPresenter.onEndCallClicked", "call: " + call); 319 if (call != null) { 320 call.disconnect(); 321 } 322 } 323 324 @Override showAudioRouteSelector()325 public void showAudioRouteSelector() { 326 inCallButtonUi.showAudioRouteSelector(); 327 } 328 329 @Override swapSimClicked()330 public void swapSimClicked() { 331 LogUtil.enterBlock("CallButtonPresenter.swapSimClicked"); 332 Logger.get(getContext()).logImpression(Type.DUAL_SIM_CHANGE_SIM_PRESSED); 333 SwapSimWorker worker = 334 new SwapSimWorker( 335 getContext(), 336 call, 337 InCallPresenter.getInstance().getCallList(), 338 otherAccount, 339 InCallPresenter.getInstance().acquireInCallUiLock("swapSim")); 340 DialerExecutorComponent.get(getContext()) 341 .dialerExecutorFactory() 342 .createNonUiTaskBuilder(worker) 343 .build() 344 .executeParallel(null); 345 } 346 347 /** 348 * Switches the camera between the front-facing and back-facing camera. 349 * 350 * @param useFrontFacingCamera True if we should switch to using the front-facing camera, or false 351 * if we should switch to using the back-facing camera. 352 */ 353 @Override switchCameraClicked(boolean useFrontFacingCamera)354 public void switchCameraClicked(boolean useFrontFacingCamera) { 355 updateCamera(useFrontFacingCamera); 356 } 357 358 @Override toggleCameraClicked()359 public void toggleCameraClicked() { 360 LogUtil.i("CallButtonPresenter.toggleCameraClicked", ""); 361 if (call == null) { 362 return; 363 } 364 Logger.get(context) 365 .logCallImpression( 366 DialerImpression.Type.IN_CALL_SCREEN_SWAP_CAMERA, 367 call.getUniqueCallId(), 368 call.getTimeAddedMs()); 369 switchCameraClicked( 370 !InCallPresenter.getInstance().getInCallCameraManager().isUsingFrontFacingCamera()); 371 } 372 373 /** 374 * Stop or start client's video transmission. 375 * 376 * @param pause True if pausing the local user's video, or false if starting the local user's 377 * video. 378 */ 379 @Override pauseVideoClicked(boolean pause)380 public void pauseVideoClicked(boolean pause) { 381 LogUtil.i("CallButtonPresenter.pauseVideoClicked", "%s", pause ? "pause" : "unpause"); 382 383 Logger.get(context) 384 .logCallImpression( 385 pause 386 ? DialerImpression.Type.IN_CALL_SCREEN_TURN_OFF_VIDEO 387 : DialerImpression.Type.IN_CALL_SCREEN_TURN_ON_VIDEO, 388 call.getUniqueCallId(), 389 call.getTimeAddedMs()); 390 391 if (pause) { 392 call.getVideoTech().stopTransmission(); 393 } else { 394 updateCamera( 395 InCallPresenter.getInstance().getInCallCameraManager().isUsingFrontFacingCamera()); 396 call.getVideoTech().resumeTransmission(context); 397 } 398 399 inCallButtonUi.setVideoPaused(pause); 400 inCallButtonUi.enableButton(InCallButtonIds.BUTTON_PAUSE_VIDEO, false); 401 } 402 updateCamera(boolean useFrontFacingCamera)403 private void updateCamera(boolean useFrontFacingCamera) { 404 InCallCameraManager cameraManager = InCallPresenter.getInstance().getInCallCameraManager(); 405 cameraManager.setUseFrontFacingCamera(useFrontFacingCamera); 406 407 String cameraId = cameraManager.getActiveCameraId(); 408 if (cameraId != null) { 409 final int cameraDir = 410 cameraManager.isUsingFrontFacingCamera() 411 ? CameraDirection.CAMERA_DIRECTION_FRONT_FACING 412 : CameraDirection.CAMERA_DIRECTION_BACK_FACING; 413 call.setCameraDir(cameraDir); 414 call.getVideoTech().setCamera(cameraId); 415 } 416 } 417 updateUi(InCallState state, DialerCall call)418 private void updateUi(InCallState state, DialerCall call) { 419 LogUtil.v("CallButtonPresenter", "updating call UI for call: %s", call); 420 421 if (inCallButtonUi == null) { 422 return; 423 } 424 425 if (call != null) { 426 inCallButtonUi.updateInCallButtonUiColors( 427 InCallPresenter.getInstance().getThemeColorManager().getSecondaryColor()); 428 } 429 430 final boolean isEnabled = 431 state.isConnectingOrConnected() && !state.isIncoming() && call != null; 432 inCallButtonUi.setEnabled(isEnabled); 433 434 if (call == null) { 435 return; 436 } 437 438 updateButtonsState(call); 439 } 440 441 /** 442 * Updates the buttons applicable for the UI. 443 * 444 * @param call The active call. 445 */ 446 @SuppressWarnings(value = {"MissingPermission"}) updateButtonsState(DialerCall call)447 private void updateButtonsState(DialerCall call) { 448 LogUtil.v("CallButtonPresenter.updateButtonsState", ""); 449 final boolean isVideo = call.isVideoCall(); 450 451 // Common functionality (audio, hold, etc). 452 // Show either HOLD or SWAP, but not both. If neither HOLD or SWAP is available: 453 // (1) If the device normally can hold, show HOLD in a disabled state. 454 // (2) If the device doesn't have the concept of hold/swap, remove the button. 455 final boolean showSwap = call.can(android.telecom.Call.Details.CAPABILITY_SWAP_CONFERENCE); 456 final boolean showHold = 457 !showSwap 458 && call.can(android.telecom.Call.Details.CAPABILITY_SUPPORT_HOLD) 459 && call.can(android.telecom.Call.Details.CAPABILITY_HOLD); 460 final boolean isCallOnHold = call.getState() == DialerCallState.ONHOLD; 461 462 final boolean showAddCall = 463 TelecomAdapter.getInstance().canAddCall() && UserManagerCompat.isUserUnlocked(context); 464 // There can only be two calls so don't show the ability to merge when one of them 465 // is a speak easy call. 466 final boolean showMerge = 467 InCallPresenter.getInstance() 468 .getCallList() 469 .getAllCalls() 470 .stream() 471 .noneMatch(c -> c != null && c.isSpeakEasyCall()) 472 && call.can(android.telecom.Call.Details.CAPABILITY_MERGE_CONFERENCE); 473 final boolean showUpgradeToVideo = !isVideo && (hasVideoCallCapabilities(call)); 474 final boolean showDowngradeToAudio = isVideo && isDowngradeToAudioSupported(call); 475 final boolean showMute = call.can(android.telecom.Call.Details.CAPABILITY_MUTE); 476 477 final boolean hasCameraPermission = 478 isVideo && VideoUtils.hasCameraPermissionAndShownPrivacyToast(context); 479 // Disabling local video doesn't seem to work when dialing. See a bug. 480 final boolean showPauseVideo = 481 isVideo 482 && call.getState() != DialerCallState.DIALING 483 && call.getState() != DialerCallState.CONNECTING; 484 485 otherAccount = TelecomUtil.getOtherAccount(getContext(), call.getAccountHandle()); 486 boolean showSwapSim = 487 !call.isEmergencyCall() 488 && otherAccount != null 489 && !call.isVoiceMailNumber() 490 && DialerCallState.isDialing(call.getState()) 491 // Most devices cannot make calls on 2 SIMs at the same time. 492 && InCallPresenter.getInstance().getCallList().getAllCalls().size() == 1; 493 494 boolean showUpgradeToRtt = call.canUpgradeToRttCall(); 495 boolean enableUpgradeToRtt = showUpgradeToRtt && call.getState() == DialerCallState.ACTIVE; 496 497 inCallButtonUi.showButton(InCallButtonIds.BUTTON_AUDIO, true); 498 inCallButtonUi.showButton(InCallButtonIds.BUTTON_SWAP, showSwap); 499 inCallButtonUi.showButton(InCallButtonIds.BUTTON_HOLD, showHold); 500 inCallButtonUi.setHold(isCallOnHold); 501 inCallButtonUi.showButton(InCallButtonIds.BUTTON_MUTE, showMute); 502 inCallButtonUi.showButton(InCallButtonIds.BUTTON_SWAP_SIM, showSwapSim); 503 inCallButtonUi.showButton(InCallButtonIds.BUTTON_ADD_CALL, true); 504 inCallButtonUi.enableButton(InCallButtonIds.BUTTON_ADD_CALL, showAddCall); 505 inCallButtonUi.showButton(InCallButtonIds.BUTTON_UPGRADE_TO_VIDEO, showUpgradeToVideo); 506 inCallButtonUi.showButton(InCallButtonIds.BUTTON_UPGRADE_TO_RTT, showUpgradeToRtt); 507 inCallButtonUi.enableButton(InCallButtonIds.BUTTON_UPGRADE_TO_RTT, enableUpgradeToRtt); 508 inCallButtonUi.showButton(InCallButtonIds.BUTTON_DOWNGRADE_TO_AUDIO, showDowngradeToAudio); 509 inCallButtonUi.showButton( 510 InCallButtonIds.BUTTON_SWITCH_CAMERA, 511 isVideo && hasCameraPermission && call.getVideoTech().isTransmitting()); 512 inCallButtonUi.showButton(InCallButtonIds.BUTTON_PAUSE_VIDEO, showPauseVideo); 513 if (isVideo) { 514 inCallButtonUi.setVideoPaused(!call.getVideoTech().isTransmitting() || !hasCameraPermission); 515 } 516 inCallButtonUi.showButton(InCallButtonIds.BUTTON_DIALPAD, true); 517 inCallButtonUi.showButton(InCallButtonIds.BUTTON_MERGE, showMerge); 518 519 inCallButtonUi.updateButtonStates(); 520 } 521 hasVideoCallCapabilities(DialerCall call)522 private boolean hasVideoCallCapabilities(DialerCall call) { 523 return call.getVideoTech().isAvailable(context, call.getAccountHandle()); 524 } 525 526 /** 527 * Determines if downgrading from a video call to an audio-only call is supported. In order to 528 * support downgrade to audio, the SDK version must be >= N and the call should NOT have the 529 * {@link android.telecom.Call.Details#CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO}. 530 * 531 * @param call The call. 532 * @return {@code true} if downgrading to an audio-only call from a video call is supported. 533 */ isDowngradeToAudioSupported(DialerCall call)534 private boolean isDowngradeToAudioSupported(DialerCall call) { 535 // TODO(a bug): If there is an RCS video share session, return true here 536 return !call.can(CallCompat.Details.CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO); 537 } 538 539 @Override onSaveInstanceState(Bundle outState)540 public void onSaveInstanceState(Bundle outState) {} 541 542 @Override onRestoreInstanceState(Bundle savedInstanceState)543 public void onRestoreInstanceState(Bundle savedInstanceState) {} 544 545 @Override onCameraPermissionGranted()546 public void onCameraPermissionGranted() { 547 if (call != null) { 548 updateButtonsState(call); 549 } 550 } 551 552 @Override onActiveCameraSelectionChanged(boolean isUsingFrontFacingCamera)553 public void onActiveCameraSelectionChanged(boolean isUsingFrontFacingCamera) { 554 if (inCallButtonUi == null) { 555 return; 556 } 557 inCallButtonUi.setCameraSwitched(!isUsingFrontFacingCamera); 558 } 559 560 @Override onDialerCallSessionModificationStateChange()561 public void onDialerCallSessionModificationStateChange() { 562 if (inCallButtonUi != null && call != null) { 563 inCallButtonUi.enableButton(InCallButtonIds.BUTTON_PAUSE_VIDEO, true); 564 updateButtonsState(call); 565 } 566 } 567 568 @Override onDialerCallDisconnect()569 public void onDialerCallDisconnect() {} 570 571 @Override onDialerCallUpdate()572 public void onDialerCallUpdate() {} 573 574 @Override onDialerCallChildNumberChange()575 public void onDialerCallChildNumberChange() {} 576 577 @Override onDialerCallLastForwardedNumberChange()578 public void onDialerCallLastForwardedNumberChange() {} 579 580 @Override onDialerCallUpgradeToVideo()581 public void onDialerCallUpgradeToVideo() {} 582 583 @Override onWiFiToLteHandover()584 public void onWiFiToLteHandover() {} 585 586 @Override onHandoverToWifiFailure()587 public void onHandoverToWifiFailure() {} 588 589 @Override onInternationalCallOnWifi()590 public void onInternationalCallOnWifi() {} 591 592 @Override onEnrichedCallSessionUpdate()593 public void onEnrichedCallSessionUpdate() {} 594 595 @Override getContext()596 public Context getContext() { 597 return context; 598 } 599 getActivity()600 private InCallActivity getActivity() { 601 if (inCallButtonUi != null) { 602 Fragment fragment = inCallButtonUi.getInCallButtonUiFragment(); 603 if (fragment != null) { 604 return (InCallActivity) fragment.getActivity(); 605 } 606 } 607 return null; 608 } 609 } 610