1 /*
2  * Copyright (C) 2014 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 android.telecom;
18 
19 import android.annotation.NonNull;
20 import android.bluetooth.BluetoothDevice;
21 import android.net.Uri;
22 import android.os.Binder;
23 import android.os.Bundle;
24 import android.os.OutcomeReceiver;
25 import android.os.RemoteException;
26 import android.os.ResultReceiver;
27 
28 import com.android.internal.telecom.IInCallAdapter;
29 
30 import java.util.List;
31 import java.util.concurrent.Executor;
32 
33 /**
34  * Receives commands from {@link InCallService} implementations which should be executed by
35  * Telecom. When Telecom binds to a {@link InCallService}, an instance of this class is given to
36  * the in-call service through which it can manipulate live (active, dialing, ringing) calls. When
37  * the in-call service is notified of new calls, it can use the
38  * given call IDs to execute commands such as {@link #answerCall} for incoming calls or
39  * {@link #disconnectCall} for active calls the user would like to end. Some commands are only
40  * appropriate for calls in certain states; please consult each method for such limitations.
41  * <p>
42  * The adapter will stop functioning when there are no more calls.
43  *
44  * @hide
45  */
46 public final class InCallAdapter {
47     private final IInCallAdapter mAdapter;
48 
49     /**
50      * {@hide}
51      */
InCallAdapter(IInCallAdapter adapter)52     public InCallAdapter(IInCallAdapter adapter) {
53         mAdapter = adapter;
54     }
55 
56     /**
57      * Instructs Telecom to answer the specified call.
58      *
59      * @param callId The identifier of the call to answer.
60      * @param videoState The video state in which to answer the call.
61      */
answerCall(String callId, int videoState)62     public void answerCall(String callId, int videoState) {
63         try {
64             mAdapter.answerCall(callId, videoState);
65         } catch (RemoteException e) {
66         }
67     }
68 
69     /**
70      * Instructs Telecom to deflect the specified call.
71      *
72      * @param callId The identifier of the call to deflect.
73      * @param address The address to deflect.
74      */
deflectCall(String callId, Uri address)75     public void deflectCall(String callId, Uri address) {
76         try {
77             mAdapter.deflectCall(callId, address);
78         } catch (RemoteException e) {
79         }
80     }
81 
82     /**
83      * Instructs Telecom to reject the specified call.
84      *
85      * @param callId The identifier of the call to reject.
86      * @param rejectWithMessage Whether to reject with a text message.
87      * @param textMessage An optional text message with which to respond.
88      */
rejectCall(String callId, boolean rejectWithMessage, String textMessage)89     public void rejectCall(String callId, boolean rejectWithMessage, String textMessage) {
90         try {
91             mAdapter.rejectCall(callId, rejectWithMessage, textMessage);
92         } catch (RemoteException e) {
93         }
94     }
95 
96     /**
97      * Instructs Telecom to reject the specified call.
98      *
99      * @param callId The identifier of the call to reject.
100      * @param rejectReason The reason the call was rejected.
101      */
rejectCall(String callId, @Call.RejectReason int rejectReason)102     public void rejectCall(String callId, @Call.RejectReason int rejectReason) {
103         try {
104             mAdapter.rejectCallWithReason(callId, rejectReason);
105         } catch (RemoteException e) {
106         }
107     }
108 
109     /**
110      * Instructs Telecom to transfer the specified call.
111      *
112      * @param callId The identifier of the call to transfer.
113      * @param targetNumber The address to transfer to.
114      * @param isConfirmationRequired if {@code true} it will initiate a confirmed transfer,
115      * if {@code false}, it will initiate unconfirmed transfer.
116      */
transferCall(@onNull String callId, @NonNull Uri targetNumber, boolean isConfirmationRequired)117     public void transferCall(@NonNull String callId, @NonNull Uri targetNumber,
118             boolean isConfirmationRequired) {
119         try {
120             mAdapter.transferCall(callId, targetNumber, isConfirmationRequired);
121         } catch (RemoteException e) {
122         }
123     }
124 
125     /**
126      * Instructs Telecom to transfer the specified call to another ongoing call.
127      *
128      * @param callId The identifier of the call to transfer.
129      * @param otherCallId The identifier of the other call to which this will be transferred.
130      */
transferCall(@onNull String callId, @NonNull String otherCallId)131     public void transferCall(@NonNull String callId, @NonNull String otherCallId) {
132         try {
133             mAdapter.consultativeTransfer(callId, otherCallId);
134         } catch (RemoteException e) {
135         }
136     }
137 
138     /**
139      * Instructs Telecom to disconnect the specified call.
140      *
141      * @param callId The identifier of the call to disconnect.
142      */
disconnectCall(String callId)143     public void disconnectCall(String callId) {
144         try {
145             mAdapter.disconnectCall(callId);
146         } catch (RemoteException e) {
147         }
148     }
149 
150     /**
151      * Instructs Telecom to put the specified call on hold.
152      *
153      * @param callId The identifier of the call to put on hold.
154      */
holdCall(String callId)155     public void holdCall(String callId) {
156         try {
157             mAdapter.holdCall(callId);
158         } catch (RemoteException e) {
159         }
160     }
161 
162     /**
163      * Instructs Telecom to release the specified call from hold.
164      *
165      * @param callId The identifier of the call to release from hold.
166      */
unholdCall(String callId)167     public void unholdCall(String callId) {
168         try {
169             mAdapter.unholdCall(callId);
170         } catch (RemoteException e) {
171         }
172     }
173 
174     /**
175      * Mute the microphone.
176      *
177      * @param shouldMute True if the microphone should be muted.
178      */
mute(boolean shouldMute)179     public void mute(boolean shouldMute) {
180         try {
181             mAdapter.mute(shouldMute);
182         } catch (RemoteException e) {
183         }
184     }
185 
186     /**
187      * Sets the audio route (speaker, bluetooth, etc...). See {@link CallAudioState}.
188      *
189      * @param route The audio route to use.
190      */
setAudioRoute(int route)191     public void setAudioRoute(int route) {
192         try {
193             mAdapter.setAudioRoute(route, null);
194         } catch (RemoteException e) {
195         }
196     }
197 
198     /**
199      * @see Call#enterBackgroundAudioProcessing()
200      */
enterBackgroundAudioProcessing(String callId)201     public void enterBackgroundAudioProcessing(String callId) {
202         try {
203             mAdapter.enterBackgroundAudioProcessing(callId);
204         } catch (RemoteException e) {
205         }
206     }
207 
208     /**
209      * @see Call#exitBackgroundAudioProcessing(boolean)
210      */
exitBackgroundAudioProcessing(String callId, boolean shouldRing)211     public void exitBackgroundAudioProcessing(String callId, boolean shouldRing) {
212         try {
213             mAdapter.exitBackgroundAudioProcessing(callId, shouldRing);
214         } catch (RemoteException e) {
215         }
216     }
217 
218     /**
219      * Request audio routing to a specific bluetooth device. Calling this method may result in
220      * the device routing audio to a different bluetooth device than the one specified. A list of
221      * available devices can be obtained via {@link CallAudioState#getSupportedBluetoothDevices()}
222      *
223      * @param bluetoothAddress The address of the bluetooth device to connect to, as returned by
224      * {@link BluetoothDevice#getAddress()}, or {@code null} if no device is preferred.
225      */
requestBluetoothAudio(String bluetoothAddress)226     public void requestBluetoothAudio(String bluetoothAddress) {
227         try {
228             mAdapter.setAudioRoute(CallAudioState.ROUTE_BLUETOOTH, bluetoothAddress);
229         } catch (RemoteException e) {
230         }
231     }
232 
233     /**
234      * Request audio routing to a specific CallEndpoint.. See {@link CallEndpoint}.
235      *
236      * @param endpoint The call endpoint to use.
237      * @param executor The executor of where the callback will execute.
238      * @param callback The callback to notify the result of the endpoint change.
239      */
requestCallEndpointChange(CallEndpoint endpoint, Executor executor, OutcomeReceiver<Void, CallEndpointException> callback)240     public void requestCallEndpointChange(CallEndpoint endpoint, Executor executor,
241             OutcomeReceiver<Void, CallEndpointException> callback) {
242         try {
243             mAdapter.requestCallEndpointChange(endpoint, new ResultReceiver(null) {
244                 @Override
245                 protected void onReceiveResult(int resultCode, Bundle result) {
246                     super.onReceiveResult(resultCode, result);
247                     final long identity = Binder.clearCallingIdentity();
248                     try {
249                         if (resultCode == CallEndpoint.ENDPOINT_OPERATION_SUCCESS) {
250                             executor.execute(() -> callback.onResult(null));
251                         } else {
252                             executor.execute(() -> callback.onError(
253                                     result.getParcelable(CallEndpointException.CHANGE_ERROR,
254                                             CallEndpointException.class)));
255                         }
256                     } finally {
257                         Binder.restoreCallingIdentity(identity);
258                     }
259                 }
260             });
261         } catch (RemoteException e) {
262             Log.d(this, "Remote exception calling requestCallEndpointChange");
263         }
264     }
265 
266     /**
267      * Instructs Telecom to play a dual-tone multi-frequency signaling (DTMF) tone in a call.
268      *
269      * Any other currently playing DTMF tone in the specified call is immediately stopped.
270      *
271      * @param callId The unique ID of the call in which the tone will be played.
272      * @param digit A character representing the DTMF digit for which to play the tone. This
273      *         value must be one of {@code '0'} through {@code '9'}, {@code '*'} or {@code '#'}.
274      */
playDtmfTone(String callId, char digit)275     public void playDtmfTone(String callId, char digit) {
276         try {
277             mAdapter.playDtmfTone(callId, digit);
278         } catch (RemoteException e) {
279         }
280     }
281 
282     /**
283      * Instructs Telecom to stop any dual-tone multi-frequency signaling (DTMF) tone currently
284      * playing.
285      *
286      * DTMF tones are played by calling {@link #playDtmfTone(String,char)}. If no DTMF tone is
287      * currently playing, this method will do nothing.
288      *
289      * @param callId The unique ID of the call in which any currently playing tone will be stopped.
290      */
stopDtmfTone(String callId)291     public void stopDtmfTone(String callId) {
292         try {
293             mAdapter.stopDtmfTone(callId);
294         } catch (RemoteException e) {
295         }
296     }
297 
298     /**
299      * Instructs Telecom to continue playing a post-dial DTMF string.
300      *
301      * A post-dial DTMF string is a string of digits entered after a phone number, when dialed,
302      * that are immediately sent as DTMF tones to the recipient as soon as the connection is made.
303      * While these tones are playing, Telecom will notify the {@link InCallService} that the call
304      * is in the post dial state.
305      *
306      * If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_PAUSE} symbol, Telecom
307      * will temporarily pause playing the tones for a pre-defined period of time.
308      *
309      * If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_WAIT} symbol, Telecom
310      * will pause playing the tones and notify the {@link InCallService} that the call is in the
311      * post dial wait state. When the user decides to continue the postdial sequence, the
312      * {@link InCallService} should invoke the {@link #postDialContinue(String,boolean)} method.
313      *
314      * @param callId The unique ID of the call for which postdial string playing should continue.
315      * @param proceed Whether or not to continue with the post-dial sequence.
316      */
postDialContinue(String callId, boolean proceed)317     public void postDialContinue(String callId, boolean proceed) {
318         try {
319             mAdapter.postDialContinue(callId, proceed);
320         } catch (RemoteException e) {
321         }
322     }
323 
324     /**
325      * Instructs Telecom to add a PhoneAccountHandle to the specified call.
326      *
327      * @param callId The identifier of the call.
328      * @param accountHandle The PhoneAccountHandle through which to place the call.
329      * @param setDefault {@code True} if this account should be set as the default for calls.
330      */
phoneAccountSelected(String callId, PhoneAccountHandle accountHandle, boolean setDefault)331     public void phoneAccountSelected(String callId, PhoneAccountHandle accountHandle,
332             boolean setDefault) {
333         try {
334             mAdapter.phoneAccountSelected(callId, accountHandle, setDefault);
335         } catch (RemoteException e) {
336         }
337     }
338 
339     /**
340      * Instructs Telecom to conference the specified call.
341      *
342      * @param callId The unique ID of the call.
343      * @hide
344      */
conference(String callId, String otherCallId)345     public void conference(String callId, String otherCallId) {
346         try {
347             mAdapter.conference(callId, otherCallId);
348         } catch (RemoteException ignored) {
349         }
350     }
351 
352     /**
353      * Instructs Telecom to pull participants to existing call
354      *
355      * @param callId The unique ID of the call.
356      * @param participants participants to be pulled to existing call.
357      */
addConferenceParticipants(String callId, List<Uri> participants)358     public void addConferenceParticipants(String callId, List<Uri> participants) {
359         try {
360             mAdapter.addConferenceParticipants(callId, participants);
361         } catch (RemoteException ignored) {
362         }
363     }
364 
365 
366     /**
367      * Instructs Telecom to split the specified call from any conference call with which it may be
368      * connected.
369      *
370      * @param callId The unique ID of the call.
371      * @hide
372      */
splitFromConference(String callId)373     public void splitFromConference(String callId) {
374         try {
375             mAdapter.splitFromConference(callId);
376         } catch (RemoteException ignored) {
377         }
378     }
379 
380     /**
381      * Instructs Telecom to merge child calls of the specified conference call.
382      */
mergeConference(String callId)383     public void mergeConference(String callId) {
384         try {
385             mAdapter.mergeConference(callId);
386         } catch (RemoteException ignored) {
387         }
388     }
389 
390     /**
391      * Instructs Telecom to swap the child calls of the specified conference call.
392      */
swapConference(String callId)393     public void swapConference(String callId) {
394         try {
395             mAdapter.swapConference(callId);
396         } catch (RemoteException ignored) {
397         }
398     }
399 
400     /**
401      * Instructs Telecom to pull an external call to the local device.
402      *
403      * @param callId The callId to pull.
404      */
pullExternalCall(String callId)405     public void pullExternalCall(String callId) {
406         try {
407             mAdapter.pullExternalCall(callId);
408         } catch (RemoteException ignored) {
409         }
410     }
411 
412     /**
413      * Intructs Telecom to send a call event.
414      *
415      * @param callId The callId to send the event for.
416      * @param event The event.
417      * @param targetSdkVer Target sdk version of the app calling this api
418      * @param extras Extras associated with the event.
419      */
sendCallEvent(String callId, String event, int targetSdkVer, Bundle extras)420     public void sendCallEvent(String callId, String event, int targetSdkVer, Bundle extras) {
421         try {
422             mAdapter.sendCallEvent(callId, event, targetSdkVer, extras);
423         } catch (RemoteException ignored) {
424         }
425     }
426 
427     /**
428      * Intructs Telecom to add extras to a call.
429      *
430      * @param callId The callId to add the extras to.
431      * @param extras The extras.
432      */
putExtras(String callId, Bundle extras)433     public void putExtras(String callId, Bundle extras) {
434         try {
435             mAdapter.putExtras(callId, extras);
436         } catch (RemoteException ignored) {
437         }
438     }
439 
440     /**
441      * Intructs Telecom to add an extra to a call.
442      *
443      * @param callId The callId to add the extras to.
444      * @param key The extra key.
445      * @param value The extra value.
446      */
putExtra(String callId, String key, boolean value)447     public void putExtra(String callId, String key, boolean value) {
448         try {
449             Bundle bundle = new Bundle();
450             bundle.putBoolean(key, value);
451             mAdapter.putExtras(callId, bundle);
452         } catch (RemoteException ignored) {
453         }
454     }
455 
456     /**
457      * Intructs Telecom to add an extra to a call.
458      *
459      * @param callId The callId to add the extras to.
460      * @param key The extra key.
461      * @param value The extra value.
462      */
putExtra(String callId, String key, int value)463     public void putExtra(String callId, String key, int value) {
464         try {
465             Bundle bundle = new Bundle();
466             bundle.putInt(key, value);
467             mAdapter.putExtras(callId, bundle);
468         } catch (RemoteException ignored) {
469         }
470     }
471 
472     /**
473      * Intructs Telecom to add an extra to a call.
474      *
475      * @param callId The callId to add the extras to.
476      * @param key The extra key.
477      * @param value The extra value.
478      */
putExtra(String callId, String key, String value)479     public void putExtra(String callId, String key, String value) {
480         try {
481             Bundle bundle = new Bundle();
482             bundle.putString(key, value);
483             mAdapter.putExtras(callId, bundle);
484         } catch (RemoteException ignored) {
485         }
486     }
487 
488     /**
489      * Intructs Telecom to remove extras from a call.
490      * @param callId The callId to remove the extras from.
491      * @param keys The extra keys to remove.
492      */
removeExtras(String callId, List<String> keys)493     public void removeExtras(String callId, List<String> keys) {
494         try {
495             mAdapter.removeExtras(callId, keys);
496         } catch (RemoteException ignored) {
497         }
498     }
499 
500     /**
501      * Instructs Telecom to turn the proximity sensor on.
502      */
turnProximitySensorOn()503     public void turnProximitySensorOn() {
504         try {
505             mAdapter.turnOnProximitySensor();
506         } catch (RemoteException ignored) {
507         }
508     }
509 
510     /**
511      * Instructs Telecom to turn the proximity sensor off.
512      *
513      * @param screenOnImmediately If true, the screen will be turned on immediately if it was
514      * previously off. Otherwise, the screen will only be turned on after the proximity sensor
515      * is no longer triggered.
516      */
turnProximitySensorOff(boolean screenOnImmediately)517     public void turnProximitySensorOff(boolean screenOnImmediately) {
518         try {
519             mAdapter.turnOffProximitySensor(screenOnImmediately);
520         } catch (RemoteException ignored) {
521         }
522     }
523 
524     /**
525      * Sends an RTT upgrade request to the remote end of the connection.
526      */
sendRttRequest(String callId)527     public void sendRttRequest(String callId) {
528         try {
529             mAdapter.sendRttRequest(callId);
530         } catch (RemoteException ignored) {
531         }
532     }
533 
534     /**
535      * Responds to an RTT upgrade request initiated from the remote end.
536      *
537      * @param id the ID of the request as specified by Telecom
538      * @param accept Whether the request should be accepted.
539      */
respondToRttRequest(String callId, int id, boolean accept)540     public void respondToRttRequest(String callId, int id, boolean accept) {
541         try {
542             mAdapter.respondToRttRequest(callId, id, accept);
543         } catch (RemoteException ignored) {
544         }
545     }
546 
547     /**
548      * Instructs Telecom to shut down the RTT communication channel.
549      */
stopRtt(String callId)550     public void stopRtt(String callId) {
551         try {
552             mAdapter.stopRtt(callId);
553         } catch (RemoteException ignored) {
554         }
555     }
556 
557     /**
558      * Sets the RTT audio mode.
559      * @param mode the desired RTT audio mode
560      */
setRttMode(String callId, int mode)561     public void setRttMode(String callId, int mode) {
562         try {
563             mAdapter.setRttMode(callId, mode);
564         } catch (RemoteException ignored) {
565         }
566     }
567 
568 
569     /**
570      * Initiates a handover of this {@link Call} to the {@link ConnectionService} identified
571      * by destAcct.
572      * @param callId The callId of the Call which calls this function.
573      * @param destAcct ConnectionService to which the call should be handed over.
574      * @param videoState The video state desired after the handover.
575      * @param extras Extra information to be passed to ConnectionService
576      */
handoverTo(String callId, PhoneAccountHandle destAcct, int videoState, Bundle extras)577     public void handoverTo(String callId, PhoneAccountHandle destAcct, int videoState,
578                            Bundle extras) {
579         try {
580             mAdapter.handoverTo(callId, destAcct, videoState, extras);
581         } catch (RemoteException ignored) {
582         }
583     }
584 }
585