blob: 1e1abf283af8761985024244eefea6b4f3bdf791 [file] [log] [blame]
Thomas Stuart9bfb2432022-09-27 15:02:07 -07001/*
2 * Copyright (C) 2022 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 android.telecom;
18
19import static android.telecom.CallException.TRANSACTION_EXCEPTION_KEY;
20
21import android.annotation.CallbackExecutor;
Thomas Stuartfc93e932023-12-19 10:57:06 -080022import android.annotation.FlaggedApi;
Thomas Stuart9bfb2432022-09-27 15:02:07 -070023import android.annotation.NonNull;
Thomas Stuart73a8b872023-01-10 16:21:51 -080024import android.annotation.SuppressLint;
Thomas Stuart9bfb2432022-09-27 15:02:07 -070025import android.os.Binder;
26import android.os.Bundle;
27import android.os.OutcomeReceiver;
28import android.os.ParcelUuid;
29import android.os.RemoteException;
30import android.os.ResultReceiver;
Thomas Stuartc2427a72023-01-27 17:11:02 -080031import android.text.TextUtils;
Thomas Stuart9bfb2432022-09-27 15:02:07 -070032
Thomas Stuart9bfb2432022-09-27 15:02:07 -070033import com.android.internal.telecom.ICallControl;
Thomas Stuartfc93e932023-12-19 10:57:06 -080034import com.android.server.telecom.flags.Flags;
Thomas Stuart9bfb2432022-09-27 15:02:07 -070035
Thomas Stuart7aeccde2022-12-21 14:47:21 -080036import java.util.List;
37import java.util.Objects;
Thomas Stuart9bfb2432022-09-27 15:02:07 -070038import java.util.concurrent.Executor;
39
40/**
41 * CallControl provides client side control of a call. Each Call will get an individual CallControl
Thomas Stuart15eb61b2024-08-28 18:30:18 +000042 * instance in which the client can alter the state of the associated call. Outgoing and incoming
43 * calls should move to active (via {@link CallControl#setActive(Executor, OutcomeReceiver)} or
44 * answered (via {@link CallControl#answer(int, Executor, OutcomeReceiver)} before 60 seconds. If
45 * the new call is not moved to active or answered before 60 seconds, the call will be disconnected.
Thomas Stuart9bfb2432022-09-27 15:02:07 -070046 *
47 * <p>
48 * Each method is Transactional meaning that it can succeed or fail. If a transaction succeeds,
49 * the {@link OutcomeReceiver#onResult} will be called by Telecom. Otherwise, the
50 * {@link OutcomeReceiver#onError} is called and provides a {@link CallException} that details why
51 * the operation failed.
52 */
Thomas Stuart73a8b872023-01-10 16:21:51 -080053@SuppressLint("NotCloseable")
54public final class CallControl {
Thomas Stuart9bfb2432022-09-27 15:02:07 -070055 private static final String TAG = CallControl.class.getSimpleName();
Thomas Stuart9bfb2432022-09-27 15:02:07 -070056 private final String mCallId;
57 private final ICallControl mServerInterface;
Thomas Stuart9bfb2432022-09-27 15:02:07 -070058
59 /** @hide */
Thomas Stuart0bc7c582024-01-19 17:02:53 -080060 public CallControl(@NonNull String callId, @NonNull ICallControl serverInterface) {
Thomas Stuart9bfb2432022-09-27 15:02:07 -070061 mCallId = callId;
62 mServerInterface = serverInterface;
Thomas Stuart9bfb2432022-09-27 15:02:07 -070063 }
64
65 /**
66 * @return the callId Telecom assigned to this CallControl object which should be attached to
Thomas Stuartc2427a72023-01-27 17:11:02 -080067 * an individual call.
Thomas Stuart9bfb2432022-09-27 15:02:07 -070068 */
69 @NonNull
70 public ParcelUuid getCallId() {
71 return ParcelUuid.fromString(mCallId);
72 }
73
74 /**
Thomas Stuartb4153492023-02-07 13:30:37 -080075 * Request Telecom set the call state to active. This method should be called when either an
76 * outgoing call is ready to go active or a held call is ready to go active again. For incoming
77 * calls that are ready to be answered, use
78 * {@link CallControl#answer(int, Executor, OutcomeReceiver)}.
Thomas Stuart9bfb2432022-09-27 15:02:07 -070079 *
80 * @param executor The {@link Executor} on which the {@link OutcomeReceiver} callback
Thomas Stuartc2427a72023-01-27 17:11:02 -080081 * will be called on.
Thomas Stuart9bfb2432022-09-27 15:02:07 -070082 * @param callback that will be completed on the Telecom side that details success or failure
Thomas Stuartc2427a72023-01-27 17:11:02 -080083 * of the requested operation.
Thomas Stuart9bfb2432022-09-27 15:02:07 -070084 *
85 * {@link OutcomeReceiver#onResult} will be called if Telecom has successfully
86 * switched the call state to active
87 *
88 * {@link OutcomeReceiver#onError} will be called if Telecom has failed to set
89 * the call state to active. A {@link CallException} will be passed
90 * that details why the operation failed.
91 */
92 public void setActive(@CallbackExecutor @NonNull Executor executor,
93 @NonNull OutcomeReceiver<Void, CallException> callback) {
Thomas Stuart0bc7c582024-01-19 17:02:53 -080094 Objects.requireNonNull(executor);
95 Objects.requireNonNull(callback);
96 try {
97 mServerInterface.setActive(mCallId,
98 new CallControlResultReceiver("setActive", executor, callback));
Thomas Stuart9bfb2432022-09-27 15:02:07 -070099
Thomas Stuart0bc7c582024-01-19 17:02:53 -0800100 } catch (RemoteException e) {
101 throw e.rethrowAsRuntimeException();
Thomas Stuart9bfb2432022-09-27 15:02:07 -0700102 }
103 }
104
105 /**
Thomas Stuartb4153492023-02-07 13:30:37 -0800106 * Request Telecom answer an incoming call. For outgoing calls and calls that have been placed
107 * on hold, use {@link CallControl#setActive(Executor, OutcomeReceiver)}.
108 *
109 * @param videoState to report to Telecom. Telecom will store VideoState in the event another
110 * service/device requests it in order to continue the call on another screen.
111 * @param executor The {@link Executor} on which the {@link OutcomeReceiver} callback
112 * will be called on.
113 * @param callback that will be completed on the Telecom side that details success or failure
114 * of the requested operation.
115 *
116 * {@link OutcomeReceiver#onResult} will be called if Telecom has successfully
117 * switched the call state to active
118 *
119 * {@link OutcomeReceiver#onError} will be called if Telecom has failed to set
120 * the call state to active. A {@link CallException} will be passed
121 * that details why the operation failed.
122 */
123 public void answer(@android.telecom.CallAttributes.CallType int videoState,
124 @CallbackExecutor @NonNull Executor executor,
125 @NonNull OutcomeReceiver<Void, CallException> callback) {
126 validateVideoState(videoState);
127 Objects.requireNonNull(executor);
128 Objects.requireNonNull(callback);
Thomas Stuart0bc7c582024-01-19 17:02:53 -0800129 try {
130 mServerInterface.answer(videoState, mCallId,
131 new CallControlResultReceiver("answer", executor, callback));
Thomas Stuartb4153492023-02-07 13:30:37 -0800132
Thomas Stuart0bc7c582024-01-19 17:02:53 -0800133 } catch (RemoteException e) {
134 throw e.rethrowAsRuntimeException();
Thomas Stuartb4153492023-02-07 13:30:37 -0800135 }
136 }
137
138 /**
Thomas Stuart9bfb2432022-09-27 15:02:07 -0700139 * Request Telecom set the call state to inactive. This the same as hold for two call endpoints
140 * but can be extended to setting a meeting to inactive.
141 *
142 * @param executor The {@link Executor} on which the {@link OutcomeReceiver} callback
Thomas Stuartc2427a72023-01-27 17:11:02 -0800143 * will be called on.
Thomas Stuart9bfb2432022-09-27 15:02:07 -0700144 * @param callback that will be completed on the Telecom side that details success or failure
Thomas Stuartc2427a72023-01-27 17:11:02 -0800145 * of the requested operation.
Thomas Stuart9bfb2432022-09-27 15:02:07 -0700146 *
147 * {@link OutcomeReceiver#onResult} will be called if Telecom has successfully
148 * switched the call state to inactive
149 *
150 * {@link OutcomeReceiver#onError} will be called if Telecom has failed to set
151 * the call state to inactive. A {@link CallException} will be passed
152 * that details why the operation failed.
153 */
154 public void setInactive(@CallbackExecutor @NonNull Executor executor,
155 @NonNull OutcomeReceiver<Void, CallException> callback) {
Thomas Stuart0bc7c582024-01-19 17:02:53 -0800156 Objects.requireNonNull(executor);
157 Objects.requireNonNull(callback);
158 try {
159 mServerInterface.setInactive(mCallId,
160 new CallControlResultReceiver("setInactive", executor, callback));
Thomas Stuart9bfb2432022-09-27 15:02:07 -0700161
Thomas Stuart0bc7c582024-01-19 17:02:53 -0800162 } catch (RemoteException e) {
163 throw e.rethrowAsRuntimeException();
Thomas Stuart9bfb2432022-09-27 15:02:07 -0700164 }
165 }
166
167 /**
Thomas Stuartc2427a72023-01-27 17:11:02 -0800168 * Request Telecom disconnect the call and remove the call from telecom tracking.
Thomas Stuart9bfb2432022-09-27 15:02:07 -0700169 *
Thomas Stuartc2427a72023-01-27 17:11:02 -0800170 * @param disconnectCause represents the cause for disconnecting the call. The only valid
171 * codes for the {@link android.telecom.DisconnectCause} passed in are:
172 * <ul>
173 * <li>{@link DisconnectCause#LOCAL}</li>
174 * <li>{@link DisconnectCause#REMOTE}</li>
175 * <li>{@link DisconnectCause#REJECTED}</li>
176 * <li>{@link DisconnectCause#MISSED}</li>
177 * </ul>
Thomas Stuartc2427a72023-01-27 17:11:02 -0800178 * @param executor The {@link Executor} on which the {@link OutcomeReceiver} callback
179 * will be called on.
Thomas Stuartc2427a72023-01-27 17:11:02 -0800180 * @param callback That will be completed on the Telecom side that details success or
181 * failure of the requested operation.
182 *
183 * {@link OutcomeReceiver#onResult} will be called if Telecom has
184 * successfully disconnected the call.
185 *
186 * {@link OutcomeReceiver#onError} will be called if Telecom has failed
187 * to disconnect the call. A {@link CallException} will be passed
188 * that details why the operation failed.
189 *
190 * <p>
191 * Note: After the call has been successfully disconnected, calling any CallControl API will
192 * result in the {@link OutcomeReceiver#onError} with
193 * {@link CallException#CODE_CALL_IS_NOT_BEING_TRACKED}.
Thomas Stuart9bfb2432022-09-27 15:02:07 -0700194 */
195 public void disconnect(@NonNull DisconnectCause disconnectCause,
196 @CallbackExecutor @NonNull Executor executor,
197 @NonNull OutcomeReceiver<Void, CallException> callback) {
Thomas Stuartc2427a72023-01-27 17:11:02 -0800198 Objects.requireNonNull(disconnectCause);
199 Objects.requireNonNull(executor);
200 Objects.requireNonNull(callback);
201 validateDisconnectCause(disconnectCause);
Thomas Stuart0bc7c582024-01-19 17:02:53 -0800202 try {
203 mServerInterface.disconnect(mCallId, disconnectCause,
204 new CallControlResultReceiver("disconnect", executor, callback));
205 } catch (RemoteException e) {
206 throw e.rethrowAsRuntimeException();
Thomas Stuart9bfb2432022-09-27 15:02:07 -0700207 }
208 }
209
210 /**
Grace Jiaef5a4cc2022-12-13 11:08:55 -0800211 * Request start a call streaming session. On receiving valid request, telecom will bind to
Anton Hansson84d6d752023-10-05 09:46:37 +0000212 * the {@code CallStreamingService} implemented by a general call streaming sender. So that the
Grace Jiaef5a4cc2022-12-13 11:08:55 -0800213 * call streaming sender can perform streaming local device audio to another remote device and
214 * control the call during streaming.
215 *
216 * @param executor The {@link Executor} on which the {@link OutcomeReceiver} callback
217 * will be called on.
218 * @param callback that will be completed on the Telecom side that details success or failure
219 * of the requested operation.
220 *
221 * {@link OutcomeReceiver#onResult} will be called if Telecom has successfully
Grace Jiaacd4dad2023-01-17 18:14:36 -0800222 * started the call streaming.
Grace Jiaef5a4cc2022-12-13 11:08:55 -0800223 *
224 * {@link OutcomeReceiver#onError} will be called if Telecom has failed to
Grace Jiaacd4dad2023-01-17 18:14:36 -0800225 * start the call streaming. A {@link CallException} will be passed that
Grace Jiaef5a4cc2022-12-13 11:08:55 -0800226 * details why the operation failed.
227 */
228 public void startCallStreaming(@CallbackExecutor @NonNull Executor executor,
229 @NonNull OutcomeReceiver<Void, CallException> callback) {
Thomas Stuart0bc7c582024-01-19 17:02:53 -0800230 Objects.requireNonNull(executor);
231 Objects.requireNonNull(callback);
232 try {
233 mServerInterface.startCallStreaming(mCallId,
234 new CallControlResultReceiver("startCallStreaming", executor, callback));
235 } catch (RemoteException e) {
236 throw e.rethrowAsRuntimeException();
Grace Jiaef5a4cc2022-12-13 11:08:55 -0800237 }
238 }
239
240 /**
Thomas Stuart7aeccde2022-12-21 14:47:21 -0800241 * Request a CallEndpoint change. Clients should not define their own CallEndpoint when
242 * requesting a change. Instead, the new endpoint should be one of the valid endpoints provided
243 * by {@link CallEventCallback#onAvailableCallEndpointsChanged(List)}.
244 *
Thomas Stuartc2427a72023-01-27 17:11:02 -0800245 * @param callEndpoint The {@link CallEndpoint} to change to.
246 * @param executor The {@link Executor} on which the {@link OutcomeReceiver} callback
Thomas Stuart7aeccde2022-12-21 14:47:21 -0800247 * will be called on.
Thomas Stuartc2427a72023-01-27 17:11:02 -0800248 * @param callback The {@link OutcomeReceiver} that will be completed on the Telecom side
Thomas Stuart7aeccde2022-12-21 14:47:21 -0800249 * that details success or failure of the requested operation.
250 *
251 * {@link OutcomeReceiver#onResult} will be called if Telecom has
252 * successfully changed the CallEndpoint that was requested.
253 *
254 * {@link OutcomeReceiver#onError} will be called if Telecom has failed to
255 * switch to the requested CallEndpoint. A {@link CallException} will be
256 * passed that details why the operation failed.
257 */
258 public void requestCallEndpointChange(@NonNull CallEndpoint callEndpoint,
259 @CallbackExecutor @NonNull Executor executor,
260 @NonNull OutcomeReceiver<Void, CallException> callback) {
261 Objects.requireNonNull(callEndpoint);
262 Objects.requireNonNull(executor);
263 Objects.requireNonNull(callback);
Thomas Stuart0bc7c582024-01-19 17:02:53 -0800264 try {
265 mServerInterface.requestCallEndpointChange(callEndpoint,
266 new CallControlResultReceiver("requestCallEndpointChange", executor, callback));
267 } catch (RemoteException e) {
268 throw e.rethrowAsRuntimeException();
Thomas Stuart7aeccde2022-12-21 14:47:21 -0800269 }
270 }
271
272 /**
Thomas Stuartfc93e932023-12-19 10:57:06 -0800273 * Request a new mute state. Note: {@link CallEventCallback#onMuteStateChanged(boolean)}
274 * will be called every time the mute state is changed and can be used to track the current
275 * mute state.
276 *
277 * @param isMuted The new mute state. Passing in a {@link Boolean#TRUE} for the isMuted
278 * parameter will mute the call. {@link Boolean#FALSE} will unmute the call.
279 * @param executor The {@link Executor} on which the {@link OutcomeReceiver} callback
280 * will be called on.
281 * @param callback The {@link OutcomeReceiver} that will be completed on the Telecom side
282 * that details success or failure of the requested operation.
283 *
284 * {@link OutcomeReceiver#onResult} will be called if Telecom has
285 * successfully changed the mute state.
286 *
287 * {@link OutcomeReceiver#onError} will be called if Telecom has failed to
288 * switch to the mute state. A {@link CallException} will be
289 * passed that details why the operation failed.
290 */
291 @FlaggedApi(Flags.FLAG_SET_MUTE_STATE)
Thomas Stuart0bc7c582024-01-19 17:02:53 -0800292 public void requestMuteState(boolean isMuted, @CallbackExecutor @NonNull Executor executor,
Thomas Stuartfc93e932023-12-19 10:57:06 -0800293 @NonNull OutcomeReceiver<Void, CallException> callback) {
294 Objects.requireNonNull(executor);
295 Objects.requireNonNull(callback);
Thomas Stuart0bc7c582024-01-19 17:02:53 -0800296 try {
297 mServerInterface.setMuteState(isMuted,
298 new CallControlResultReceiver("requestMuteState", executor, callback));
Thomas Stuart0bc7c582024-01-19 17:02:53 -0800299 } catch (RemoteException e) {
300 throw e.rethrowAsRuntimeException();
Thomas Stuartfc93e932023-12-19 10:57:06 -0800301 }
302 }
303
Thomas Stuart26b9bc72024-01-04 15:14:15 -0800304 /**
305 * Request a new video state for the ongoing call. This can only be changed if the application
306 * has registered a {@link PhoneAccount} with the
307 * {@link PhoneAccount#CAPABILITY_SUPPORTS_VIDEO_CALLING} and set the
308 * {@link CallAttributes#SUPPORTS_VIDEO_CALLING} when adding the call via
309 * {@link TelecomManager#addCall(CallAttributes, Executor, OutcomeReceiver,
310 * CallControlCallback, CallEventCallback)}
311 *
312 * @param videoState to report to Telecom. To see the valid argument to pass,
313 * see {@link CallAttributes.CallType}.
314 * @param executor The {@link Executor} on which the {@link OutcomeReceiver} callback
315 * will be called on.
316 * @param callback that will be completed on the Telecom side that details success or failure
317 * of the requested operation.
318 *
319 * {@link OutcomeReceiver#onResult} will be called if Telecom has successfully
320 * switched the video state.
321 *
322 * {@link OutcomeReceiver#onError} will be called if Telecom has failed to set
323 * the new video state. A {@link CallException} will be passed
324 * that details why the operation failed.
325 * @throws IllegalArgumentException if the argument passed for videoState is invalid. To see a
326 * list of valid states, see {@link CallAttributes.CallType}.
327 */
328 @FlaggedApi(Flags.FLAG_TRANSACTIONAL_VIDEO_STATE)
329 public void requestVideoState(@CallAttributes.CallType int videoState,
330 @CallbackExecutor @NonNull Executor executor,
331 @NonNull OutcomeReceiver<Void, CallException> callback) {
332 validateVideoState(videoState);
333 Objects.requireNonNull(executor);
334 Objects.requireNonNull(callback);
335 try {
336 mServerInterface.requestVideoState(videoState, mCallId,
337 new CallControlResultReceiver("requestVideoState", executor, callback));
338 } catch (RemoteException e) {
339 throw e.rethrowAsRuntimeException();
340 }
341 }
342
Thomas Stuartfc93e932023-12-19 10:57:06 -0800343 /**
Thomas Stuart9ace3392023-02-15 15:01:09 -0800344 * Raises an event to the {@link android.telecom.InCallService} implementations tracking this
345 * call via {@link android.telecom.Call.Callback#onConnectionEvent(Call, String, Bundle)}.
Thomas Stuartef584292023-03-02 13:24:46 -0800346 * These events and the associated extra keys for the {@code Bundle} parameter are mutually
347 * defined by a VoIP application and {@link android.telecom.InCallService}. This API is used to
348 * relay additional information about a call other than what is specified in the
349 * {@link android.telecom.CallAttributes} to {@link android.telecom.InCallService}s. This might
350 * include, for example, a change to the list of participants in a meeting, or the name of the
351 * speakers who have their hand raised. Where appropriate, the {@link InCallService}s tracking
352 * this call may choose to render this additional information about the call. An automotive
353 * calling UX, for example may have enough screen real estate to indicate the number of
354 * participants in a meeting, but to prevent distractions could suppress the list of
355 * participants.
Thomas Stuart9ace3392023-02-15 15:01:09 -0800356 *
Thomas Stuartef584292023-03-02 13:24:46 -0800357 * @param event a string event identifier agreed upon between a VoIP application and an
358 * {@link android.telecom.InCallService}
359 * @param extras a {@link android.os.Bundle} containing information about the event, as agreed
360 * upon between a VoIP application and {@link android.telecom.InCallService}.
Thomas Stuart9ace3392023-02-15 15:01:09 -0800361 */
362 public void sendEvent(@NonNull String event, @NonNull Bundle extras) {
363 Objects.requireNonNull(event);
364 Objects.requireNonNull(extras);
Thomas Stuart0bc7c582024-01-19 17:02:53 -0800365 try {
366 mServerInterface.sendEvent(mCallId, event, extras);
367 } catch (RemoteException e) {
368 throw e.rethrowAsRuntimeException();
Thomas Stuart9ace3392023-02-15 15:01:09 -0800369 }
370 }
371
372 /**
Thomas Stuart9bfb2432022-09-27 15:02:07 -0700373 * Since {@link OutcomeReceiver}s cannot be passed via AIDL, a ResultReceiver (which can) must
374 * wrap the Clients {@link OutcomeReceiver} passed in and await for the Telecom Server side
375 * response in {@link ResultReceiver#onReceiveResult(int, Bundle)}.
Thomas Stuartc2427a72023-01-27 17:11:02 -0800376 *
377 * @hide
378 */
Thomas Stuart9bfb2432022-09-27 15:02:07 -0700379 private class CallControlResultReceiver extends ResultReceiver {
380 private final String mCallingMethod;
381 private final Executor mExecutor;
382 private final OutcomeReceiver<Void, CallException> mClientCallback;
383
384 CallControlResultReceiver(String method, Executor executor,
385 OutcomeReceiver<Void, CallException> clientCallback) {
386 super(null);
387 mCallingMethod = method;
388 mExecutor = executor;
389 mClientCallback = clientCallback;
390 }
391
392 @Override
393 protected void onReceiveResult(int resultCode, Bundle resultData) {
394 Log.d(CallControl.TAG, "%s: oRR: resultCode=[%s]", mCallingMethod, resultCode);
395 super.onReceiveResult(resultCode, resultData);
396 final long identity = Binder.clearCallingIdentity();
397 try {
398 if (resultCode == TelecomManager.TELECOM_TRANSACTION_SUCCESS) {
399 mExecutor.execute(() -> mClientCallback.onResult(null));
400 } else {
401 mExecutor.execute(() ->
402 mClientCallback.onError(getTransactionException(resultData)));
403 }
404 } finally {
405 Binder.restoreCallingIdentity(identity);
406 }
407 }
408
409 }
410
411 /** @hide */
412 private CallException getTransactionException(Bundle resultData) {
413 String message = "unknown error";
414 if (resultData != null && resultData.containsKey(TRANSACTION_EXCEPTION_KEY)) {
415 return resultData.getParcelable(TRANSACTION_EXCEPTION_KEY,
416 CallException.class);
417 }
418 return new CallException(message, CallException.CODE_ERROR_UNKNOWN);
419 }
Thomas Stuartc2427a72023-01-27 17:11:02 -0800420
421 /** @hide */
422 private void validateDisconnectCause(DisconnectCause disconnectCause) {
423 final int code = disconnectCause.getCode();
424 if (code != DisconnectCause.LOCAL && code != DisconnectCause.REMOTE
425 && code != DisconnectCause.MISSED && code != DisconnectCause.REJECTED) {
426 throw new IllegalArgumentException(TextUtils.formatSimple(
427 "The DisconnectCause code provided, %d , is not a valid Disconnect code. Valid "
428 + "DisconnectCause codes are limited to [DisconnectCause.LOCAL, "
429 + "DisconnectCause.REMOTE, DisconnectCause.MISSED, or "
430 + "DisconnectCause.REJECTED]", disconnectCause.getCode()));
431 }
432 }
433
Thomas Stuartb4153492023-02-07 13:30:37 -0800434 /** @hide */
435 private void validateVideoState(@android.telecom.CallAttributes.CallType int videoState) {
436 if (videoState != CallAttributes.AUDIO_CALL && videoState != CallAttributes.VIDEO_CALL) {
437 throw new IllegalArgumentException(TextUtils.formatSimple(
438 "The VideoState argument passed in, %d , is not a valid VideoState. The "
439 + "VideoState choices are limited to CallAttributes.AUDIO_CALL or"
440 + "CallAttributes.VIDEO_CALL", videoState));
441 }
442 }
Thomas Stuart9bfb2432022-09-27 15:02:07 -0700443}