blob: 8bf234823ed5c2ff96552093af2482b2140ad37c [file] [log] [blame]
Eric Erfanianccca3152017-02-22 16:32:36 -08001/*
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;
Eric Erfanianccca3152017-02-22 16:32:36 -080020import android.os.Bundle;
Eric Erfanian2ca43182017-08-31 06:57:16 -070021import android.os.Trace;
Eric Erfanianccca3152017-02-22 16:32:36 -080022import android.support.v4.app.Fragment;
23import android.support.v4.os.UserManagerCompat;
24import android.telecom.CallAudioState;
twyen00623aa2017-10-10 12:15:08 -070025import android.telecom.PhoneAccountHandle;
Eric Erfanianccca3152017-02-22 16:32:36 -080026import com.android.contacts.common.compat.CallCompat;
27import com.android.dialer.common.Assert;
28import com.android.dialer.common.LogUtil;
twyen00623aa2017-10-10 12:15:08 -070029import com.android.dialer.common.concurrent.DialerExecutorComponent;
Eric Erfanian8369df02017-05-03 10:27:13 -070030import com.android.dialer.logging.DialerImpression;
twyenfc1f9cf2017-11-27 13:22:48 -080031import com.android.dialer.logging.DialerImpression.Type;
Eric Erfanianccca3152017-02-22 16:32:36 -080032import com.android.dialer.logging.Logger;
twyen00623aa2017-10-10 12:15:08 -070033import com.android.dialer.telecom.TelecomUtil;
Eric Erfanianccca3152017-02-22 16:32:36 -080034import com.android.incallui.InCallCameraManager.Listener;
35import com.android.incallui.InCallPresenter.CanAddCallListener;
36import com.android.incallui.InCallPresenter.InCallDetailsListener;
37import com.android.incallui.InCallPresenter.InCallState;
38import com.android.incallui.InCallPresenter.InCallStateListener;
39import com.android.incallui.InCallPresenter.IncomingCallListener;
Eric Erfanian8369df02017-05-03 10:27:13 -070040import com.android.incallui.audiomode.AudioModeProvider;
41import com.android.incallui.audiomode.AudioModeProvider.AudioModeListener;
Eric Erfanianccca3152017-02-22 16:32:36 -080042import com.android.incallui.call.CallList;
43import com.android.incallui.call.DialerCall;
Eric Erfaniand5e47f62017-03-15 14:41:07 -070044import com.android.incallui.call.DialerCall.CameraDirection;
Eric Erfanianccca3152017-02-22 16:32:36 -080045import com.android.incallui.call.TelecomAdapter;
wangqibb94ca62018-04-27 14:34:04 -070046import com.android.incallui.call.state.DialerCallState;
Eric Erfanianccca3152017-02-22 16:32:36 -080047import com.android.incallui.incall.protocol.InCallButtonIds;
48import com.android.incallui.incall.protocol.InCallButtonUi;
49import com.android.incallui.incall.protocol.InCallButtonUiDelegate;
twyen00623aa2017-10-10 12:15:08 -070050import com.android.incallui.multisim.SwapSimWorker;
Eric Erfanian90508232017-03-24 09:31:16 -070051import com.android.incallui.videotech.utils.VideoUtils;
Eric Erfanianccca3152017-02-22 16:32:36 -080052
53/** Logic for call buttons. */
54public class CallButtonPresenter
55 implements InCallStateListener,
56 AudioModeListener,
57 IncomingCallListener,
58 InCallDetailsListener,
59 CanAddCallListener,
60 Listener,
61 InCallButtonUiDelegate {
62
linyuh183cb712017-12-27 17:02:37 -080063 private final Context context;
64 private InCallButtonUi inCallButtonUi;
65 private DialerCall call;
Eric Erfanianccca3152017-02-22 16:32:36 -080066 private boolean isInCallButtonUiReady;
linyuh183cb712017-12-27 17:02:37 -080067 private PhoneAccountHandle otherAccount;
Eric Erfanianccca3152017-02-22 16:32:36 -080068
69 public CallButtonPresenter(Context context) {
linyuh183cb712017-12-27 17:02:37 -080070 this.context = context.getApplicationContext();
Eric Erfanianccca3152017-02-22 16:32:36 -080071 }
72
73 @Override
74 public void onInCallButtonUiReady(InCallButtonUi ui) {
75 Assert.checkState(!isInCallButtonUiReady);
linyuh183cb712017-12-27 17:02:37 -080076 inCallButtonUi = ui;
Eric Erfanianccca3152017-02-22 16:32:36 -080077 AudioModeProvider.getInstance().addListener(this);
78
79 // register for call state changes last
80 final InCallPresenter inCallPresenter = InCallPresenter.getInstance();
81 inCallPresenter.addListener(this);
82 inCallPresenter.addIncomingCallListener(this);
83 inCallPresenter.addDetailsListener(this);
84 inCallPresenter.addCanAddCallListener(this);
85 inCallPresenter.getInCallCameraManager().addCameraSelectionListener(this);
86
87 // Update the buttons state immediately for the current call
88 onStateChange(InCallState.NO_CALLS, inCallPresenter.getInCallState(), CallList.getInstance());
89 isInCallButtonUiReady = true;
90 }
91
92 @Override
93 public void onInCallButtonUiUnready() {
94 Assert.checkState(isInCallButtonUiReady);
linyuh183cb712017-12-27 17:02:37 -080095 inCallButtonUi = null;
Eric Erfanianccca3152017-02-22 16:32:36 -080096 InCallPresenter.getInstance().removeListener(this);
97 AudioModeProvider.getInstance().removeListener(this);
98 InCallPresenter.getInstance().removeIncomingCallListener(this);
99 InCallPresenter.getInstance().removeDetailsListener(this);
100 InCallPresenter.getInstance().getInCallCameraManager().removeCameraSelectionListener(this);
101 InCallPresenter.getInstance().removeCanAddCallListener(this);
102 isInCallButtonUiReady = false;
103 }
104
105 @Override
106 public void onStateChange(InCallState oldState, InCallState newState, CallList callList) {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700107 Trace.beginSection("CallButtonPresenter.onStateChange");
Eric Erfanianccca3152017-02-22 16:32:36 -0800108 if (newState == InCallState.OUTGOING) {
linyuh183cb712017-12-27 17:02:37 -0800109 call = callList.getOutgoingCall();
Eric Erfanianccca3152017-02-22 16:32:36 -0800110 } else if (newState == InCallState.INCALL) {
linyuh183cb712017-12-27 17:02:37 -0800111 call = callList.getActiveOrBackgroundCall();
Eric Erfanianccca3152017-02-22 16:32:36 -0800112
113 // When connected to voice mail, automatically shows the dialpad.
114 // (On previous releases we showed it when in-call shows up, before waiting for
115 // OUTGOING. We may want to do that once we start showing "Voice mail" label on
116 // the dialpad too.)
linyuh183cb712017-12-27 17:02:37 -0800117 if (oldState == InCallState.OUTGOING && call != null) {
118 if (call.isVoiceMailNumber() && getActivity() != null) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800119 getActivity().showDialpadFragment(true /* show */, true /* animate */);
120 }
121 }
122 } else if (newState == InCallState.INCOMING) {
123 if (getActivity() != null) {
124 getActivity().showDialpadFragment(false /* show */, true /* animate */);
125 }
linyuh183cb712017-12-27 17:02:37 -0800126 call = callList.getIncomingCall();
Eric Erfanianccca3152017-02-22 16:32:36 -0800127 } else {
linyuh183cb712017-12-27 17:02:37 -0800128 call = null;
Eric Erfanianccca3152017-02-22 16:32:36 -0800129 }
linyuh183cb712017-12-27 17:02:37 -0800130 updateUi(newState, call);
Eric Erfanian2ca43182017-08-31 06:57:16 -0700131 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800132 }
133
134 /**
135 * Updates the user interface in response to a change in the details of a call. Currently handles
136 * changes to the call buttons in response to a change in the details for a call. This is
137 * important to ensure changes to the active call are reflected in the available buttons.
138 *
139 * @param call The active call.
140 * @param details The call details.
141 */
142 @Override
143 public void onDetailsChanged(DialerCall call, android.telecom.Call.Details details) {
144 // Only update if the changes are for the currently active call
linyuh183cb712017-12-27 17:02:37 -0800145 if (inCallButtonUi != null && call != null && call.equals(this.call)) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800146 updateButtonsState(call);
147 }
148 }
149
150 @Override
151 public void onIncomingCall(InCallState oldState, InCallState newState, DialerCall call) {
152 onStateChange(oldState, newState, CallList.getInstance());
153 }
154
155 @Override
156 public void onCanAddCallChanged(boolean canAddCall) {
linyuh183cb712017-12-27 17:02:37 -0800157 if (inCallButtonUi != null && call != null) {
158 updateButtonsState(call);
Eric Erfanianccca3152017-02-22 16:32:36 -0800159 }
160 }
161
162 @Override
163 public void onAudioStateChanged(CallAudioState audioState) {
linyuh183cb712017-12-27 17:02:37 -0800164 if (inCallButtonUi != null) {
165 inCallButtonUi.setAudioState(audioState);
Eric Erfanianccca3152017-02-22 16:32:36 -0800166 }
167 }
168
169 @Override
170 public CallAudioState getCurrentAudioState() {
171 return AudioModeProvider.getInstance().getAudioState();
172 }
173
174 @Override
175 public void setAudioRoute(int route) {
176 LogUtil.i(
177 "CallButtonPresenter.setAudioRoute",
178 "sending new audio route: " + CallAudioState.audioRouteToString(route));
179 TelecomAdapter.getInstance().setAudioRoute(route);
180 }
181
182 /** Function assumes that bluetooth is not supported. */
183 @Override
184 public void toggleSpeakerphone() {
185 // This function should not be called if bluetooth is available.
186 CallAudioState audioState = getCurrentAudioState();
187 if (0 != (CallAudioState.ROUTE_BLUETOOTH & audioState.getSupportedRouteMask())) {
188 // It's clear the UI is wrong, so update the supported mode once again.
189 LogUtil.e(
190 "CallButtonPresenter", "toggling speakerphone not allowed when bluetooth supported.");
linyuh183cb712017-12-27 17:02:37 -0800191 inCallButtonUi.setAudioState(audioState);
Eric Erfanianccca3152017-02-22 16:32:36 -0800192 return;
193 }
194
195 int newRoute;
196 if (audioState.getRoute() == CallAudioState.ROUTE_SPEAKER) {
197 newRoute = CallAudioState.ROUTE_WIRED_OR_EARPIECE;
linyuh183cb712017-12-27 17:02:37 -0800198 Logger.get(context)
Eric Erfanianccca3152017-02-22 16:32:36 -0800199 .logCallImpression(
200 DialerImpression.Type.IN_CALL_SCREEN_TURN_ON_WIRED_OR_EARPIECE,
linyuh183cb712017-12-27 17:02:37 -0800201 call.getUniqueCallId(),
202 call.getTimeAddedMs());
Eric Erfanianccca3152017-02-22 16:32:36 -0800203 } else {
204 newRoute = CallAudioState.ROUTE_SPEAKER;
linyuh183cb712017-12-27 17:02:37 -0800205 Logger.get(context)
Eric Erfanianccca3152017-02-22 16:32:36 -0800206 .logCallImpression(
207 DialerImpression.Type.IN_CALL_SCREEN_TURN_ON_SPEAKERPHONE,
linyuh183cb712017-12-27 17:02:37 -0800208 call.getUniqueCallId(),
209 call.getTimeAddedMs());
Eric Erfanianccca3152017-02-22 16:32:36 -0800210 }
211
212 setAudioRoute(newRoute);
213 }
214
215 @Override
Eric Erfanian9a090c82017-03-16 19:22:24 -0700216 public void muteClicked(boolean checked, boolean clickedByUser) {
217 LogUtil.i(
218 "CallButtonPresenter", "turning on mute: %s, clicked by user: %s", checked, clickedByUser);
219 if (clickedByUser) {
linyuh183cb712017-12-27 17:02:37 -0800220 Logger.get(context)
Eric Erfanian9a090c82017-03-16 19:22:24 -0700221 .logCallImpression(
222 checked
223 ? DialerImpression.Type.IN_CALL_SCREEN_TURN_ON_MUTE
224 : DialerImpression.Type.IN_CALL_SCREEN_TURN_OFF_MUTE,
linyuh183cb712017-12-27 17:02:37 -0800225 call.getUniqueCallId(),
226 call.getTimeAddedMs());
Eric Erfanian9a090c82017-03-16 19:22:24 -0700227 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800228 TelecomAdapter.getInstance().mute(checked);
229 }
230
231 @Override
232 public void holdClicked(boolean checked) {
linyuh183cb712017-12-27 17:02:37 -0800233 if (call == null) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800234 return;
235 }
236 if (checked) {
linyuh183cb712017-12-27 17:02:37 -0800237 LogUtil.i("CallButtonPresenter", "putting the call on hold: " + call);
238 call.hold();
Eric Erfanianccca3152017-02-22 16:32:36 -0800239 } else {
linyuh183cb712017-12-27 17:02:37 -0800240 LogUtil.i("CallButtonPresenter", "removing the call from hold: " + call);
241 call.unhold();
Eric Erfanianccca3152017-02-22 16:32:36 -0800242 }
243 }
244
245 @Override
246 public void swapClicked() {
linyuh183cb712017-12-27 17:02:37 -0800247 if (call == null) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800248 return;
249 }
250
linyuh183cb712017-12-27 17:02:37 -0800251 LogUtil.i("CallButtonPresenter", "swapping the call: " + call);
252 TelecomAdapter.getInstance().swap(call.getId());
Eric Erfanianccca3152017-02-22 16:32:36 -0800253 }
254
255 @Override
256 public void mergeClicked() {
linyuh183cb712017-12-27 17:02:37 -0800257 Logger.get(context)
Eric Erfanian2ca43182017-08-31 06:57:16 -0700258 .logCallImpression(
259 DialerImpression.Type.IN_CALL_MERGE_BUTTON_PRESSED,
linyuh183cb712017-12-27 17:02:37 -0800260 call.getUniqueCallId(),
261 call.getTimeAddedMs());
262 TelecomAdapter.getInstance().merge(call.getId());
Eric Erfanianccca3152017-02-22 16:32:36 -0800263 }
264
265 @Override
266 public void addCallClicked() {
linyuh183cb712017-12-27 17:02:37 -0800267 Logger.get(context)
Eric Erfanian2ca43182017-08-31 06:57:16 -0700268 .logCallImpression(
269 DialerImpression.Type.IN_CALL_ADD_CALL_BUTTON_PRESSED,
linyuh183cb712017-12-27 17:02:37 -0800270 call.getUniqueCallId(),
271 call.getTimeAddedMs());
Sekine Yasuakia7020842018-05-31 17:10:12 +0900272 InCallPresenter.getInstance().addCallClicked();
Eric Erfanianccca3152017-02-22 16:32:36 -0800273 }
274
275 @Override
276 public void showDialpadClicked(boolean checked) {
linyuh183cb712017-12-27 17:02:37 -0800277 Logger.get(context)
Eric Erfanian2ca43182017-08-31 06:57:16 -0700278 .logCallImpression(
279 DialerImpression.Type.IN_CALL_SHOW_DIALPAD_BUTTON_PRESSED,
linyuh183cb712017-12-27 17:02:37 -0800280 call.getUniqueCallId(),
281 call.getTimeAddedMs());
Eric Erfanianccca3152017-02-22 16:32:36 -0800282 LogUtil.v("CallButtonPresenter", "show dialpad " + String.valueOf(checked));
283 getActivity().showDialpadFragment(checked /* show */, true /* animate */);
284 }
285
286 @Override
287 public void changeToVideoClicked() {
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700288 LogUtil.enterBlock("CallButtonPresenter.changeToVideoClicked");
linyuh183cb712017-12-27 17:02:37 -0800289 Logger.get(context)
Eric Erfanian8369df02017-05-03 10:27:13 -0700290 .logCallImpression(
291 DialerImpression.Type.VIDEO_CALL_UPGRADE_REQUESTED,
linyuh183cb712017-12-27 17:02:37 -0800292 call.getUniqueCallId(),
293 call.getTimeAddedMs());
294 call.getVideoTech().upgradeToVideo(context);
Eric Erfanianccca3152017-02-22 16:32:36 -0800295 }
296
297 @Override
wangqif6be6172018-03-30 15:57:56 -0700298 public void changeToRttClicked() {
299 LogUtil.enterBlock("CallButtonPresenter.changeToRttClicked");
300 call.sendRttUpgradeRequest();
301 }
302
303 @Override
Eric Erfanianccca3152017-02-22 16:32:36 -0800304 public void onEndCallClicked() {
linyuh183cb712017-12-27 17:02:37 -0800305 LogUtil.i("CallButtonPresenter.onEndCallClicked", "call: " + call);
306 if (call != null) {
307 call.disconnect();
Eric Erfanianccca3152017-02-22 16:32:36 -0800308 }
309 }
310
311 @Override
312 public void showAudioRouteSelector() {
linyuh183cb712017-12-27 17:02:37 -0800313 inCallButtonUi.showAudioRouteSelector();
Eric Erfanianccca3152017-02-22 16:32:36 -0800314 }
315
twyen00623aa2017-10-10 12:15:08 -0700316 @Override
317 public void swapSimClicked() {
318 LogUtil.enterBlock("CallButtonPresenter.swapSimClicked");
twyenfc1f9cf2017-11-27 13:22:48 -0800319 Logger.get(getContext()).logImpression(Type.DUAL_SIM_CHANGE_SIM_PRESSED);
twyen00623aa2017-10-10 12:15:08 -0700320 SwapSimWorker worker =
321 new SwapSimWorker(
322 getContext(),
linyuh183cb712017-12-27 17:02:37 -0800323 call,
twyen00623aa2017-10-10 12:15:08 -0700324 InCallPresenter.getInstance().getCallList(),
linyuh183cb712017-12-27 17:02:37 -0800325 otherAccount,
twyen00623aa2017-10-10 12:15:08 -0700326 InCallPresenter.getInstance().acquireInCallUiLock("swapSim"));
327 DialerExecutorComponent.get(getContext())
328 .dialerExecutorFactory()
329 .createNonUiTaskBuilder(worker)
330 .build()
331 .executeParallel(null);
332 }
333
Eric Erfanianccca3152017-02-22 16:32:36 -0800334 /**
335 * Switches the camera between the front-facing and back-facing camera.
336 *
337 * @param useFrontFacingCamera True if we should switch to using the front-facing camera, or false
338 * if we should switch to using the back-facing camera.
339 */
340 @Override
341 public void switchCameraClicked(boolean useFrontFacingCamera) {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700342 updateCamera(useFrontFacingCamera);
Eric Erfanianccca3152017-02-22 16:32:36 -0800343 }
344
345 @Override
346 public void toggleCameraClicked() {
347 LogUtil.i("CallButtonPresenter.toggleCameraClicked", "");
linyuh183cb712017-12-27 17:02:37 -0800348 if (call == null) {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700349 return;
350 }
linyuh183cb712017-12-27 17:02:37 -0800351 Logger.get(context)
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700352 .logCallImpression(
353 DialerImpression.Type.IN_CALL_SCREEN_SWAP_CAMERA,
linyuh183cb712017-12-27 17:02:37 -0800354 call.getUniqueCallId(),
355 call.getTimeAddedMs());
Eric Erfanianccca3152017-02-22 16:32:36 -0800356 switchCameraClicked(
357 !InCallPresenter.getInstance().getInCallCameraManager().isUsingFrontFacingCamera());
358 }
359
360 /**
361 * Stop or start client's video transmission.
362 *
363 * @param pause True if pausing the local user's video, or false if starting the local user's
364 * video.
365 */
366 @Override
367 public void pauseVideoClicked(boolean pause) {
368 LogUtil.i("CallButtonPresenter.pauseVideoClicked", "%s", pause ? "pause" : "unpause");
Eric Erfanianccca3152017-02-22 16:32:36 -0800369
linyuh183cb712017-12-27 17:02:37 -0800370 Logger.get(context)
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700371 .logCallImpression(
372 pause
373 ? DialerImpression.Type.IN_CALL_SCREEN_TURN_OFF_VIDEO
374 : DialerImpression.Type.IN_CALL_SCREEN_TURN_ON_VIDEO,
linyuh183cb712017-12-27 17:02:37 -0800375 call.getUniqueCallId(),
376 call.getTimeAddedMs());
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700377
Eric Erfanianccca3152017-02-22 16:32:36 -0800378 if (pause) {
linyuh183cb712017-12-27 17:02:37 -0800379 call.getVideoTech().setCamera(null);
380 call.getVideoTech().stopTransmission();
Eric Erfanianccca3152017-02-22 16:32:36 -0800381 } else {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700382 updateCamera(
383 InCallPresenter.getInstance().getInCallCameraManager().isUsingFrontFacingCamera());
linyuh183cb712017-12-27 17:02:37 -0800384 call.getVideoTech().resumeTransmission(context);
Eric Erfanianccca3152017-02-22 16:32:36 -0800385 }
386
linyuh183cb712017-12-27 17:02:37 -0800387 inCallButtonUi.setVideoPaused(pause);
388 inCallButtonUi.enableButton(InCallButtonIds.BUTTON_PAUSE_VIDEO, false);
Eric Erfanianccca3152017-02-22 16:32:36 -0800389 }
390
Eric Erfanian2ca43182017-08-31 06:57:16 -0700391 private void updateCamera(boolean useFrontFacingCamera) {
392 InCallCameraManager cameraManager = InCallPresenter.getInstance().getInCallCameraManager();
393 cameraManager.setUseFrontFacingCamera(useFrontFacingCamera);
394
395 String cameraId = cameraManager.getActiveCameraId();
396 if (cameraId != null) {
397 final int cameraDir =
398 cameraManager.isUsingFrontFacingCamera()
399 ? CameraDirection.CAMERA_DIRECTION_FRONT_FACING
400 : CameraDirection.CAMERA_DIRECTION_BACK_FACING;
linyuh183cb712017-12-27 17:02:37 -0800401 call.setCameraDir(cameraDir);
402 call.getVideoTech().setCamera(cameraId);
Eric Erfanian2ca43182017-08-31 06:57:16 -0700403 }
404 }
405
Eric Erfanianccca3152017-02-22 16:32:36 -0800406 private void updateUi(InCallState state, DialerCall call) {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700407 LogUtil.v("CallButtonPresenter", "updating call UI for call: %s", call);
Eric Erfanianccca3152017-02-22 16:32:36 -0800408
linyuh183cb712017-12-27 17:02:37 -0800409 if (inCallButtonUi == null) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800410 return;
411 }
412
Eric Erfanian92854e02018-07-10 18:37:33 +0000413 if (call != null) {
414 inCallButtonUi.updateInCallButtonUiColors(
415 InCallPresenter.getInstance().getThemeColorManager().getSecondaryColor());
416 }
417
Eric Erfanianccca3152017-02-22 16:32:36 -0800418 final boolean isEnabled =
419 state.isConnectingOrConnected() && !state.isIncoming() && call != null;
linyuh183cb712017-12-27 17:02:37 -0800420 inCallButtonUi.setEnabled(isEnabled);
Eric Erfanianccca3152017-02-22 16:32:36 -0800421
422 if (call == null) {
423 return;
424 }
425
426 updateButtonsState(call);
427 }
428
429 /**
430 * Updates the buttons applicable for the UI.
431 *
432 * @param call The active call.
433 */
linyuh60c1e572018-06-28 20:13:52 -0700434 @SuppressWarnings(value = {"MissingPermission"})
Eric Erfanianccca3152017-02-22 16:32:36 -0800435 private void updateButtonsState(DialerCall call) {
436 LogUtil.v("CallButtonPresenter.updateButtonsState", "");
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700437 final boolean isVideo = call.isVideoCall();
Eric Erfanianccca3152017-02-22 16:32:36 -0800438
439 // Common functionality (audio, hold, etc).
440 // Show either HOLD or SWAP, but not both. If neither HOLD or SWAP is available:
441 // (1) If the device normally can hold, show HOLD in a disabled state.
442 // (2) If the device doesn't have the concept of hold/swap, remove the button.
443 final boolean showSwap = call.can(android.telecom.Call.Details.CAPABILITY_SWAP_CONFERENCE);
444 final boolean showHold =
445 !showSwap
446 && call.can(android.telecom.Call.Details.CAPABILITY_SUPPORT_HOLD)
447 && call.can(android.telecom.Call.Details.CAPABILITY_HOLD);
wangqibb94ca62018-04-27 14:34:04 -0700448 final boolean isCallOnHold = call.getState() == DialerCallState.ONHOLD;
Eric Erfanianccca3152017-02-22 16:32:36 -0800449
450 final boolean showAddCall =
linyuh183cb712017-12-27 17:02:37 -0800451 TelecomAdapter.getInstance().canAddCall() && UserManagerCompat.isUserUnlocked(context);
erfanian9dfd6a42018-04-17 15:01:17 -0700452 // There can only be two calls so don't show the ability to merge when one of them
453 // is a speak easy call.
454 final boolean showMerge =
455 InCallPresenter.getInstance()
456 .getCallList()
457 .getAllCalls()
458 .stream()
459 .noneMatch(c -> c != null && c.isSpeakEasyCall())
460 && call.can(android.telecom.Call.Details.CAPABILITY_MERGE_CONFERENCE);
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700461 final boolean showUpgradeToVideo = !isVideo && (hasVideoCallCapabilities(call));
Eric Erfanianccca3152017-02-22 16:32:36 -0800462 final boolean showDowngradeToAudio = isVideo && isDowngradeToAudioSupported(call);
463 final boolean showMute = call.can(android.telecom.Call.Details.CAPABILITY_MUTE);
464
465 final boolean hasCameraPermission =
linyuh183cb712017-12-27 17:02:37 -0800466 isVideo && VideoUtils.hasCameraPermissionAndShownPrivacyToast(context);
Eric Erfanian938468d2017-10-24 14:05:52 -0700467 // Disabling local video doesn't seem to work when dialing. See a bug.
Eric Erfanianccca3152017-02-22 16:32:36 -0800468 final boolean showPauseVideo =
469 isVideo
wangqibb94ca62018-04-27 14:34:04 -0700470 && call.getState() != DialerCallState.DIALING
471 && call.getState() != DialerCallState.CONNECTING;
Eric Erfanianccca3152017-02-22 16:32:36 -0800472
linyuh183cb712017-12-27 17:02:37 -0800473 otherAccount = TelecomUtil.getOtherAccount(getContext(), call.getAccountHandle());
twyen38af6512017-11-22 17:12:49 -0800474 boolean showSwapSim =
twyenea3b1622018-04-24 10:45:08 -0700475 !call.isEmergencyCall()
476 && otherAccount != null
twyen2c6803d2017-11-28 11:41:49 -0800477 && !call.isVoiceMailNumber()
wangqibb94ca62018-04-27 14:34:04 -0700478 && DialerCallState.isDialing(call.getState())
twyen38af6512017-11-22 17:12:49 -0800479 // Most devices cannot make calls on 2 SIMs at the same time.
480 && InCallPresenter.getInstance().getCallList().getAllCalls().size() == 1;
twyen00623aa2017-10-10 12:15:08 -0700481
wangqi01b78272018-04-03 17:02:44 -0700482 boolean showUpgradeToRtt = call.canUpgradeToRttCall();
wangqibb94ca62018-04-27 14:34:04 -0700483 boolean enableUpgradeToRtt = showUpgradeToRtt && call.getState() == DialerCallState.ACTIVE;
wangqif6be6172018-03-30 15:57:56 -0700484
linyuh183cb712017-12-27 17:02:37 -0800485 inCallButtonUi.showButton(InCallButtonIds.BUTTON_AUDIO, true);
486 inCallButtonUi.showButton(InCallButtonIds.BUTTON_SWAP, showSwap);
487 inCallButtonUi.showButton(InCallButtonIds.BUTTON_HOLD, showHold);
488 inCallButtonUi.setHold(isCallOnHold);
489 inCallButtonUi.showButton(InCallButtonIds.BUTTON_MUTE, showMute);
490 inCallButtonUi.showButton(InCallButtonIds.BUTTON_SWAP_SIM, showSwapSim);
491 inCallButtonUi.showButton(InCallButtonIds.BUTTON_ADD_CALL, true);
492 inCallButtonUi.enableButton(InCallButtonIds.BUTTON_ADD_CALL, showAddCall);
493 inCallButtonUi.showButton(InCallButtonIds.BUTTON_UPGRADE_TO_VIDEO, showUpgradeToVideo);
wangqif6be6172018-03-30 15:57:56 -0700494 inCallButtonUi.showButton(InCallButtonIds.BUTTON_UPGRADE_TO_RTT, showUpgradeToRtt);
wangqi15514ef2018-04-04 10:50:13 -0700495 inCallButtonUi.enableButton(InCallButtonIds.BUTTON_UPGRADE_TO_RTT, enableUpgradeToRtt);
linyuh183cb712017-12-27 17:02:37 -0800496 inCallButtonUi.showButton(InCallButtonIds.BUTTON_DOWNGRADE_TO_AUDIO, showDowngradeToAudio);
497 inCallButtonUi.showButton(
roldenburgf15085f2017-11-06 12:02:06 -0800498 InCallButtonIds.BUTTON_SWITCH_CAMERA,
499 isVideo && hasCameraPermission && call.getVideoTech().isTransmitting());
linyuh183cb712017-12-27 17:02:37 -0800500 inCallButtonUi.showButton(InCallButtonIds.BUTTON_PAUSE_VIDEO, showPauseVideo);
Eric Erfanianccca3152017-02-22 16:32:36 -0800501 if (isVideo) {
linyuh183cb712017-12-27 17:02:37 -0800502 inCallButtonUi.setVideoPaused(!call.getVideoTech().isTransmitting() || !hasCameraPermission);
Eric Erfanianccca3152017-02-22 16:32:36 -0800503 }
linyuh183cb712017-12-27 17:02:37 -0800504 inCallButtonUi.showButton(InCallButtonIds.BUTTON_DIALPAD, true);
505 inCallButtonUi.showButton(InCallButtonIds.BUTTON_MERGE, showMerge);
Eric Erfanianccca3152017-02-22 16:32:36 -0800506
linyuh183cb712017-12-27 17:02:37 -0800507 inCallButtonUi.updateButtonStates();
Eric Erfanianccca3152017-02-22 16:32:36 -0800508 }
509
510 private boolean hasVideoCallCapabilities(DialerCall call) {
roldenburg6bd612f2018-01-18 12:57:19 -0800511 return call.getVideoTech().isAvailable(context, call.getAccountHandle());
Eric Erfanianccca3152017-02-22 16:32:36 -0800512 }
513
514 /**
515 * Determines if downgrading from a video call to an audio-only call is supported. In order to
516 * support downgrade to audio, the SDK version must be >= N and the call should NOT have the
517 * {@link android.telecom.Call.Details#CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO}.
518 *
519 * @param call The call.
520 * @return {@code true} if downgrading to an audio-only call from a video call is supported.
521 */
522 private boolean isDowngradeToAudioSupported(DialerCall call) {
Eric Erfanian938468d2017-10-24 14:05:52 -0700523 // TODO(a bug): If there is an RCS video share session, return true here
Eric Erfanianccca3152017-02-22 16:32:36 -0800524 return !call.can(CallCompat.Details.CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO);
525 }
526
527 @Override
Sekine Yasuakia7020842018-05-31 17:10:12 +0900528 public void onSaveInstanceState(Bundle outState) {}
Eric Erfanianccca3152017-02-22 16:32:36 -0800529
530 @Override
Sekine Yasuakia7020842018-05-31 17:10:12 +0900531 public void onRestoreInstanceState(Bundle savedInstanceState) {}
Eric Erfanianccca3152017-02-22 16:32:36 -0800532
533 @Override
534 public void onCameraPermissionGranted() {
linyuh183cb712017-12-27 17:02:37 -0800535 if (call != null) {
536 updateButtonsState(call);
Eric Erfanianccca3152017-02-22 16:32:36 -0800537 }
538 }
539
540 @Override
541 public void onActiveCameraSelectionChanged(boolean isUsingFrontFacingCamera) {
linyuh183cb712017-12-27 17:02:37 -0800542 if (inCallButtonUi == null) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800543 return;
544 }
linyuh183cb712017-12-27 17:02:37 -0800545 inCallButtonUi.setCameraSwitched(!isUsingFrontFacingCamera);
Eric Erfanianccca3152017-02-22 16:32:36 -0800546 }
547
548 @Override
549 public Context getContext() {
linyuh183cb712017-12-27 17:02:37 -0800550 return context;
Eric Erfanianccca3152017-02-22 16:32:36 -0800551 }
552
553 private InCallActivity getActivity() {
linyuh183cb712017-12-27 17:02:37 -0800554 if (inCallButtonUi != null) {
555 Fragment fragment = inCallButtonUi.getInCallButtonUiFragment();
Eric Erfanianccca3152017-02-22 16:32:36 -0800556 if (fragment != null) {
557 return (InCallActivity) fragment.getActivity();
558 }
559 }
560 return null;
561 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800562}