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 com.android.server.telecom;
18 
19 import android.net.Uri;
20 import android.os.Binder;
21 import android.os.Bundle;
22 import android.telecom.Log;
23 import android.telecom.PhoneAccountHandle;
24 
25 import com.android.internal.telecom.IInCallAdapter;
26 
27 import java.util.List;
28 
29 /**
30  * Receives call commands and updates from in-call app and passes them through to CallsManager.
31  * {@link InCallController} creates an instance of this class and passes it to the in-call app after
32  * binding to it. This adapter can receive commands and updates until the in-call app is unbound.
33  */
34 class InCallAdapter extends IInCallAdapter.Stub {
35     private final CallsManager mCallsManager;
36     private final CallIdMapper mCallIdMapper;
37     private final TelecomSystem.SyncRoot mLock;
38     private final String mOwnerPackageName;
39     private final String mOwnerPackageAbbreviation;
40 
41     /** Persists the specified parameters. */
InCallAdapter(CallsManager callsManager, CallIdMapper callIdMapper, TelecomSystem.SyncRoot lock, String ownerPackageName)42     public InCallAdapter(CallsManager callsManager, CallIdMapper callIdMapper,
43             TelecomSystem.SyncRoot lock, String ownerPackageName) {
44         mCallsManager = callsManager;
45         mCallIdMapper = callIdMapper;
46         mLock = lock;
47         mOwnerPackageName = ownerPackageName;
48         mOwnerPackageAbbreviation = Log.getPackageAbbreviation(ownerPackageName);
49     }
50 
51     @Override
answerCall(String callId, int videoState)52     public void answerCall(String callId, int videoState) {
53         try {
54             Log.startSession(LogUtils.Sessions.ICA_ANSWER_CALL, mOwnerPackageAbbreviation);
55             long token = Binder.clearCallingIdentity();
56             try {
57                 synchronized (mLock) {
58                     Log.d(this, "answerCall(%s,%d)", callId, videoState);
59                     Call call = mCallIdMapper.getCall(callId);
60                     if (call != null) {
61                         mCallsManager.answerCall(call, videoState);
62                     } else {
63                         Log.w(this, "answerCall, unknown call id: %s", callId);
64                     }
65                 }
66             } finally {
67                 Binder.restoreCallingIdentity(token);
68             }
69         } finally {
70             Log.endSession();
71         }
72     }
73 
74     @Override
deflectCall(String callId, Uri address)75     public void deflectCall(String callId, Uri address) {
76         try {
77             Log.startSession(LogUtils.Sessions.ICA_DEFLECT_CALL, mOwnerPackageAbbreviation);
78             long token = Binder.clearCallingIdentity();
79             try {
80                 synchronized (mLock) {
81                     Log.i(this, "deflectCall - %s, %s ", callId, Log.pii(address));
82                     Call call = mCallIdMapper.getCall(callId);
83                     if (call != null) {
84                         mCallsManager.deflectCall(call, address);
85                     } else {
86                         Log.w(this, "deflectCall, unknown call id: %s", callId);
87                     }
88                 }
89             } finally {
90                 Binder.restoreCallingIdentity(token);
91             }
92         } finally {
93             Log.endSession();
94         }
95     }
96 
97     @Override
rejectCall(String callId, boolean rejectWithMessage, String textMessage)98     public void rejectCall(String callId, boolean rejectWithMessage, String textMessage) {
99         try {
100             Log.startSession(LogUtils.Sessions.ICA_REJECT_CALL, mOwnerPackageAbbreviation);
101 
102             int callingUid = Binder.getCallingUid();
103             long token = Binder.clearCallingIdentity();
104             try {
105                 synchronized (mLock) {
106                     // Check to make sure the in-call app's user isn't restricted from sending SMS.
107                     // If so, silently drop the outgoing message. Also drop message if the screen is
108                     // locked.
109                     if (!mCallsManager.isReplyWithSmsAllowed(callingUid)) {
110                         rejectWithMessage = false;
111                         textMessage = null;
112                     }
113 
114                     Log.d(this, "rejectCall(%s,%b,%s)", callId, rejectWithMessage, textMessage);
115                     Call call = mCallIdMapper.getCall(callId);
116                     if (call != null) {
117                         mCallsManager.rejectCall(call, rejectWithMessage, textMessage);
118                     } else {
119                         Log.w(this, "setRingback, unknown call id: %s", callId);
120                     }
121                 }
122             } finally {
123                 Binder.restoreCallingIdentity(token);
124             }
125         } finally {
126             Log.endSession();
127         }
128     }
129 
130     @Override
rejectCallWithReason(String callId, @android.telecom.Call.RejectReason int rejectReason)131     public void rejectCallWithReason(String callId,
132             @android.telecom.Call.RejectReason int rejectReason) {
133         try {
134             Log.startSession(LogUtils.Sessions.ICA_REJECT_CALL, mOwnerPackageAbbreviation);
135 
136             int callingUid = Binder.getCallingUid();
137             long token = Binder.clearCallingIdentity();
138             try {
139                 synchronized (mLock) {
140                     Log.d(this, "rejectCallWithReason(%s,%d)", callId, rejectReason);
141                     Call call = mCallIdMapper.getCall(callId);
142                     if (call != null) {
143                         mCallsManager.rejectCall(call, rejectReason);
144                     } else {
145                         Log.w(this, "rejectCallWithReason, unknown call id: %s", callId);
146                     }
147                 }
148             } finally {
149                 Binder.restoreCallingIdentity(token);
150             }
151         } finally {
152             Log.endSession();
153         }
154     }
155 
transferCall(String callId, Uri targetNumber, boolean isConfirmationRequired)156     public void transferCall(String callId, Uri targetNumber, boolean isConfirmationRequired) {
157         try {
158             Log.startSession(LogUtils.Sessions.ICA_TRANSFER_CALL, mOwnerPackageAbbreviation);
159             long token = Binder.clearCallingIdentity();
160             try {
161                 synchronized (mLock) {
162                     Log.i(this, "transferCall - %s, %s, %b", callId, Log.pii(targetNumber),
163                             isConfirmationRequired);
164                     Call call = mCallIdMapper.getCall(callId);
165                     if (call != null) {
166                         mCallsManager.transferCall(call, targetNumber, isConfirmationRequired);
167                     } else {
168                         Log.w(this, "transferCall, unknown call id: %s", callId);
169                     }
170                 }
171             } finally {
172                 Binder.restoreCallingIdentity(token);
173             }
174         } finally {
175             Log.endSession();
176         }
177     }
178 
179     @Override
consultativeTransfer(String callId, String otherCallId)180     public void consultativeTransfer(String callId, String otherCallId) {
181         try {
182             Log.startSession(LogUtils.Sessions.ICA_CONSULTATIVE_TRANSFER,
183                     mOwnerPackageAbbreviation);
184             long token = Binder.clearCallingIdentity();
185             try {
186                 synchronized (mLock) {
187                     Log.i(this, "consultativeTransfer - %s, %s", callId, otherCallId);
188                     Call call = mCallIdMapper.getCall(callId);
189                     Call otherCall = mCallIdMapper.getCall(otherCallId);
190                     if (call != null && otherCall != null) {
191                         mCallsManager.transferCall(call, otherCall);
192                     } else {
193                         Log.w(this, "consultativeTransfer, unknown call id: %s or %s",
194                                 callId, otherCallId);
195                     }
196                 }
197             } finally {
198                 Binder.restoreCallingIdentity(token);
199             }
200         } finally {
201             Log.endSession();
202         }
203     }
204 
205     @Override
playDtmfTone(String callId, char digit)206     public void playDtmfTone(String callId, char digit) {
207         try {
208             Log.startSession("ICA.pDT", mOwnerPackageAbbreviation);
209             long token = Binder.clearCallingIdentity();
210             try {
211                 synchronized (mLock) {
212                     Log.d(this, "playDtmfTone(%s,%c)", callId, digit);
213                     Call call = mCallIdMapper.getCall(callId);
214                     if (call != null) {
215                         mCallsManager.playDtmfTone(call, digit);
216                     } else {
217                         Log.w(this, "playDtmfTone, unknown call id: %s", callId);
218                     }
219                 }
220             } finally {
221                 Binder.restoreCallingIdentity(token);
222             }
223         } finally {
224             Log.endSession();
225         }
226     }
227 
228     @Override
stopDtmfTone(String callId)229     public void stopDtmfTone(String callId) {
230         try {
231             Log.startSession("ICA.sDT", mOwnerPackageAbbreviation);
232             long token = Binder.clearCallingIdentity();
233             try {
234                 synchronized (mLock) {
235                     Log.d(this, "stopDtmfTone(%s)", callId);
236                     Call call = mCallIdMapper.getCall(callId);
237                     if (call != null) {
238                         mCallsManager.stopDtmfTone(call);
239                     } else {
240                         Log.w(this, "stopDtmfTone, unknown call id: %s", callId);
241                     }
242                 }
243             } finally {
244                 Binder.restoreCallingIdentity(token);
245             }
246         } finally {
247             Log.endSession();
248         }
249     }
250 
251     @Override
postDialContinue(String callId, boolean proceed)252     public void postDialContinue(String callId, boolean proceed) {
253         try {
254             Log.startSession("ICA.pDC", mOwnerPackageAbbreviation);
255             long token = Binder.clearCallingIdentity();
256             try {
257                 synchronized (mLock) {
258                     Log.d(this, "postDialContinue(%s)", callId);
259                     Call call = mCallIdMapper.getCall(callId);
260                     if (call != null) {
261                         mCallsManager.postDialContinue(call, proceed);
262                     } else {
263                         Log.w(this, "postDialContinue, unknown call id: %s", callId);
264                     }
265                 }
266             } finally {
267                 Binder.restoreCallingIdentity(token);
268             }
269         } finally {
270             Log.endSession();
271         }
272     }
273 
274     @Override
disconnectCall(String callId)275     public void disconnectCall(String callId) {
276         try {
277             Log.startSession(LogUtils.Sessions.ICA_DISCONNECT_CALL, mOwnerPackageAbbreviation);
278             long token = Binder.clearCallingIdentity();
279             try {
280                 synchronized (mLock) {
281                     Log.v(this, "disconnectCall: %s", callId);
282                     Call call = mCallIdMapper.getCall(callId);
283                     if (call != null) {
284                         mCallsManager.disconnectCall(call);
285                     } else {
286                         Log.w(this, "disconnectCall, unknown call id: %s", callId);
287                     }
288                 }
289             } finally {
290                 Binder.restoreCallingIdentity(token);
291             }
292         } finally {
293             Log.endSession();
294         }
295     }
296 
297     @Override
holdCall(String callId)298     public void holdCall(String callId) {
299         try {
300             Log.startSession(LogUtils.Sessions.ICA_HOLD_CALL, mOwnerPackageAbbreviation);
301             long token = Binder.clearCallingIdentity();
302             try {
303                 synchronized (mLock) {
304                     Call call = mCallIdMapper.getCall(callId);
305                     if (call != null) {
306                         mCallsManager.holdCall(call);
307                     } else {
308                         Log.w(this, "holdCall, unknown call id: %s", callId);
309                     }
310                 }
311             } finally {
312                 Binder.restoreCallingIdentity(token);
313             }
314         } finally {
315             Log.endSession();
316         }
317     }
318 
319     @Override
unholdCall(String callId)320     public void unholdCall(String callId) {
321         try {
322             Log.startSession(LogUtils.Sessions.ICA_UNHOLD_CALL, mOwnerPackageAbbreviation);
323             long token = Binder.clearCallingIdentity();
324             try {
325                 synchronized (mLock) {
326                     Call call = mCallIdMapper.getCall(callId);
327                     if (call != null) {
328                         mCallsManager.unholdCall(call);
329                     } else {
330                         Log.w(this, "unholdCall, unknown call id: %s", callId);
331                     }
332                 }
333             } finally {
334                 Binder.restoreCallingIdentity(token);
335             }
336         } finally {
337             Log.endSession();
338         }
339     }
340 
341     @Override
phoneAccountSelected(String callId, PhoneAccountHandle accountHandle, boolean setDefault)342     public void phoneAccountSelected(String callId, PhoneAccountHandle accountHandle,
343             boolean setDefault) {
344         try {
345             Log.startSession("ICA.pAS", mOwnerPackageAbbreviation);
346             long token = Binder.clearCallingIdentity();
347             try {
348                 synchronized (mLock) {
349                     Call call = mCallIdMapper.getCall(callId);
350                     if (call != null) {
351                         mCallsManager.phoneAccountSelected(call, accountHandle, setDefault);
352                     } else {
353                         Log.w(this, "phoneAccountSelected, unknown call id: %s", callId);
354                     }
355                 }
356             } finally {
357                 Binder.restoreCallingIdentity(token);
358             }
359         } finally {
360             Log.endSession();
361         }
362     }
363 
364     @Override
mute(boolean shouldMute)365     public void mute(boolean shouldMute) {
366         try {
367             Log.startSession(LogUtils.Sessions.ICA_MUTE, mOwnerPackageAbbreviation);
368             long token = Binder.clearCallingIdentity();
369             try {
370                 synchronized (mLock) {
371                     mCallsManager.mute(shouldMute);
372                 }
373             } finally {
374                 Binder.restoreCallingIdentity(token);
375             }
376         } finally {
377             Log.endSession();
378         }
379     }
380 
381     @Override
setAudioRoute(int route, String bluetoothAddress)382     public void setAudioRoute(int route, String bluetoothAddress) {
383         try {
384             Log.startSession(LogUtils.Sessions.ICA_SET_AUDIO_ROUTE, mOwnerPackageAbbreviation);
385             long token = Binder.clearCallingIdentity();
386             try {
387                 synchronized (mLock) {
388                     mCallsManager.setAudioRoute(route, bluetoothAddress);
389                 }
390             } finally {
391                 Binder.restoreCallingIdentity(token);
392             }
393         } finally {
394             Log.endSession();
395         }
396     }
397 
398     @Override
enterBackgroundAudioProcessing(String callId)399     public void enterBackgroundAudioProcessing(String callId) {
400         try {
401             Log.startSession(LogUtils.Sessions.ICA_ENTER_AUDIO_PROCESSING,
402                     mOwnerPackageAbbreviation);
403             // TODO: enforce the extra permission.
404             Binder.withCleanCallingIdentity(() -> {
405                 synchronized (mLock) {
406                     Call call = mCallIdMapper.getCall(callId);
407                     if (call != null) {
408                         mCallsManager.enterBackgroundAudioProcessing(call, mOwnerPackageName);
409                     } else {
410                         Log.w(this, "enterBackgroundAudioProcessing, unknown call id: %s", callId);
411                     }
412                 }
413             });
414         } finally {
415             Log.endSession();
416         }
417     }
418 
419     @Override
exitBackgroundAudioProcessing(String callId, boolean shouldRing)420     public void exitBackgroundAudioProcessing(String callId, boolean shouldRing) {
421         try {
422             Log.startSession(LogUtils.Sessions.ICA_EXIT_AUDIO_PROCESSING,
423                     mOwnerPackageAbbreviation);
424             Binder.withCleanCallingIdentity(() -> {
425                 synchronized (mLock) {
426                     Call call = mCallIdMapper.getCall(callId);
427                     if (call != null) {
428                         mCallsManager.exitBackgroundAudioProcessing(call, shouldRing);
429                     } else {
430                         Log.w(InCallAdapter.this,
431                                 "exitBackgroundAudioProcessing, unknown call id: %s", callId);
432                     }
433                 }
434             });
435         } finally {
436             Log.endSession();
437         }
438     }
439 
440     @Override
conference(String callId, String otherCallId)441     public void conference(String callId, String otherCallId) {
442         try {
443             Log.startSession(LogUtils.Sessions.ICA_CONFERENCE, mOwnerPackageAbbreviation);
444             long token = Binder.clearCallingIdentity();
445             try {
446                 synchronized (mLock) {
447                     Call call = mCallIdMapper.getCall(callId);
448                     Call otherCall = mCallIdMapper.getCall(otherCallId);
449                     if (call != null && otherCall != null) {
450                         mCallsManager.conference(call, otherCall);
451                     } else {
452                         Log.w(this, "conference, unknown call id: %s or %s", callId, otherCallId);
453                     }
454                 }
455             } finally {
456                 Binder.restoreCallingIdentity(token);
457             }
458         } finally {
459             Log.endSession();
460         }
461     }
462 
463     @Override
splitFromConference(String callId)464     public void splitFromConference(String callId) {
465         try {
466             Log.startSession("ICA.sFC", mOwnerPackageAbbreviation);
467             long token = Binder.clearCallingIdentity();
468             try {
469                 synchronized (mLock) {
470                     Call call = mCallIdMapper.getCall(callId);
471                     if (call != null) {
472                         call.splitFromConference();
473                     } else {
474                         Log.w(this, "splitFromConference, unknown call id: %s", callId);
475                     }
476                 }
477             } finally {
478                 Binder.restoreCallingIdentity(token);
479             }
480         } finally {
481             Log.endSession();
482         }
483     }
484 
485     @Override
mergeConference(String callId)486     public void mergeConference(String callId) {
487         try {
488             Log.startSession("ICA.mC", mOwnerPackageAbbreviation);
489             long token = Binder.clearCallingIdentity();
490             try {
491                 synchronized (mLock) {
492                     Call call = mCallIdMapper.getCall(callId);
493                     if (call != null) {
494                         call.mergeConference();
495                     } else {
496                         Log.w(this, "mergeConference, unknown call id: %s", callId);
497                     }
498                 }
499             } finally {
500                 Binder.restoreCallingIdentity(token);
501             }
502         } finally {
503             Log.endSession();
504         }
505     }
506 
507     @Override
swapConference(String callId)508     public void swapConference(String callId) {
509         try {
510             Log.startSession("ICA.sC", mOwnerPackageAbbreviation);
511             long token = Binder.clearCallingIdentity();
512             try {
513                 synchronized (mLock) {
514                     Call call = mCallIdMapper.getCall(callId);
515                     if (call != null) {
516                         call.swapConference();
517                     } else {
518                         Log.w(this, "swapConference, unknown call id: %s", callId);
519                     }
520                 }
521             } finally {
522                 Binder.restoreCallingIdentity(token);
523             }
524         } finally {
525             Log.endSession();
526         }
527     }
528 
529     @Override
addConferenceParticipants(String callId, List<Uri> participants)530     public void addConferenceParticipants(String callId, List<Uri> participants) {
531         try {
532             Log.startSession("ICA.aCP", mOwnerPackageAbbreviation);
533             long token = Binder.clearCallingIdentity();
534             try {
535                 synchronized (mLock) {
536                     Call call = mCallIdMapper.getCall(callId);
537                     if (call != null) {
538                         call.addConferenceParticipants(participants);
539                     } else {
540                         Log.w(this, "addConferenceParticipants, unknown call id: %s", callId);
541                     }
542                 }
543             } finally {
544                 Binder.restoreCallingIdentity(token);
545             }
546         } finally {
547             Log.endSession();
548         }
549     }
550 
551 
552     @Override
pullExternalCall(String callId)553     public void pullExternalCall(String callId) {
554         try {
555             Log.startSession("ICA.pEC", mOwnerPackageAbbreviation);
556             long token = Binder.clearCallingIdentity();
557             try {
558                 synchronized (mLock) {
559                     Call call = mCallIdMapper.getCall(callId);
560                     if (call != null) {
561                         call.pullExternalCall();
562                     } else {
563                         Log.w(this, "pullExternalCall, unknown call id: %s", callId);
564                     }
565                 }
566             } finally {
567                 Binder.restoreCallingIdentity(token);
568             }
569         } finally {
570             Log.endSession();
571         }
572     }
573 
574     @Override
sendCallEvent(String callId, String event, int targetSdkVer, Bundle extras)575     public void sendCallEvent(String callId, String event, int targetSdkVer, Bundle extras) {
576         try {
577             Log.startSession("ICA.sCE", mOwnerPackageAbbreviation);
578             long token = Binder.clearCallingIdentity();
579             try {
580                 synchronized (mLock) {
581                     Call call = mCallIdMapper.getCall(callId);
582                     if (call != null) {
583                         call.sendCallEvent(event, targetSdkVer, extras);
584                     } else {
585                         Log.w(this, "sendCallEvent, unknown call id: %s", callId);
586                     }
587                 }
588             } finally {
589                 Binder.restoreCallingIdentity(token);
590             }
591         } finally {
592             Log.endSession();
593         }
594     }
595 
596     @Override
putExtras(String callId, Bundle extras)597     public void putExtras(String callId, Bundle extras) {
598         try {
599             Log.startSession("ICA.pE", mOwnerPackageAbbreviation);
600             long token = Binder.clearCallingIdentity();
601             try {
602                 synchronized (mLock) {
603                     Call call = mCallIdMapper.getCall(callId);
604                     if (call != null) {
605                         call.putExtras(Call.SOURCE_INCALL_SERVICE, extras);
606                     } else {
607                         Log.w(this, "putExtras, unknown call id: %s", callId);
608                     }
609                 }
610             } finally {
611                 Binder.restoreCallingIdentity(token);
612             }
613         } finally {
614             Log.endSession();
615         }
616     }
617 
618     @Override
removeExtras(String callId, List<String> keys)619     public void removeExtras(String callId, List<String> keys) {
620         try {
621             Log.startSession("ICA.rE", mOwnerPackageAbbreviation);
622             long token = Binder.clearCallingIdentity();
623             try {
624                 synchronized (mLock) {
625                     Call call = mCallIdMapper.getCall(callId);
626                     if (call != null) {
627                         call.removeExtras(Call.SOURCE_INCALL_SERVICE, keys);
628                     } else {
629                         Log.w(this, "removeExtra, unknown call id: %s", callId);
630                     }
631                 }
632             } finally {
633                 Binder.restoreCallingIdentity(token);
634             }
635         } finally {
636             Log.endSession();
637         }
638     }
639 
640     @Override
turnOnProximitySensor()641     public void turnOnProximitySensor() {
642         try {
643             Log.startSession("ICA.tOnPS", mOwnerPackageAbbreviation);
644             long token = Binder.clearCallingIdentity();
645             try {
646                 synchronized (mLock) {
647                     mCallsManager.turnOnProximitySensor();
648                 }
649             } finally {
650                 Binder.restoreCallingIdentity(token);
651             }
652         } finally {
653             Log.endSession();
654         }
655     }
656 
657     @Override
turnOffProximitySensor(boolean screenOnImmediately)658     public void turnOffProximitySensor(boolean screenOnImmediately) {
659         try {
660             Log.startSession("ICA.tOffPS", mOwnerPackageAbbreviation);
661             long token = Binder.clearCallingIdentity();
662             try {
663                 synchronized (mLock) {
664                     mCallsManager.turnOffProximitySensor(screenOnImmediately);
665                 }
666             } finally {
667                 Binder.restoreCallingIdentity(token);
668             }
669         } finally {
670              Log.endSession();
671         }
672     }
673 
674     @Override
sendRttRequest(String callId)675     public void sendRttRequest(String callId) {
676         try {
677             Log.startSession("ICA.sRR");
678             long token = Binder.clearCallingIdentity();
679             try {
680                 synchronized (mLock) {
681                     Call call = mCallIdMapper.getCall(callId);
682                     if (call != null) {
683                         call.sendRttRequest();
684                     } else {
685                         Log.w(this, "stopRtt(): call %s not found", callId);
686                     }
687                 }
688             } finally {
689                 Binder.restoreCallingIdentity(token);
690             }
691         } finally {
692             Log.endSession();
693         }
694     }
695 
696     @Override
respondToRttRequest(String callId, int id, boolean accept)697     public void respondToRttRequest(String callId, int id, boolean accept) {
698         try {
699             Log.startSession("ICA.rTRR");
700             long token = Binder.clearCallingIdentity();
701             try {
702                 synchronized (mLock) {
703                     Call call = mCallIdMapper.getCall(callId);
704                     if (call != null) {
705                         call.handleRttRequestResponse(id, accept);
706                     } else {
707                         Log.w(this, "respondToRttRequest(): call %s not found", callId);
708                     }
709                 }
710             } finally {
711                 Binder.restoreCallingIdentity(token);
712             }
713         } finally {
714             Log.endSession();
715         }
716     }
717 
718     @Override
stopRtt(String callId)719     public void stopRtt(String callId) {
720         try {
721             Log.startSession("ICA.sRTT");
722             long token = Binder.clearCallingIdentity();
723             try {
724                 synchronized (mLock) {
725                     Call call = mCallIdMapper.getCall(callId);
726                     if (call != null) {
727                         call.stopRtt();
728                     } else {
729                         Log.w(this, "stopRtt(): call %s not found", callId);
730                     }
731                 }
732             } finally {
733                 Binder.restoreCallingIdentity(token);
734             }
735         } finally {
736             Log.endSession();
737         }
738     }
739 
740     @Override
setRttMode(String callId, int mode)741     public void setRttMode(String callId, int mode) {
742         try {
743             Log.startSession("ICA.sRM");
744             long token = Binder.clearCallingIdentity();
745             try {
746                 synchronized (mLock) {
747                     // TODO
748                 }
749             } finally {
750                 Binder.restoreCallingIdentity(token);
751             }
752         } finally {
753             Log.endSession();
754         }
755     }
756 
757     @Override
handoverTo(String callId, PhoneAccountHandle destAcct, int videoState, Bundle extras)758     public void handoverTo(String callId, PhoneAccountHandle destAcct, int videoState,
759                            Bundle extras) {
760         try {
761             Log.startSession("ICA.hT", mOwnerPackageAbbreviation);
762             long token = Binder.clearCallingIdentity();
763             try {
764                 synchronized (mLock) {
765                     Call call = mCallIdMapper.getCall(callId);
766                     if (call != null) {
767                         call.handoverTo(destAcct, videoState, extras);
768                     } else {
769                         Log.w(this, "handoverTo, unknown call id: %s", callId);
770                     }
771                 }
772             } finally {
773                 Binder.restoreCallingIdentity(token);
774             }
775         } finally {
776             Log.endSession();
777         }
778     }
779 }
780