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
17package com.android.server.telecom;
18
19import android.os.Binder;
20import android.os.Bundle;
21import android.telecom.Log;
22import android.telecom.PhoneAccountHandle;
23
24import com.android.internal.telecom.IInCallAdapter;
25
26import java.util.List;
27
28/**
29 * Receives call commands and updates from in-call app and passes them through to CallsManager.
30 * {@link InCallController} creates an instance of this class and passes it to the in-call app after
31 * binding to it. This adapter can receive commands and updates until the in-call app is unbound.
32 */
33class InCallAdapter extends IInCallAdapter.Stub {
34    private final CallsManager mCallsManager;
35    private final CallIdMapper mCallIdMapper;
36    private final TelecomSystem.SyncRoot mLock;
37    private final String mOwnerComponentName;
38
39    /** Persists the specified parameters. */
40    public InCallAdapter(CallsManager callsManager, CallIdMapper callIdMapper,
41            TelecomSystem.SyncRoot lock, String ownerComponentName) {
42        mCallsManager = callsManager;
43        mCallIdMapper = callIdMapper;
44        mLock = lock;
45        mOwnerComponentName = ownerComponentName;
46    }
47
48    @Override
49    public void answerCall(String callId, int videoState) {
50        try {
51            Log.startSession(LogUtils.Sessions.ICA_ANSWER_CALL, mOwnerComponentName);
52            long token = Binder.clearCallingIdentity();
53            try {
54                synchronized (mLock) {
55                    Log.d(this, "answerCall(%s,%d)", callId, videoState);
56                    Call call = mCallIdMapper.getCall(callId);
57                    if (call != null) {
58                        mCallsManager.answerCall(call, videoState);
59                    } else {
60                        Log.w(this, "answerCall, unknown call id: %s", callId);
61                    }
62                }
63            } finally {
64                Binder.restoreCallingIdentity(token);
65            }
66        } finally {
67            Log.endSession();
68        }
69    }
70
71    @Override
72    public void rejectCall(String callId, boolean rejectWithMessage, String textMessage) {
73        try {
74            Log.startSession(LogUtils.Sessions.ICA_REJECT_CALL, mOwnerComponentName);
75            long token = Binder.clearCallingIdentity();
76            try {
77                synchronized (mLock) {
78                    Log.d(this, "rejectCall(%s,%b,%s)", callId, rejectWithMessage, textMessage);
79                    Call call = mCallIdMapper.getCall(callId);
80                    if (call != null) {
81                        mCallsManager.rejectCall(call, rejectWithMessage, textMessage);
82                    } else {
83                        Log.w(this, "setRingback, unknown call id: %s", callId);
84                    }
85                }
86            } finally {
87                Binder.restoreCallingIdentity(token);
88            }
89        } finally {
90            Log.endSession();
91        }
92    }
93
94    @Override
95    public void playDtmfTone(String callId, char digit) {
96        try {
97            Log.startSession("ICA.pDT", mOwnerComponentName);
98            long token = Binder.clearCallingIdentity();
99            try {
100                synchronized (mLock) {
101                    Log.d(this, "playDtmfTone(%s,%c)", callId, digit);
102                    Call call = mCallIdMapper.getCall(callId);
103                    if (call != null) {
104                        mCallsManager.playDtmfTone(call, digit);
105                    } else {
106                        Log.w(this, "playDtmfTone, unknown call id: %s", callId);
107                    }
108                }
109            } finally {
110                Binder.restoreCallingIdentity(token);
111            }
112        } finally {
113            Log.endSession();
114        }
115    }
116
117    @Override
118    public void stopDtmfTone(String callId) {
119        try {
120            Log.startSession("ICA.sDT", mOwnerComponentName);
121            long token = Binder.clearCallingIdentity();
122            try {
123                synchronized (mLock) {
124                    Log.d(this, "stopDtmfTone(%s)", callId);
125                    Call call = mCallIdMapper.getCall(callId);
126                    if (call != null) {
127                        mCallsManager.stopDtmfTone(call);
128                    } else {
129                        Log.w(this, "stopDtmfTone, unknown call id: %s", callId);
130                    }
131                }
132            } finally {
133                Binder.restoreCallingIdentity(token);
134            }
135        } finally {
136            Log.endSession();
137        }
138    }
139
140    @Override
141    public void postDialContinue(String callId, boolean proceed) {
142        try {
143            Log.startSession("ICA.pDC", mOwnerComponentName);
144            long token = Binder.clearCallingIdentity();
145            try {
146                synchronized (mLock) {
147                    Log.d(this, "postDialContinue(%s)", callId);
148                    Call call = mCallIdMapper.getCall(callId);
149                    if (call != null) {
150                        mCallsManager.postDialContinue(call, proceed);
151                    } else {
152                        Log.w(this, "postDialContinue, unknown call id: %s", callId);
153                    }
154                }
155            } finally {
156                Binder.restoreCallingIdentity(token);
157            }
158        } finally {
159            Log.endSession();
160        }
161    }
162
163    @Override
164    public void disconnectCall(String callId) {
165        try {
166            Log.startSession(LogUtils.Sessions.ICA_DISCONNECT_CALL, mOwnerComponentName);
167            long token = Binder.clearCallingIdentity();
168            try {
169                synchronized (mLock) {
170                    Log.v(this, "disconnectCall: %s", callId);
171                    Call call = mCallIdMapper.getCall(callId);
172                    if (call != null) {
173                        mCallsManager.disconnectCall(call);
174                    } else {
175                        Log.w(this, "disconnectCall, unknown call id: %s", callId);
176                    }
177                }
178            } finally {
179                Binder.restoreCallingIdentity(token);
180            }
181        } finally {
182            Log.endSession();
183        }
184    }
185
186    @Override
187    public void holdCall(String callId) {
188        try {
189            Log.startSession(LogUtils.Sessions.ICA_HOLD_CALL, mOwnerComponentName);
190            long token = Binder.clearCallingIdentity();
191            try {
192                synchronized (mLock) {
193                    Call call = mCallIdMapper.getCall(callId);
194                    if (call != null) {
195                        mCallsManager.holdCall(call);
196                    } else {
197                        Log.w(this, "holdCall, unknown call id: %s", callId);
198                    }
199                }
200            } finally {
201                Binder.restoreCallingIdentity(token);
202            }
203        } finally {
204            Log.endSession();
205        }
206    }
207
208    @Override
209    public void unholdCall(String callId) {
210        try {
211            Log.startSession(LogUtils.Sessions.ICA_UNHOLD_CALL, mOwnerComponentName);
212            long token = Binder.clearCallingIdentity();
213            try {
214                synchronized (mLock) {
215                    Call call = mCallIdMapper.getCall(callId);
216                    if (call != null) {
217                        mCallsManager.unholdCall(call);
218                    } else {
219                        Log.w(this, "unholdCall, unknown call id: %s", callId);
220                    }
221                }
222            } finally {
223                Binder.restoreCallingIdentity(token);
224            }
225        } finally {
226            Log.endSession();
227        }
228    }
229
230    @Override
231    public void phoneAccountSelected(String callId, PhoneAccountHandle accountHandle,
232            boolean setDefault) {
233        try {
234            Log.startSession("ICA.pAS", mOwnerComponentName);
235            long token = Binder.clearCallingIdentity();
236            try {
237                synchronized (mLock) {
238                    Call call = mCallIdMapper.getCall(callId);
239                    if (call != null) {
240                        mCallsManager.phoneAccountSelected(call, accountHandle, setDefault);
241                    } else {
242                        Log.w(this, "phoneAccountSelected, unknown call id: %s", callId);
243                    }
244                }
245            } finally {
246                Binder.restoreCallingIdentity(token);
247            }
248        } finally {
249            Log.endSession();
250        }
251    }
252
253    @Override
254    public void mute(boolean shouldMute) {
255        try {
256            Log.startSession(LogUtils.Sessions.ICA_MUTE, mOwnerComponentName);
257            long token = Binder.clearCallingIdentity();
258            try {
259                synchronized (mLock) {
260                    mCallsManager.mute(shouldMute);
261                }
262            } finally {
263                Binder.restoreCallingIdentity(token);
264            }
265        } finally {
266            Log.endSession();
267        }
268    }
269
270    @Override
271    public void setAudioRoute(int route) {
272        try {
273            Log.startSession(LogUtils.Sessions.ICA_SET_AUDIO_ROUTE, mOwnerComponentName);
274            long token = Binder.clearCallingIdentity();
275            try {
276                synchronized (mLock) {
277                    mCallsManager.setAudioRoute(route);
278                }
279            } finally {
280                Binder.restoreCallingIdentity(token);
281            }
282        } finally {
283            Log.endSession();
284        }
285    }
286
287    @Override
288    public void conference(String callId, String otherCallId) {
289        try {
290            Log.startSession(LogUtils.Sessions.ICA_CONFERENCE, mOwnerComponentName);
291            long token = Binder.clearCallingIdentity();
292            try {
293                synchronized (mLock) {
294                    Call call = mCallIdMapper.getCall(callId);
295                    Call otherCall = mCallIdMapper.getCall(otherCallId);
296                    if (call != null && otherCall != null) {
297                        mCallsManager.conference(call, otherCall);
298                    } else {
299                        Log.w(this, "conference, unknown call id: %s or %s", callId, otherCallId);
300                    }
301                }
302            } finally {
303                Binder.restoreCallingIdentity(token);
304            }
305        } finally {
306            Log.endSession();
307        }
308    }
309
310    @Override
311    public void splitFromConference(String callId) {
312        try {
313            Log.startSession("ICA.sFC", mOwnerComponentName);
314            long token = Binder.clearCallingIdentity();
315            try {
316                synchronized (mLock) {
317                    Call call = mCallIdMapper.getCall(callId);
318                    if (call != null) {
319                        call.splitFromConference();
320                    } else {
321                        Log.w(this, "splitFromConference, unknown call id: %s", callId);
322                    }
323                }
324            } finally {
325                Binder.restoreCallingIdentity(token);
326            }
327        } finally {
328            Log.endSession();
329        }
330    }
331
332    @Override
333    public void mergeConference(String callId) {
334        try {
335            Log.startSession("ICA.mC", mOwnerComponentName);
336            long token = Binder.clearCallingIdentity();
337            try {
338                synchronized (mLock) {
339                    Call call = mCallIdMapper.getCall(callId);
340                    if (call != null) {
341                        call.mergeConference();
342                    } else {
343                        Log.w(this, "mergeConference, unknown call id: %s", callId);
344                    }
345                }
346            } finally {
347                Binder.restoreCallingIdentity(token);
348            }
349        } finally {
350            Log.endSession();
351        }
352    }
353
354    @Override
355    public void swapConference(String callId) {
356        try {
357            Log.startSession("ICA.sC", mOwnerComponentName);
358            long token = Binder.clearCallingIdentity();
359            try {
360                synchronized (mLock) {
361                    Call call = mCallIdMapper.getCall(callId);
362                    if (call != null) {
363                        call.swapConference();
364                    } else {
365                        Log.w(this, "swapConference, unknown call id: %s", callId);
366                    }
367                }
368            } finally {
369                Binder.restoreCallingIdentity(token);
370            }
371        } finally {
372            Log.endSession();
373        }
374    }
375
376    @Override
377    public void pullExternalCall(String callId) {
378        try {
379            Log.startSession("ICA.pEC", mOwnerComponentName);
380            long token = Binder.clearCallingIdentity();
381            try {
382                synchronized (mLock) {
383                    Call call = mCallIdMapper.getCall(callId);
384                    if (call != null) {
385                        call.pullExternalCall();
386                    } else {
387                        Log.w(this, "pullExternalCall, unknown call id: %s", callId);
388                    }
389                }
390            } finally {
391                Binder.restoreCallingIdentity(token);
392            }
393        } finally {
394            Log.endSession();
395        }
396    }
397
398    @Override
399    public void sendCallEvent(String callId, String event, Bundle extras) {
400        try {
401            Log.startSession("ICA.sCE", mOwnerComponentName);
402            long token = Binder.clearCallingIdentity();
403            try {
404                synchronized (mLock) {
405                    Call call = mCallIdMapper.getCall(callId);
406                    if (call != null) {
407                        call.sendCallEvent(event, extras);
408                    } else {
409                        Log.w(this, "sendCallEvent, unknown call id: %s", callId);
410                    }
411                }
412            } finally {
413                Binder.restoreCallingIdentity(token);
414            }
415        } finally {
416            Log.endSession();
417        }
418    }
419
420    @Override
421    public void putExtras(String callId, Bundle extras) {
422        try {
423            Log.startSession("ICA.pE", mOwnerComponentName);
424            long token = Binder.clearCallingIdentity();
425            try {
426                synchronized (mLock) {
427                    Call call = mCallIdMapper.getCall(callId);
428                    if (call != null) {
429                        call.putExtras(Call.SOURCE_INCALL_SERVICE, extras);
430                    } else {
431                        Log.w(this, "putExtras, unknown call id: %s", callId);
432                    }
433                }
434            } finally {
435                Binder.restoreCallingIdentity(token);
436            }
437        } finally {
438            Log.endSession();
439        }
440    }
441
442    @Override
443    public void removeExtras(String callId, List<String> keys) {
444        try {
445            Log.startSession("ICA.rE", mOwnerComponentName);
446            long token = Binder.clearCallingIdentity();
447            try {
448                synchronized (mLock) {
449                    Call call = mCallIdMapper.getCall(callId);
450                    if (call != null) {
451                        call.removeExtras(Call.SOURCE_INCALL_SERVICE, keys);
452                    } else {
453                        Log.w(this, "removeExtra, unknown call id: %s", callId);
454                    }
455                }
456            } finally {
457                Binder.restoreCallingIdentity(token);
458            }
459        } finally {
460            Log.endSession();
461        }
462    }
463
464    @Override
465    public void turnOnProximitySensor() {
466        try {
467            Log.startSession("ICA.tOnPS", mOwnerComponentName);
468            long token = Binder.clearCallingIdentity();
469            try {
470                synchronized (mLock) {
471                    mCallsManager.turnOnProximitySensor();
472                }
473            } finally {
474                Binder.restoreCallingIdentity(token);
475            }
476        } finally {
477            Log.endSession();
478        }
479    }
480
481    @Override
482    public void turnOffProximitySensor(boolean screenOnImmediately) {
483        try {
484            Log.startSession("ICA.tOffPS", mOwnerComponentName);
485            long token = Binder.clearCallingIdentity();
486            try {
487                synchronized (mLock) {
488                    mCallsManager.turnOffProximitySensor(screenOnImmediately);
489                }
490            } finally {
491                Binder.restoreCallingIdentity(token);
492            }
493        } finally {
494             Log.endSession();
495        }
496    }
497
498    @Override
499    public void sendRttRequest(String callId) {
500        try {
501            Log.startSession("ICA.sRR");
502            long token = Binder.clearCallingIdentity();
503            try {
504                synchronized (mLock) {
505                    Call call = mCallIdMapper.getCall(callId);
506                    if (call != null) {
507                        call.sendRttRequest();
508                    } else {
509                        Log.w(this, "stopRtt(): call %s not found", callId);
510                    }
511                }
512            } finally {
513                Binder.restoreCallingIdentity(token);
514            }
515        } finally {
516            Log.endSession();
517        }
518    }
519
520    @Override
521    public void respondToRttRequest(String callId, int id, boolean accept) {
522        try {
523            Log.startSession("ICA.rTRR");
524            long token = Binder.clearCallingIdentity();
525            try {
526                synchronized (mLock) {
527                    Call call = mCallIdMapper.getCall(callId);
528                    if (call != null) {
529                        call.handleRttRequestResponse(id, accept);
530                    } else {
531                        Log.w(this, "respondToRttRequest(): call %s not found", callId);
532                    }
533                }
534            } finally {
535                Binder.restoreCallingIdentity(token);
536            }
537        } finally {
538            Log.endSession();
539        }
540    }
541
542    @Override
543    public void stopRtt(String callId) {
544        try {
545            Log.startSession("ICA.sRTT");
546            long token = Binder.clearCallingIdentity();
547            try {
548                synchronized (mLock) {
549                    Call call = mCallIdMapper.getCall(callId);
550                    if (call != null) {
551                        call.stopRtt();
552                    } else {
553                        Log.w(this, "stopRtt(): call %s not found", callId);
554                    }
555                }
556            } finally {
557                Binder.restoreCallingIdentity(token);
558            }
559        } finally {
560            Log.endSession();
561        }
562    }
563
564    @Override
565    public void setRttMode(String callId, int mode) {
566        try {
567            Log.startSession("ICA.sRM");
568            long token = Binder.clearCallingIdentity();
569            try {
570                synchronized (mLock) {
571                    // TODO
572                }
573            } finally {
574                Binder.restoreCallingIdentity(token);
575            }
576        } finally {
577            Log.endSession();
578        }
579    }
580}
581