1 /*
2  * Copyright 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 static android.Manifest.permission.MODIFY_PHONE_STATE;
20 
21 import android.Manifest;
22 import android.app.AppOpsManager;
23 import android.content.ComponentName;
24 import android.content.Context;
25 import android.content.pm.PackageManager;
26 import android.net.Uri;
27 import android.os.Binder;
28 import android.os.Bundle;
29 import android.os.IBinder;
30 import android.os.ParcelFileDescriptor;
31 import android.os.RemoteException;
32 import android.os.UserHandle;
33 import android.telecom.CallAudioState;
34 import android.telecom.CallScreeningService;
35 import android.telecom.Connection;
36 import android.telecom.ConnectionRequest;
37 import android.telecom.ConnectionService;
38 import android.telecom.DisconnectCause;
39 import android.telecom.GatewayInfo;
40 import android.telecom.Log;
41 import android.telecom.Logging.Session;
42 import android.telecom.ParcelableConference;
43 import android.telecom.ParcelableConnection;
44 import android.telecom.PhoneAccountHandle;
45 import android.telecom.StatusHints;
46 import android.telecom.TelecomManager;
47 import android.telecom.VideoProfile;
48 
49 import com.android.internal.annotations.VisibleForTesting;
50 import com.android.internal.telecom.IConnectionService;
51 import com.android.internal.telecom.IConnectionServiceAdapter;
52 import com.android.internal.telecom.IVideoProvider;
53 import com.android.internal.telecom.RemoteServiceCallback;
54 import com.android.internal.util.Preconditions;
55 
56 import java.util.ArrayList;
57 import java.util.Collections;
58 import java.util.HashMap;
59 import java.util.List;
60 import java.util.Map;
61 import java.util.Set;
62 import java.util.concurrent.ConcurrentHashMap;
63 
64 /**
65  * Wrapper for {@link IConnectionService}s, handles binding to {@link IConnectionService} and keeps
66  * track of when the object can safely be unbound. Other classes should not use
67  * {@link IConnectionService} directly and instead should use this class to invoke methods of
68  * {@link IConnectionService}.
69  */
70 @VisibleForTesting
71 public class ConnectionServiceWrapper extends ServiceBinder implements
72         ConnectionServiceFocusManager.ConnectionServiceFocus {
73 
74     private static final String TELECOM_ABBREVIATION = "cast";
75 
76     private final class Adapter extends IConnectionServiceAdapter.Stub {
77 
78         @Override
handleCreateConnectionComplete(String callId, ConnectionRequest request, ParcelableConnection connection, Session.Info sessionInfo)79         public void handleCreateConnectionComplete(String callId, ConnectionRequest request,
80                 ParcelableConnection connection, Session.Info sessionInfo) {
81             Log.startSession(sessionInfo, LogUtils.Sessions.CSW_HANDLE_CREATE_CONNECTION_COMPLETE,
82                     mPackageAbbreviation);
83             long token = Binder.clearCallingIdentity();
84             try {
85                 synchronized (mLock) {
86                     logIncoming("handleCreateConnectionComplete %s", callId);
87                     ConnectionServiceWrapper.this
88                             .handleCreateConnectionComplete(callId, request, connection);
89 
90                     if (mServiceInterface != null) {
91                         logOutgoing("createConnectionComplete %s", callId);
92                         try {
93                             mServiceInterface.createConnectionComplete(callId,
94                                     Log.getExternalSession());
95                         } catch (RemoteException e) {
96                             logOutgoing("createConnectionComplete remote exception=%s", e);
97                         }
98                     }
99                 }
100             } catch (Throwable t) {
101                 Log.e(ConnectionServiceWrapper.this, t, "");
102                 throw t;
103             } finally {
104                 Binder.restoreCallingIdentity(token);
105                 Log.endSession();
106             }
107         }
108 
109         @Override
handleCreateConferenceComplete(String callId, ConnectionRequest request, ParcelableConference conference, Session.Info sessionInfo)110         public void handleCreateConferenceComplete(String callId, ConnectionRequest request,
111                 ParcelableConference conference, Session.Info sessionInfo) {
112             Log.startSession(sessionInfo, LogUtils.Sessions.CSW_HANDLE_CREATE_CONNECTION_COMPLETE,
113                     mPackageAbbreviation);
114             long token = Binder.clearCallingIdentity();
115             try {
116                 synchronized (mLock) {
117                     logIncoming("handleCreateConferenceComplete %s", callId);
118                     ConnectionServiceWrapper.this
119                             .handleCreateConferenceComplete(callId, request, conference);
120 
121                     if (mServiceInterface != null) {
122                         logOutgoing("createConferenceComplete %s", callId);
123                         try {
124                             mServiceInterface.createConferenceComplete(callId,
125                                     Log.getExternalSession());
126                         } catch (RemoteException e) {
127                         }
128                     }
129                 }
130             } catch (Throwable t) {
131                 Log.e(ConnectionServiceWrapper.this, t, "");
132                 throw t;
133             } finally {
134                 Binder.restoreCallingIdentity(token);
135                 Log.endSession();
136             }
137         }
138 
139 
140         @Override
setActive(String callId, Session.Info sessionInfo)141         public void setActive(String callId, Session.Info sessionInfo) {
142             Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_ACTIVE,
143                     mPackageAbbreviation);
144             long token = Binder.clearCallingIdentity();
145             try {
146                 synchronized (mLock) {
147                     logIncoming("setActive %s", callId);
148                     Call call = mCallIdMapper.getCall(callId);
149                     if (call != null) {
150                         mCallsManager.markCallAsActive(call);
151                     } else {
152                         // Log.w(this, "setActive, unknown call id: %s", msg.obj);
153                     }
154                 }
155             } catch (Throwable t) {
156                 Log.e(ConnectionServiceWrapper.this, t, "");
157                 throw t;
158             } finally {
159                 Binder.restoreCallingIdentity(token);
160                 Log.endSession();
161             }
162         }
163 
164         @Override
setRinging(String callId, Session.Info sessionInfo)165         public void setRinging(String callId, Session.Info sessionInfo) {
166             Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_RINGING, mPackageAbbreviation);
167             long token = Binder.clearCallingIdentity();
168             try {
169                 synchronized (mLock) {
170                     logIncoming("setRinging %s", callId);
171                     Call call = mCallIdMapper.getCall(callId);
172                     if (call != null) {
173                         mCallsManager.markCallAsRinging(call);
174                     } else {
175                         // Log.w(this, "setRinging, unknown call id: %s", msg.obj);
176                     }
177                 }
178             } catch (Throwable t) {
179                 Log.e(ConnectionServiceWrapper.this, t, "");
180                 throw t;
181             } finally {
182                 Binder.restoreCallingIdentity(token);
183                 Log.endSession();
184             }
185         }
186 
187         @Override
resetConnectionTime(String callId, Session.Info sessionInfo)188         public void resetConnectionTime(String callId, Session.Info sessionInfo) {
189             Log.startSession(sessionInfo, "CSW.rCCT", mPackageAbbreviation);
190             long token = Binder.clearCallingIdentity();
191             try {
192                 synchronized (mLock) {
193                     logIncoming("resetConnectionTime %s", callId);
194                     Call call = mCallIdMapper.getCall(callId);
195                     if (call != null) {
196                         mCallsManager.resetConnectionTime(call);
197                     } else {
198                         // Log.w(this, "resetConnectionTime, unknown call id: %s", msg.obj);
199                     }
200                 }
201             } finally {
202                 Binder.restoreCallingIdentity(token);
203                 Log.endSession();
204             }
205         }
206 
207         @Override
setVideoProvider(String callId, IVideoProvider videoProvider, Session.Info sessionInfo)208         public void setVideoProvider(String callId, IVideoProvider videoProvider,
209                 Session.Info sessionInfo) {
210             Log.startSession(sessionInfo, "CSW.sVP", mPackageAbbreviation);
211             long token = Binder.clearCallingIdentity();
212             try {
213                 synchronized (mLock) {
214                     logIncoming("setVideoProvider %s", callId);
215                     Call call = mCallIdMapper.getCall(callId);
216                     if (call != null) {
217                         call.setVideoProvider(videoProvider);
218                     }
219                 }
220             } catch (Throwable t) {
221                 Log.e(ConnectionServiceWrapper.this, t, "");
222                 throw t;
223             } finally {
224                 Binder.restoreCallingIdentity(token);
225                 Log.endSession();
226             }
227         }
228 
229         @Override
setDialing(String callId, Session.Info sessionInfo)230         public void setDialing(String callId, Session.Info sessionInfo) {
231             Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_DIALING, mPackageAbbreviation);
232             long token = Binder.clearCallingIdentity();
233             try {
234                 synchronized (mLock) {
235                     logIncoming("setDialing %s", callId);
236                     Call call = mCallIdMapper.getCall(callId);
237                     if (call != null) {
238                         mCallsManager.markCallAsDialing(call);
239                     } else {
240                         // Log.w(this, "setDialing, unknown call id: %s", msg.obj);
241                     }
242                 }
243             } catch (Throwable t) {
244                 Log.e(ConnectionServiceWrapper.this, t, "");
245                 throw t;
246             } finally {
247                 Binder.restoreCallingIdentity(token);
248                 Log.endSession();
249             }
250         }
251 
252         @Override
setPulling(String callId, Session.Info sessionInfo)253         public void setPulling(String callId, Session.Info sessionInfo) {
254             Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_PULLING, mPackageAbbreviation);
255             long token = Binder.clearCallingIdentity();
256             try {
257                 synchronized (mLock) {
258                     logIncoming("setPulling %s", callId);
259                     Call call = mCallIdMapper.getCall(callId);
260                     if (call != null) {
261                         mCallsManager.markCallAsPulling(call);
262                     }
263                 }
264             } catch (Throwable t) {
265                 Log.e(ConnectionServiceWrapper.this, t, "");
266                 throw t;
267             } finally {
268                 Binder.restoreCallingIdentity(token);
269                 Log.endSession();
270             }
271         }
272 
273         @Override
setDisconnected(String callId, DisconnectCause disconnectCause, Session.Info sessionInfo)274         public void setDisconnected(String callId, DisconnectCause disconnectCause,
275                 Session.Info sessionInfo) {
276             Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_DISCONNECTED,
277                     mPackageAbbreviation);
278             long token = Binder.clearCallingIdentity();
279             try {
280                 synchronized (mLock) {
281                     logIncoming("setDisconnected %s %s", callId, disconnectCause);
282                     Call call = mCallIdMapper.getCall(callId);
283                     Log.d(this, "disconnect call %s %s", disconnectCause, call);
284                     if (call != null) {
285                         mCallsManager.markCallAsDisconnected(call, disconnectCause);
286                     } else {
287                         // Log.w(this, "setDisconnected, unknown call id: %s", args.arg1);
288                     }
289                 }
290             } catch (Throwable t) {
291                 Log.e(ConnectionServiceWrapper.this, t, "");
292                 throw t;
293             } finally {
294                 Binder.restoreCallingIdentity(token);
295                 Log.endSession();
296             }
297         }
298 
299         @Override
setOnHold(String callId, Session.Info sessionInfo)300         public void setOnHold(String callId, Session.Info sessionInfo) {
301             Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_ON_HOLD, mPackageAbbreviation);
302             long token = Binder.clearCallingIdentity();
303             try {
304                 synchronized (mLock) {
305                     logIncoming("setOnHold %s", callId);
306                     Call call = mCallIdMapper.getCall(callId);
307                     if (call != null) {
308                         mCallsManager.markCallAsOnHold(call);
309                     } else {
310                         // Log.w(this, "setOnHold, unknown call id: %s", msg.obj);
311                     }
312                 }
313             } catch (Throwable t) {
314                 Log.e(ConnectionServiceWrapper.this, t, "");
315                 throw t;
316             } finally {
317                 Binder.restoreCallingIdentity(token);
318                 Log.endSession();
319             }
320         }
321 
322         @Override
setRingbackRequested(String callId, boolean ringback, Session.Info sessionInfo)323         public void setRingbackRequested(String callId, boolean ringback,
324                 Session.Info sessionInfo) {
325             Log.startSession(sessionInfo, "CSW.SRR", mPackageAbbreviation);
326             long token = Binder.clearCallingIdentity();
327             try {
328                 synchronized (mLock) {
329                     logIncoming("setRingbackRequested %s %b", callId, ringback);
330                     Call call = mCallIdMapper.getCall(callId);
331                     if (call != null) {
332                         call.setRingbackRequested(ringback);
333                     } else {
334                         // Log.w(this, "setRingback, unknown call id: %s", args.arg1);
335                     }
336                 }
337             } catch (Throwable t) {
338                 Log.e(ConnectionServiceWrapper.this, t, "");
339                 throw t;
340             } finally {
341                 Binder.restoreCallingIdentity(token);
342                 Log.endSession();
343             }
344         }
345 
346         @Override
removeCall(String callId, Session.Info sessionInfo)347         public void removeCall(String callId, Session.Info sessionInfo) {
348             Log.startSession(sessionInfo, LogUtils.Sessions.CSW_REMOVE_CALL, mPackageAbbreviation);
349             long token = Binder.clearCallingIdentity();
350             try {
351                 synchronized (mLock) {
352                     logIncoming("removeCall %s", callId);
353                     Call call = mCallIdMapper.getCall(callId);
354                     if (call != null) {
355                         if (call.isAlive() && !call.isDisconnectHandledViaFuture()) {
356                             mCallsManager.markCallAsDisconnected(
357                                     call, new DisconnectCause(DisconnectCause.REMOTE));
358                         } else {
359                             mCallsManager.markCallAsRemoved(call);
360                         }
361                     }
362                 }
363             } catch (Throwable t) {
364                 Log.e(ConnectionServiceWrapper.this, t, "");
365                 throw t;
366             } finally {
367                 Binder.restoreCallingIdentity(token);
368                 Log.endSession();
369             }
370         }
371 
372         @Override
setConnectionCapabilities(String callId, int connectionCapabilities, Session.Info sessionInfo)373         public void setConnectionCapabilities(String callId, int connectionCapabilities,
374                 Session.Info sessionInfo) {
375             Log.startSession(sessionInfo, "CSW.sCC", mPackageAbbreviation);
376             long token = Binder.clearCallingIdentity();
377             try {
378                 synchronized (mLock) {
379                     logIncoming("setConnectionCapabilities %s %d", callId, connectionCapabilities);
380                     Call call = mCallIdMapper.getCall(callId);
381                     if (call != null) {
382                         call.setConnectionCapabilities(connectionCapabilities);
383                     } else {
384                         // Log.w(ConnectionServiceWrapper.this,
385                         // "setConnectionCapabilities, unknown call id: %s", msg.obj);
386                     }
387                 }
388             } catch (Throwable t) {
389                 Log.e(ConnectionServiceWrapper.this, t, "");
390                 throw t;
391             } finally {
392                 Binder.restoreCallingIdentity(token);
393                 Log.endSession();
394             }
395         }
396 
397         @Override
setConnectionProperties(String callId, int connectionProperties, Session.Info sessionInfo)398         public void setConnectionProperties(String callId, int connectionProperties,
399                 Session.Info sessionInfo) {
400             Log.startSession("CSW.sCP", mPackageAbbreviation);
401             long token = Binder.clearCallingIdentity();
402             try {
403                 synchronized (mLock) {
404                     logIncoming("setConnectionProperties %s %d", callId, connectionProperties);
405                     Call call = mCallIdMapper.getCall(callId);
406                     if (call != null) {
407                         call.setConnectionProperties(connectionProperties);
408                     }
409                 }
410             } catch (Throwable t) {
411                 Log.e(ConnectionServiceWrapper.this, t, "");
412                 throw t;
413             } finally {
414                 Binder.restoreCallingIdentity(token);
415                 Log.endSession();
416             }
417         }
418 
419         @Override
setIsConferenced(String callId, String conferenceCallId, Session.Info sessionInfo)420         public void setIsConferenced(String callId, String conferenceCallId,
421                 Session.Info sessionInfo) {
422             Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_IS_CONFERENCED,
423                     mPackageAbbreviation);
424             long token = Binder.clearCallingIdentity();
425             try {
426                 synchronized (mLock) {
427                     logIncoming("setIsConferenced %s %s", callId, conferenceCallId);
428                     Call childCall = mCallIdMapper.getCall(callId);
429                     if (childCall != null) {
430                         if (conferenceCallId == null) {
431                             Log.d(this, "unsetting parent: %s", conferenceCallId);
432                             childCall.setParentAndChildCall(null);
433                         } else {
434                             Call conferenceCall = mCallIdMapper.getCall(conferenceCallId);
435                             childCall.setParentAndChildCall(conferenceCall);
436                         }
437                     } else {
438                         // Log.w(this, "setIsConferenced, unknown call id: %s", args.arg1);
439                     }
440                 }
441             } catch (Throwable t) {
442                 Log.e(ConnectionServiceWrapper.this, t, "");
443                 throw t;
444             } finally {
445                 Binder.restoreCallingIdentity(token);
446                 Log.endSession();
447             }
448         }
449 
450         @Override
setConferenceMergeFailed(String callId, Session.Info sessionInfo)451         public void setConferenceMergeFailed(String callId, Session.Info sessionInfo) {
452             Log.startSession(sessionInfo, "CSW.sCMF", mPackageAbbreviation);
453             long token = Binder.clearCallingIdentity();
454             try {
455                 synchronized (mLock) {
456                     logIncoming("setConferenceMergeFailed %s", callId);
457                     // TODO: we should move the UI for indication a merge failure here
458                     // from CallNotifier.onSuppServiceFailed(). This way the InCallUI can
459                     // deliver the message anyway that they want. b/20530631.
460                     Call call = mCallIdMapper.getCall(callId);
461                     if (call != null) {
462                         call.onConnectionEvent(Connection.EVENT_CALL_MERGE_FAILED, null);
463                     } else {
464                         Log.w(this, "setConferenceMergeFailed, unknown call id: %s", callId);
465                     }
466                 }
467             } catch (Throwable t) {
468                 Log.e(ConnectionServiceWrapper.this, t, "");
469                 throw t;
470             } finally {
471                 Binder.restoreCallingIdentity(token);
472                 Log.endSession();
473             }
474         }
475 
476         @Override
addConferenceCall(String callId, ParcelableConference parcelableConference, Session.Info sessionInfo)477         public void addConferenceCall(String callId, ParcelableConference parcelableConference,
478                 Session.Info sessionInfo) {
479             Log.startSession(sessionInfo, LogUtils.Sessions.CSW_ADD_CONFERENCE_CALL,
480                     mPackageAbbreviation);
481 
482             if (parcelableConference.getConnectElapsedTimeMillis() != 0
483                     && mContext.checkCallingOrSelfPermission(MODIFY_PHONE_STATE)
484                             != PackageManager.PERMISSION_GRANTED) {
485                 Log.w(this, "addConferenceCall from caller without permission!");
486                 parcelableConference = new ParcelableConference.Builder(
487                         parcelableConference.getPhoneAccount(),
488                         parcelableConference.getState())
489                         .setConnectionCapabilities(parcelableConference.getConnectionCapabilities())
490                         .setConnectionProperties(parcelableConference.getConnectionProperties())
491                         .setConnectionIds(parcelableConference.getConnectionIds())
492                         .setVideoAttributes(parcelableConference.getVideoProvider(),
493                                 parcelableConference.getVideoState())
494                         .setStatusHints(parcelableConference.getStatusHints())
495                         .setExtras(parcelableConference.getExtras())
496                         .setAddress(parcelableConference.getHandle(),
497                                 parcelableConference.getHandlePresentation())
498                         // no caller display name set.
499                         .setDisconnectCause(parcelableConference.getDisconnectCause())
500                         .setRingbackRequested(parcelableConference.isRingbackRequested())
501                         .build();
502             }
503 
504             long token = Binder.clearCallingIdentity();
505             try {
506                 synchronized (mLock) {
507                     if (mCallIdMapper.getCall(callId) != null) {
508                         Log.w(this, "Attempting to add a conference call using an existing " +
509                                 "call id %s", callId);
510                         return;
511                     }
512                     logIncoming("addConferenceCall %s %s [%s]", callId, parcelableConference,
513                             parcelableConference.getConnectionIds());
514 
515                     // Make sure that there's at least one valid call. For remote connections
516                     // we'll get a add conference msg from both the remote connection service
517                     // and from the real connection service.
518                     boolean hasValidCalls = false;
519                     for (String connId : parcelableConference.getConnectionIds()) {
520                         if (mCallIdMapper.getCall(connId) != null) {
521                             hasValidCalls = true;
522                         }
523                     }
524                     // But don't bail out if the connection count is 0, because that is a valid
525                     // IMS conference state.
526                     if (!hasValidCalls && parcelableConference.getConnectionIds().size() > 0) {
527                         Log.d(this, "Attempting to add a conference with no valid calls");
528                         return;
529                     }
530 
531                     PhoneAccountHandle phAcc = null;
532                     if (parcelableConference != null &&
533                             parcelableConference.getPhoneAccount() != null) {
534                         phAcc = parcelableConference.getPhoneAccount();
535                     }
536 
537                     Bundle connectionExtras = parcelableConference.getExtras();
538 
539                     String connectIdToCheck = null;
540                     if (connectionExtras != null && connectionExtras
541                             .containsKey(Connection.EXTRA_ORIGINAL_CONNECTION_ID)) {
542                         // Conference was added via a connection manager, see if its original id is
543                         // known.
544                         connectIdToCheck = connectionExtras
545                                 .getString(Connection.EXTRA_ORIGINAL_CONNECTION_ID);
546                     } else {
547                         connectIdToCheck = callId;
548                     }
549 
550                     Call conferenceCall;
551                     // Check to see if this conference has already been added.
552                     Call alreadyAddedConnection = mCallsManager
553                             .getAlreadyAddedConnection(connectIdToCheck);
554                     if (alreadyAddedConnection != null && mCallIdMapper.getCall(callId) == null) {
555                         // We are currently attempting to add the conference via a connection mgr,
556                         // and the originating ConnectionService has already added it.  Instead of
557                         // making a new Telecom call, we will simply add it to the ID mapper here,
558                         // and replace the ConnectionService on the call.
559                         mCallIdMapper.addCall(alreadyAddedConnection, callId);
560                         alreadyAddedConnection.replaceConnectionService(
561                                 ConnectionServiceWrapper.this);
562                         conferenceCall = alreadyAddedConnection;
563                     } else {
564                         // need to create a new Call
565                         Call newConferenceCall = mCallsManager.createConferenceCall(callId,
566                                 phAcc, parcelableConference);
567                         mCallIdMapper.addCall(newConferenceCall, callId);
568                         newConferenceCall.setConnectionService(ConnectionServiceWrapper.this);
569                         conferenceCall = newConferenceCall;
570                     }
571 
572                     Log.d(this, "adding children to conference %s phAcc %s",
573                             parcelableConference.getConnectionIds(), phAcc);
574                     for (String connId : parcelableConference.getConnectionIds()) {
575                         Call childCall = mCallIdMapper.getCall(connId);
576                         Log.d(this, "found child: %s", connId);
577                         if (childCall != null) {
578                             childCall.setParentAndChildCall(conferenceCall);
579                         }
580                     }
581                 }
582             } catch (Throwable t) {
583                 Log.e(ConnectionServiceWrapper.this, t, "");
584                 throw t;
585             } finally {
586                 Binder.restoreCallingIdentity(token);
587                 Log.endSession();
588             }
589         }
590 
591         @Override
onPostDialWait(String callId, String remaining, Session.Info sessionInfo)592         public void onPostDialWait(String callId, String remaining,
593                 Session.Info sessionInfo) throws RemoteException {
594             Log.startSession(sessionInfo, "CSW.oPDW", mPackageAbbreviation);
595             long token = Binder.clearCallingIdentity();
596             try {
597                 synchronized (mLock) {
598                     logIncoming("onPostDialWait %s %s", callId, remaining);
599                     Call call = mCallIdMapper.getCall(callId);
600                     if (call != null) {
601                         call.onPostDialWait(remaining);
602                     } else {
603                         // Log.w(this, "onPostDialWait, unknown call id: %s", args.arg1);
604                     }
605                 }
606             } catch (Throwable t) {
607                 Log.e(ConnectionServiceWrapper.this, t, "");
608                 throw t;
609             } finally {
610                 Binder.restoreCallingIdentity(token);
611                 Log.endSession();
612             }
613         }
614 
615         @Override
onPostDialChar(String callId, char nextChar, Session.Info sessionInfo)616         public void onPostDialChar(String callId, char nextChar,
617                 Session.Info sessionInfo) throws RemoteException {
618             Log.startSession(sessionInfo, "CSW.oPDC", mPackageAbbreviation);
619             long token = Binder.clearCallingIdentity();
620             try {
621                 synchronized (mLock) {
622                     logIncoming("onPostDialChar %s %s", callId, nextChar);
623                     Call call = mCallIdMapper.getCall(callId);
624                     if (call != null) {
625                         call.onPostDialChar(nextChar);
626                     } else {
627                         // Log.w(this, "onPostDialChar, unknown call id: %s", args.arg1);
628                     }
629                 }
630             } catch (Throwable t) {
631                 Log.e(ConnectionServiceWrapper.this, t, "");
632                 throw t;
633             } finally {
634                 Binder.restoreCallingIdentity(token);
635                 Log.endSession();
636             }
637         }
638 
639         @Override
queryRemoteConnectionServices(RemoteServiceCallback callback, String callingPackage, Session.Info sessionInfo)640         public void queryRemoteConnectionServices(RemoteServiceCallback callback,
641                 String callingPackage, Session.Info sessionInfo) {
642             final UserHandle callingUserHandle = Binder.getCallingUserHandle();
643             Log.startSession(sessionInfo, "CSW.qRCS", mPackageAbbreviation);
644             long token = Binder.clearCallingIdentity();
645             try {
646                 synchronized (mLock) {
647                     logIncoming("queryRemoteConnectionServices callingPackage=" + callingPackage);
648                     ConnectionServiceWrapper.this
649                             .queryRemoteConnectionServices(callingUserHandle, callingPackage,
650                                     callback);
651                 }
652             } catch (Throwable t) {
653                 Log.e(ConnectionServiceWrapper.this, t, "");
654                 throw t;
655             } finally {
656                 Binder.restoreCallingIdentity(token);
657                 Log.endSession();
658             }
659         }
660 
661         @Override
setVideoState(String callId, int videoState, Session.Info sessionInfo)662         public void setVideoState(String callId, int videoState, Session.Info sessionInfo) {
663             Log.startSession(sessionInfo, "CSW.sVS", mPackageAbbreviation);
664             long token = Binder.clearCallingIdentity();
665             try {
666                 synchronized (mLock) {
667                     logIncoming("setVideoState %s %d", callId, videoState);
668                     Call call = mCallIdMapper.getCall(callId);
669                     if (call != null) {
670                         call.setVideoState(videoState);
671                     }
672                 }
673             } catch (Throwable t) {
674                 Log.e(ConnectionServiceWrapper.this, t, "");
675                 throw t;
676             } finally {
677                 Binder.restoreCallingIdentity(token);
678                 Log.endSession();
679             }
680         }
681 
682         @Override
setIsVoipAudioMode(String callId, boolean isVoip, Session.Info sessionInfo)683         public void setIsVoipAudioMode(String callId, boolean isVoip, Session.Info sessionInfo) {
684             Log.startSession(sessionInfo, "CSW.sIVAM", mPackageAbbreviation);
685             long token = Binder.clearCallingIdentity();
686             try {
687                 synchronized (mLock) {
688                     logIncoming("setIsVoipAudioMode %s %b", callId, isVoip);
689                     Call call = mCallIdMapper.getCall(callId);
690                     if (call != null) {
691                         call.setIsVoipAudioMode(isVoip);
692                     }
693                 }
694             } catch (Throwable t) {
695                 Log.e(ConnectionServiceWrapper.this, t, "");
696                 throw t;
697             } finally {
698                 Binder.restoreCallingIdentity(token);
699                 Log.endSession();
700             }
701         }
702 
703         @Override
setAudioRoute(String callId, int audioRoute, String bluetoothAddress, Session.Info sessionInfo)704         public void setAudioRoute(String callId, int audioRoute,
705                 String bluetoothAddress, Session.Info sessionInfo) {
706             Log.startSession(sessionInfo, "CSW.sAR", mPackageAbbreviation);
707             long token = Binder.clearCallingIdentity();
708             try {
709                 synchronized (mLock) {
710                     logIncoming("setAudioRoute %s %s", callId,
711                             CallAudioState.audioRouteToString(audioRoute));
712                     mCallsManager.setAudioRoute(audioRoute, bluetoothAddress);
713                 }
714             } catch (Throwable t) {
715                 Log.e(ConnectionServiceWrapper.this, t, "");
716                 throw t;
717             } finally {
718                 Binder.restoreCallingIdentity(token);
719                 Log.endSession();
720             }
721         }
722 
723         @Override
setStatusHints(String callId, StatusHints statusHints, Session.Info sessionInfo)724         public void setStatusHints(String callId, StatusHints statusHints,
725                 Session.Info sessionInfo) {
726             Log.startSession(sessionInfo, "CSW.sSH", mPackageAbbreviation);
727             long token = Binder.clearCallingIdentity();
728             try {
729                 synchronized (mLock) {
730                     logIncoming("setStatusHints %s %s", callId, statusHints);
731                     Call call = mCallIdMapper.getCall(callId);
732                     if (call != null) {
733                         call.setStatusHints(statusHints);
734                     }
735                 }
736             } catch (Throwable t) {
737                 Log.e(ConnectionServiceWrapper.this, t, "");
738                 throw t;
739             } finally {
740                 Binder.restoreCallingIdentity(token);
741                 Log.endSession();
742             }
743         }
744 
745         @Override
putExtras(String callId, Bundle extras, Session.Info sessionInfo)746         public void putExtras(String callId, Bundle extras, Session.Info sessionInfo) {
747             Log.startSession(sessionInfo, "CSW.pE", mPackageAbbreviation);
748             long token = Binder.clearCallingIdentity();
749             try {
750                 synchronized (mLock) {
751                     Bundle.setDefusable(extras, true);
752                     Call call = mCallIdMapper.getCall(callId);
753                     if (call != null) {
754                         call.putExtras(Call.SOURCE_CONNECTION_SERVICE, extras);
755                     }
756                 }
757             } catch (Throwable t) {
758                 Log.e(ConnectionServiceWrapper.this, t, "");
759                 throw t;
760             } finally {
761                 Binder.restoreCallingIdentity(token);
762                 Log.endSession();
763             }
764         }
765 
766         @Override
removeExtras(String callId, List<String> keys, Session.Info sessionInfo)767         public void removeExtras(String callId, List<String> keys, Session.Info sessionInfo) {
768             Log.startSession(sessionInfo, "CSW.rE", mPackageAbbreviation);
769             long token = Binder.clearCallingIdentity();
770             try {
771                 synchronized (mLock) {
772                     logIncoming("removeExtra %s %s", callId, keys);
773                     Call call = mCallIdMapper.getCall(callId);
774                     if (call != null) {
775                         call.removeExtras(Call.SOURCE_CONNECTION_SERVICE, keys);
776                     }
777                 }
778             } catch (Throwable t) {
779                 Log.e(ConnectionServiceWrapper.this, t, "");
780                 throw t;
781             } finally {
782                 Binder.restoreCallingIdentity(token);
783                 Log.endSession();
784             }
785         }
786 
787         @Override
setAddress(String callId, Uri address, int presentation, Session.Info sessionInfo)788         public void setAddress(String callId, Uri address, int presentation,
789                 Session.Info sessionInfo) {
790             Log.startSession(sessionInfo, "CSW.sA", mPackageAbbreviation);
791 
792             long token = Binder.clearCallingIdentity();
793             try {
794                 synchronized (mLock) {
795                     logIncoming("setAddress %s %s %d", callId, address, presentation);
796                     Call call = mCallIdMapper.getCall(callId);
797                     if (call != null) {
798                         call.setHandle(address, presentation);
799                     }
800                 }
801             } catch (Throwable t) {
802                 Log.e(ConnectionServiceWrapper.this, t, "");
803                 throw t;
804             } finally {
805                 Binder.restoreCallingIdentity(token);
806                 Log.endSession();
807             }
808         }
809 
810         @Override
setCallerDisplayName(String callId, String callerDisplayName, int presentation, Session.Info sessionInfo)811         public void setCallerDisplayName(String callId, String callerDisplayName, int presentation,
812                 Session.Info sessionInfo) {
813             Log.startSession(sessionInfo, "CSW.sCDN", mPackageAbbreviation);
814             long token = Binder.clearCallingIdentity();
815             try {
816                 synchronized (mLock) {
817                     logIncoming("setCallerDisplayName %s %s %d", callId, callerDisplayName,
818                             presentation);
819                     Call call = mCallIdMapper.getCall(callId);
820                     if (call != null) {
821                         call.setCallerDisplayName(callerDisplayName, presentation);
822                     }
823                 }
824             } catch (Throwable t) {
825                 Log.e(ConnectionServiceWrapper.this, t, "");
826                 throw t;
827             } finally {
828                 Binder.restoreCallingIdentity(token);
829                 Log.endSession();
830             }
831         }
832 
833         @Override
setConferenceableConnections(String callId, List<String> conferenceableCallIds, Session.Info sessionInfo)834         public void setConferenceableConnections(String callId, List<String> conferenceableCallIds,
835                 Session.Info sessionInfo) {
836             Log.startSession(sessionInfo, "CSW.sCC", mPackageAbbreviation);
837             long token = Binder.clearCallingIdentity();
838             try {
839                 synchronized (mLock) {
840 
841                     Call call = mCallIdMapper.getCall(callId);
842                     if (call != null) {
843                         logIncoming("setConferenceableConnections %s %s", callId,
844                                 conferenceableCallIds);
845                         List<Call> conferenceableCalls =
846                                 new ArrayList<>(conferenceableCallIds.size());
847                         for (String otherId : conferenceableCallIds) {
848                             Call otherCall = mCallIdMapper.getCall(otherId);
849                             if (otherCall != null && otherCall != call) {
850                                 conferenceableCalls.add(otherCall);
851                             }
852                         }
853                         call.setConferenceableCalls(conferenceableCalls);
854                     }
855                 }
856             } catch (Throwable t) {
857                 Log.e(ConnectionServiceWrapper.this, t, "");
858                 throw t;
859             } finally {
860                 Binder.restoreCallingIdentity(token);
861                 Log.endSession();
862             }
863         }
864 
865         @Override
addExistingConnection(String callId, ParcelableConnection connection, Session.Info sessionInfo)866         public void addExistingConnection(String callId, ParcelableConnection connection,
867                 Session.Info sessionInfo) {
868             Log.startSession(sessionInfo, "CSW.aEC", mPackageAbbreviation);
869             UserHandle userHandle = Binder.getCallingUserHandle();
870             // Check that the Calling Package matches PhoneAccountHandle's Component Package
871             PhoneAccountHandle callingPhoneAccountHandle = connection.getPhoneAccount();
872             if (callingPhoneAccountHandle != null) {
873                 mAppOpsManager.checkPackage(Binder.getCallingUid(),
874                         callingPhoneAccountHandle.getComponentName().getPackageName());
875             }
876 
877             long token = Binder.clearCallingIdentity();
878             try {
879                 synchronized (mLock) {
880                     // Make sure that the PhoneAccount associated with the incoming
881                     // ParcelableConnection is in fact registered to Telecom and is being called
882                     // from the correct user.
883                     List<PhoneAccountHandle> accountHandles =
884                     // Include CAPABILITY_EMERGENCY_CALLS_ONLY in this list in case we are adding
885                     // an emergency call.
886                             mPhoneAccountRegistrar.getCallCapablePhoneAccounts(null /*uriScheme*/,
887                             false /*includeDisabledAccounts*/, userHandle, 0 /*capabilities*/,
888                             0 /*excludedCapabilities*/);
889                     PhoneAccountHandle phoneAccountHandle = null;
890                     for (PhoneAccountHandle accountHandle : accountHandles) {
891                         if(accountHandle.equals(callingPhoneAccountHandle)) {
892                             phoneAccountHandle = accountHandle;
893                         }
894                     }
895                     // Allow the Sim call manager account as well, even if its disabled.
896                     if (phoneAccountHandle == null && callingPhoneAccountHandle != null) {
897                         // Search all SIM PhoneAccounts to see if there is a SIM call manager
898                         // associated with any of them and verify that the calling handle matches.
899                         for (PhoneAccountHandle handle :
900                                 mPhoneAccountRegistrar.getSimPhoneAccounts(userHandle)) {
901                             int subId = mPhoneAccountRegistrar.getSubscriptionIdForPhoneAccount(
902                                     handle);
903                             PhoneAccountHandle connectionMgrHandle =
904                                     mPhoneAccountRegistrar.getSimCallManager(subId, userHandle);
905                             if (callingPhoneAccountHandle.equals(connectionMgrHandle)) {
906                                 phoneAccountHandle = connectionMgrHandle;
907                                 break;
908                             }
909                         }
910                     }
911                     if (phoneAccountHandle != null) {
912                         logIncoming("addExistingConnection %s %s", callId, connection);
913 
914                         Bundle connectionExtras = connection.getExtras();
915                         String connectIdToCheck = null;
916                         if (connectionExtras != null && connectionExtras
917                                 .containsKey(Connection.EXTRA_ORIGINAL_CONNECTION_ID)) {
918                             connectIdToCheck = connectionExtras
919                                     .getString(Connection.EXTRA_ORIGINAL_CONNECTION_ID);
920                         } else {
921                             connectIdToCheck = callId;
922                         }
923 
924                         // Handle the case where an existing connection was added by Telephony via
925                         // a connection manager.  The remote connection service API does not include
926                         // the ability to specify a parent connection when adding an existing
927                         // connection, so we stash the desired parent in the connection extras.
928                         if (connectionExtras != null
929                                 && connectionExtras.containsKey(
930                                         Connection.EXTRA_ADD_TO_CONFERENCE_ID)
931                                 && connection.getParentCallId() == null) {
932                             String parentId = connectionExtras.getString(
933                                     Connection.EXTRA_ADD_TO_CONFERENCE_ID);
934                             Log.i(ConnectionServiceWrapper.this, "addExistingConnection: remote "
935                                     + "connection will auto-add to parent %s", parentId);
936                             // Replace parcelable connection instance, swapping the new desired
937                             // parent in.
938                             connection = new ParcelableConnection(
939                                     connection.getPhoneAccount(),
940                                     connection.getState(),
941                                     connection.getConnectionCapabilities(),
942                                     connection.getConnectionProperties(),
943                                     connection.getSupportedAudioRoutes(),
944                                     connection.getHandle(),
945                                     connection.getHandlePresentation(),
946                                     connection.getCallerDisplayName(),
947                                     connection.getCallerDisplayNamePresentation(),
948                                     connection.getVideoProvider(),
949                                     connection.getVideoState(),
950                                     connection.isRingbackRequested(),
951                                     connection.getIsVoipAudioMode(),
952                                     connection.getConnectTimeMillis(),
953                                     connection.getConnectElapsedTimeMillis(),
954                                     connection.getStatusHints(),
955                                     connection.getDisconnectCause(),
956                                     connection.getConferenceableConnectionIds(),
957                                     connection.getExtras(),
958                                     parentId,
959                                     connection.getCallDirection(),
960                                     connection.getCallerNumberVerificationStatus());
961                         }
962                         // Check to see if this Connection has already been added.
963                         Call alreadyAddedConnection = mCallsManager
964                                 .getAlreadyAddedConnection(connectIdToCheck);
965 
966                         if (alreadyAddedConnection != null
967                                 && mCallIdMapper.getCall(callId) == null) {
968                             mCallIdMapper.addCall(alreadyAddedConnection, callId);
969                             alreadyAddedConnection
970                                     .replaceConnectionService(ConnectionServiceWrapper.this);
971                             return;
972                         }
973 
974                         Call existingCall = mCallsManager
975                                 .createCallForExistingConnection(callId, connection);
976                         mCallIdMapper.addCall(existingCall, callId);
977                         existingCall.setConnectionService(ConnectionServiceWrapper.this);
978                     } else {
979                         Log.e(this, new RemoteException("The PhoneAccount being used is not " +
980                                 "currently registered with Telecom."), "Unable to " +
981                                 "addExistingConnection.");
982                     }
983                 }
984             } catch (Throwable t) {
985                 Log.e(ConnectionServiceWrapper.this, t, "");
986                 throw t;
987             } finally {
988                 Binder.restoreCallingIdentity(token);
989                 Log.endSession();
990             }
991         }
992 
993         @Override
onConnectionEvent(String callId, String event, Bundle extras, Session.Info sessionInfo)994         public void onConnectionEvent(String callId, String event, Bundle extras,
995                 Session.Info sessionInfo) {
996             Log.startSession(sessionInfo, "CSW.oCE", mPackageAbbreviation);
997             long token = Binder.clearCallingIdentity();
998             try {
999                 synchronized (mLock) {
1000                     Bundle.setDefusable(extras, true);
1001                     Call call = mCallIdMapper.getCall(callId);
1002                     if (call != null) {
1003                         call.onConnectionEvent(event, extras);
1004                     }
1005                 }
1006             } catch (Throwable t) {
1007                 Log.e(ConnectionServiceWrapper.this, t, "");
1008                 throw t;
1009             } finally {
1010                 Binder.restoreCallingIdentity(token);
1011                 Log.endSession();
1012             }
1013         }
1014 
1015         @Override
onRttInitiationSuccess(String callId, Session.Info sessionInfo)1016         public void onRttInitiationSuccess(String callId, Session.Info sessionInfo)
1017                 throws RemoteException {
1018 
1019         }
1020 
1021         @Override
onRttInitiationFailure(String callId, int reason, Session.Info sessionInfo)1022         public void onRttInitiationFailure(String callId, int reason, Session.Info sessionInfo)
1023                 throws RemoteException {
1024             Log.startSession(sessionInfo, "CSW.oRIF", mPackageAbbreviation);
1025             long token = Binder.clearCallingIdentity();
1026             try {
1027                 synchronized (mLock) {
1028                     Call call = mCallIdMapper.getCall(callId);
1029                     if (call != null) {
1030                         call.onRttConnectionFailure(reason);
1031                     }
1032                 }
1033             } catch (Throwable t) {
1034                 Log.e(ConnectionServiceWrapper.this, t, "");
1035                 throw t;
1036             } finally {
1037                 Binder.restoreCallingIdentity(token);
1038                 Log.endSession();
1039             }
1040         }
1041 
1042         @Override
onRttSessionRemotelyTerminated(String callId, Session.Info sessionInfo)1043         public void onRttSessionRemotelyTerminated(String callId, Session.Info sessionInfo)
1044                 throws RemoteException {
1045 
1046         }
1047 
1048         @Override
onRemoteRttRequest(String callId, Session.Info sessionInfo)1049         public void onRemoteRttRequest(String callId, Session.Info sessionInfo)
1050                 throws RemoteException {
1051             Log.startSession(sessionInfo, "CSW.oRRR", mPackageAbbreviation);
1052             long token = Binder.clearCallingIdentity();
1053             try {
1054                 synchronized (mLock) {
1055                     Call call = mCallIdMapper.getCall(callId);
1056                     if (call != null) {
1057                         call.onRemoteRttRequest();
1058                     }
1059                 }
1060             } catch (Throwable t) {
1061                 Log.e(ConnectionServiceWrapper.this, t, "");
1062                 throw t;
1063             } finally {
1064                 Binder.restoreCallingIdentity(token);
1065                 Log.endSession();
1066             }
1067         }
1068 
1069         @Override
onPhoneAccountChanged(String callId, PhoneAccountHandle pHandle, Session.Info sessionInfo)1070         public void onPhoneAccountChanged(String callId, PhoneAccountHandle pHandle,
1071                 Session.Info sessionInfo) throws RemoteException {
1072             // Check that the Calling Package matches PhoneAccountHandle's Component Package
1073             if (pHandle != null) {
1074                 mAppOpsManager.checkPackage(Binder.getCallingUid(),
1075                         pHandle.getComponentName().getPackageName());
1076             }
1077             Log.startSession(sessionInfo, "CSW.oPAC", mPackageAbbreviation);
1078             long token = Binder.clearCallingIdentity();
1079             try {
1080                 synchronized (mLock) {
1081                     Call call = mCallIdMapper.getCall(callId);
1082                     if (call != null) {
1083                         call.setTargetPhoneAccount(pHandle);
1084                     }
1085                 }
1086             } catch (Throwable t) {
1087                 Log.e(ConnectionServiceWrapper.this, t, "");
1088                 throw t;
1089             } finally {
1090                 Binder.restoreCallingIdentity(token);
1091                 Log.endSession();
1092             }
1093         }
1094 
1095         @Override
onConnectionServiceFocusReleased(Session.Info sessionInfo)1096         public void onConnectionServiceFocusReleased(Session.Info sessionInfo)
1097                 throws RemoteException {
1098             Log.startSession(sessionInfo, "CSW.oCSFR", mPackageAbbreviation);
1099             long token = Binder.clearCallingIdentity();
1100             try {
1101                 synchronized (mLock) {
1102                     mConnSvrFocusListener.onConnectionServiceReleased(
1103                             ConnectionServiceWrapper.this);
1104                 }
1105             } catch (Throwable t) {
1106                 Log.e(ConnectionServiceWrapper.this, t, "");
1107                 throw t;
1108             } finally {
1109                 Binder.restoreCallingIdentity(token);
1110                 Log.endSession();
1111             }
1112         }
1113 
1114         @Override
setConferenceState(String callId, boolean isConference, Session.Info sessionInfo)1115         public void setConferenceState(String callId, boolean isConference,
1116                 Session.Info sessionInfo) throws RemoteException {
1117             Log.startSession(sessionInfo, "CSW.sCS", mPackageAbbreviation);
1118 
1119             if (mContext.checkCallingOrSelfPermission(MODIFY_PHONE_STATE)
1120                     != PackageManager.PERMISSION_GRANTED) {
1121                 Log.w(this, "setConferenceState from caller without permission.");
1122                 Log.endSession();
1123                 return;
1124             }
1125 
1126             long token = Binder.clearCallingIdentity();
1127             try {
1128                 synchronized (mLock) {
1129                     Call call = mCallIdMapper.getCall(callId);
1130                     if (call != null) {
1131                         call.setConferenceState(isConference);
1132                     }
1133                 }
1134             } catch (Throwable t) {
1135                 Log.e(ConnectionServiceWrapper.this, t, "");
1136                 throw t;
1137             } finally {
1138                 Binder.restoreCallingIdentity(token);
1139                 Log.endSession();
1140             }
1141         }
1142 
1143         @Override
setCallDirection(String callId, int direction, Session.Info sessionInfo)1144         public void setCallDirection(String callId, int direction, Session.Info sessionInfo) {
1145             Log.startSession(sessionInfo, "CSW.sCD", mPackageAbbreviation);
1146 
1147             if (mContext.checkCallingOrSelfPermission(MODIFY_PHONE_STATE)
1148                     != PackageManager.PERMISSION_GRANTED) {
1149                 Log.w(this, "setCallDirection from caller without permission.");
1150                 Log.endSession();
1151                 return;
1152             }
1153 
1154             long token = Binder.clearCallingIdentity();
1155             try {
1156                 synchronized (mLock) {
1157                     logIncoming("setCallDirection %s %d", callId, direction);
1158                     Call call = mCallIdMapper.getCall(callId);
1159                     if (call != null) {
1160                         call.setCallDirection(Call.getRemappedCallDirection(direction));
1161                     }
1162                 }
1163             } catch (Throwable t) {
1164                 Log.e(ConnectionServiceWrapper.this, t, "");
1165                 throw t;
1166             } finally {
1167                 Binder.restoreCallingIdentity(token);
1168                 Log.endSession();
1169             }
1170         }
1171     }
1172 
1173     private final Adapter mAdapter = new Adapter();
1174     private final CallIdMapper mCallIdMapper = new CallIdMapper(Call::getConnectionId);
1175     private final Map<String, CreateConnectionResponse> mPendingResponses = new HashMap<>();
1176 
1177     private Binder2 mBinder = new Binder2();
1178     private IConnectionService mServiceInterface;
1179     private final ConnectionServiceRepository mConnectionServiceRepository;
1180     private final PhoneAccountRegistrar mPhoneAccountRegistrar;
1181     private final CallsManager mCallsManager;
1182     private final AppOpsManager mAppOpsManager;
1183     private final Context mContext;
1184 
1185     private ConnectionServiceFocusManager.ConnectionServiceFocusListener mConnSvrFocusListener;
1186 
1187     /**
1188      * Creates a connection service.
1189      *
1190      * @param componentName The component name of the service with which to bind.
1191      * @param connectionServiceRepository Connection service repository.
1192      * @param phoneAccountRegistrar Phone account registrar
1193      * @param callsManager Calls manager
1194      * @param context The context.
1195      * @param userHandle The {@link UserHandle} to use when binding.
1196      */
ConnectionServiceWrapper( ComponentName componentName, ConnectionServiceRepository connectionServiceRepository, PhoneAccountRegistrar phoneAccountRegistrar, CallsManager callsManager, Context context, TelecomSystem.SyncRoot lock, UserHandle userHandle)1197     ConnectionServiceWrapper(
1198             ComponentName componentName,
1199             ConnectionServiceRepository connectionServiceRepository,
1200             PhoneAccountRegistrar phoneAccountRegistrar,
1201             CallsManager callsManager,
1202             Context context,
1203             TelecomSystem.SyncRoot lock,
1204             UserHandle userHandle) {
1205         super(ConnectionService.SERVICE_INTERFACE, componentName, context, lock, userHandle);
1206         mConnectionServiceRepository = connectionServiceRepository;
1207         phoneAccountRegistrar.addListener(new PhoneAccountRegistrar.Listener() {
1208             // TODO -- Upon changes to PhoneAccountRegistrar, need to re-wire connections
1209             // To do this, we must proxy remote ConnectionService objects
1210         });
1211         mPhoneAccountRegistrar = phoneAccountRegistrar;
1212         mCallsManager = callsManager;
1213         mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
1214         mContext = context;
1215     }
1216 
1217     /** See {@link IConnectionService#addConnectionServiceAdapter}. */
addConnectionServiceAdapter(IConnectionServiceAdapter adapter)1218     private void addConnectionServiceAdapter(IConnectionServiceAdapter adapter) {
1219         if (isServiceValid("addConnectionServiceAdapter")) {
1220             try {
1221                 logOutgoing("addConnectionServiceAdapter %s", adapter);
1222                 mServiceInterface.addConnectionServiceAdapter(adapter, Log.getExternalSession());
1223             } catch (RemoteException e) {
1224             }
1225         }
1226     }
1227 
1228     /** See {@link IConnectionService#removeConnectionServiceAdapter}. */
removeConnectionServiceAdapter(IConnectionServiceAdapter adapter)1229     private void removeConnectionServiceAdapter(IConnectionServiceAdapter adapter) {
1230         if (isServiceValid("removeConnectionServiceAdapter")) {
1231             try {
1232                 logOutgoing("removeConnectionServiceAdapter %s", adapter);
1233                 mServiceInterface.removeConnectionServiceAdapter(adapter, Log.getExternalSession());
1234             } catch (RemoteException e) {
1235             }
1236         }
1237     }
1238 
1239     /**
1240      * Creates a conference for a new outgoing call or attach to an existing incoming call.
1241      */
createConference(final Call call, final CreateConnectionResponse response)1242     public void createConference(final Call call, final CreateConnectionResponse response) {
1243         Log.d(this, "createConference(%s) via %s.", call, getComponentName());
1244         BindCallback callback = new BindCallback() {
1245             @Override
1246             public void onSuccess() {
1247                 String callId = mCallIdMapper.getCallId(call);
1248                 mPendingResponses.put(callId, response);
1249 
1250                 Bundle extras = call.getIntentExtras();
1251                 if (extras == null) {
1252                     extras = new Bundle();
1253                 }
1254                 extras.putString(Connection.EXTRA_ORIGINAL_CONNECTION_ID, callId);
1255 
1256                 Log.addEvent(call, LogUtils.Events.START_CONFERENCE,
1257                         Log.piiHandle(call.getHandle()));
1258 
1259                 ConnectionRequest connectionRequest = new ConnectionRequest.Builder()
1260                         .setAccountHandle(call.getTargetPhoneAccount())
1261                         .setAddress(call.getHandle())
1262                         .setExtras(extras)
1263                         .setVideoState(call.getVideoState())
1264                         .setTelecomCallId(callId)
1265                         // For self-managed incoming calls, if there is another ongoing call Telecom
1266                         // is responsible for showing a UI to ask the user if they'd like to answer
1267                         // this new incoming call.
1268                         .setShouldShowIncomingCallUi(
1269                                 !mCallsManager.shouldShowSystemIncomingCallUi(call))
1270                         .setRttPipeFromInCall(call.getInCallToCsRttPipeForCs())
1271                         .setRttPipeToInCall(call.getCsToInCallRttPipeForCs())
1272                         .setParticipants(call.getParticipants())
1273                         .setIsAdhocConferenceCall(call.isAdhocConferenceCall())
1274                         .build();
1275 
1276                 try {
1277                     mServiceInterface.createConference(
1278                             call.getConnectionManagerPhoneAccount(),
1279                             callId,
1280                             connectionRequest,
1281                             call.shouldAttachToExistingConnection(),
1282                             call.isUnknown(),
1283                             Log.getExternalSession(TELECOM_ABBREVIATION));
1284 
1285                 } catch (RemoteException e) {
1286                     Log.e(this, e, "Failure to createConference -- %s", getComponentName());
1287                     mPendingResponses.remove(callId).handleCreateConferenceFailure(
1288                             new DisconnectCause(DisconnectCause.ERROR, e.toString()));
1289                 }
1290             }
1291 
1292             @Override
1293             public void onFailure() {
1294                 Log.e(this, new Exception(), "Failure to conference %s", getComponentName());
1295                 response.handleCreateConferenceFailure(new DisconnectCause(DisconnectCause.ERROR));
1296             }
1297         };
1298 
1299         mBinder.bind(callback, call);
1300 
1301     }
1302 
1303     /**
1304      * Creates a new connection for a new outgoing call or to attach to an existing incoming call.
1305      */
1306     @VisibleForTesting
createConnection(final Call call, final CreateConnectionResponse response)1307     public void createConnection(final Call call, final CreateConnectionResponse response) {
1308         Log.i(this, "createConnection(%s) via %s.", call, getComponentName());
1309         BindCallback callback = new BindCallback() {
1310             @Override
1311             public void onSuccess() {
1312                 String callId = mCallIdMapper.getCallId(call);
1313                 if (callId == null) {
1314                     Log.w(ConnectionServiceWrapper.this, "Call not present"
1315                             + " in call id mapper, maybe it was aborted before the bind"
1316                             + " completed successfully?");
1317                     response.handleCreateConnectionFailure(
1318                             new DisconnectCause(DisconnectCause.CANCELED));
1319                     return;
1320                 }
1321                 mPendingResponses.put(callId, response);
1322 
1323                 GatewayInfo gatewayInfo = call.getGatewayInfo();
1324                 Bundle extras = call.getIntentExtras();
1325                 if (gatewayInfo != null && gatewayInfo.getGatewayProviderPackageName() != null &&
1326                         gatewayInfo.getOriginalAddress() != null) {
1327                     extras = (Bundle) extras.clone();
1328                     extras.putString(
1329                             TelecomManager.GATEWAY_PROVIDER_PACKAGE,
1330                             gatewayInfo.getGatewayProviderPackageName());
1331                     extras.putParcelable(
1332                             TelecomManager.GATEWAY_ORIGINAL_ADDRESS,
1333                             gatewayInfo.getOriginalAddress());
1334                 }
1335 
1336                 if (call.isIncoming() && mCallsManager.getEmergencyCallHelper()
1337                         .getLastEmergencyCallTimeMillis() > 0) {
1338                   // Add the last emergency call time to the connection request for incoming calls
1339                   if (extras == call.getIntentExtras()) {
1340                     extras = (Bundle) extras.clone();
1341                   }
1342                   extras.putLong(android.telecom.Call.EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS,
1343                       mCallsManager.getEmergencyCallHelper().getLastEmergencyCallTimeMillis());
1344                 }
1345 
1346                 // Call is incoming and added because we're handing over from another; tell CS
1347                 // that its expected to handover.
1348                 if (call.isIncoming() && call.getHandoverSourceCall() != null) {
1349                     extras.putBoolean(TelecomManager.EXTRA_IS_HANDOVER, true);
1350                     extras.putParcelable(TelecomManager.EXTRA_HANDOVER_FROM_PHONE_ACCOUNT,
1351                             call.getHandoverSourceCall().getTargetPhoneAccount());
1352                 }
1353 
1354                 Log.addEvent(call, LogUtils.Events.START_CONNECTION,
1355                         Log.piiHandle(call.getHandle()) + " via:" +
1356                                 getComponentName().getPackageName());
1357 
1358                 ConnectionRequest connectionRequest = new ConnectionRequest.Builder()
1359                         .setAccountHandle(call.getTargetPhoneAccount())
1360                         .setAddress(call.getHandle())
1361                         .setExtras(extras)
1362                         .setVideoState(call.getVideoState())
1363                         .setTelecomCallId(callId)
1364                         // For self-managed incoming calls, if there is another ongoing call Telecom
1365                         // is responsible for showing a UI to ask the user if they'd like to answer
1366                         // this new incoming call.
1367                         .setShouldShowIncomingCallUi(
1368                                 !mCallsManager.shouldShowSystemIncomingCallUi(call))
1369                         .setRttPipeFromInCall(call.getInCallToCsRttPipeForCs())
1370                         .setRttPipeToInCall(call.getCsToInCallRttPipeForCs())
1371                         .build();
1372 
1373                 try {
1374                     mServiceInterface.createConnection(
1375                             call.getConnectionManagerPhoneAccount(),
1376                             callId,
1377                             connectionRequest,
1378                             call.shouldAttachToExistingConnection(),
1379                             call.isUnknown(),
1380                             Log.getExternalSession(TELECOM_ABBREVIATION));
1381 
1382                 } catch (RemoteException e) {
1383                     Log.e(this, e, "Failure to createConnection -- %s", getComponentName());
1384                     mPendingResponses.remove(callId).handleCreateConnectionFailure(
1385                             new DisconnectCause(DisconnectCause.ERROR, e.toString()));
1386                 }
1387             }
1388 
1389             @Override
1390             public void onFailure() {
1391                 Log.e(this, new Exception(), "Failure to call %s", getComponentName());
1392                 response.handleCreateConnectionFailure(new DisconnectCause(DisconnectCause.ERROR));
1393             }
1394         };
1395 
1396         mBinder.bind(callback, call);
1397     }
1398 
1399     /**
1400      * Notifies the {@link ConnectionService} associated with a {@link Call} that the request to
1401      * create a connection has been denied or failed.
1402      * @param call The call.
1403      */
1404     @VisibleForTesting
createConnectionFailed(final Call call)1405     public void createConnectionFailed(final Call call) {
1406         Log.d(this, "createConnectionFailed(%s) via %s.", call, getComponentName());
1407         BindCallback callback = new BindCallback() {
1408             @Override
1409             public void onSuccess() {
1410                 final String callId = mCallIdMapper.getCallId(call);
1411                 // If still bound, tell the connection service create connection has failed.
1412                 if (callId != null && isServiceValid("createConnectionFailed")) {
1413                     Log.addEvent(call, LogUtils.Events.CREATE_CONNECTION_FAILED,
1414                             Log.piiHandle(call.getHandle()));
1415                     try {
1416                         logOutgoing("createConnectionFailed %s", callId);
1417                         mServiceInterface.createConnectionFailed(
1418                                 call.getConnectionManagerPhoneAccount(),
1419                                 callId,
1420                                 new ConnectionRequest(
1421                                         call.getTargetPhoneAccount(),
1422                                         call.getHandle(),
1423                                         call.getIntentExtras(),
1424                                         call.getVideoState(),
1425                                         callId,
1426                                         false),
1427                                 call.isIncoming(),
1428                                 Log.getExternalSession(TELECOM_ABBREVIATION));
1429                         call.setDisconnectCause(new DisconnectCause(DisconnectCause.CANCELED));
1430                         call.disconnect();
1431                     } catch (RemoteException e) {
1432                     }
1433                 }
1434             }
1435 
1436             @Override
1437             public void onFailure() {
1438                 // Binding failed.  Oh no.
1439                 Log.w(this, "onFailure - could not bind to CS for call %s", call.getId());
1440             }
1441         };
1442 
1443         mBinder.bind(callback, call);
1444     }
1445 
1446     /**
1447      * Notifies the {@link ConnectionService} associated with a {@link Call} that the request to
1448      * create a conference has been denied or failed.
1449      * @param call The call.
1450      */
createConferenceFailed(final Call call)1451     void createConferenceFailed(final Call call) {
1452         Log.d(this, "createConferenceFailed(%s) via %s.", call, getComponentName());
1453         BindCallback callback = new BindCallback() {
1454             @Override
1455             public void onSuccess() {
1456                 final String callId = mCallIdMapper.getCallId(call);
1457                 // If still bound, tell the connection service create connection has failed.
1458                 if (callId != null && isServiceValid("createConferenceFailed")) {
1459                     Log.addEvent(call, LogUtils.Events.CREATE_CONFERENCE_FAILED,
1460                             Log.piiHandle(call.getHandle()));
1461                     try {
1462                         logOutgoing("createConferenceFailed %s", callId);
1463                         mServiceInterface.createConferenceFailed(
1464                                 call.getConnectionManagerPhoneAccount(),
1465                                 callId,
1466                                 new ConnectionRequest(
1467                                         call.getTargetPhoneAccount(),
1468                                         call.getHandle(),
1469                                         call.getIntentExtras(),
1470                                         call.getVideoState(),
1471                                         callId,
1472                                         false),
1473                                 call.isIncoming(),
1474                                 Log.getExternalSession(TELECOM_ABBREVIATION));
1475                         call.setDisconnectCause(new DisconnectCause(DisconnectCause.CANCELED));
1476                         call.disconnect();
1477                     } catch (RemoteException e) {
1478                     }
1479                 }
1480             }
1481 
1482             @Override
1483             public void onFailure() {
1484                 // Binding failed.  Oh no.
1485                 Log.w(this, "onFailure - could not bind to CS for conf call %s", call.getId());
1486             }
1487         };
1488 
1489         mBinder.bind(callback, call);
1490     }
1491 
1492 
handoverFailed(final Call call, final int reason)1493     void handoverFailed(final Call call, final int reason) {
1494         Log.d(this, "handoverFailed(%s) via %s.", call, getComponentName());
1495         BindCallback callback = new BindCallback() {
1496             @Override
1497             public void onSuccess() {
1498                 final String callId = mCallIdMapper.getCallId(call);
1499                 // If still bound, tell the connection service create connection has failed.
1500                 if (callId != null && isServiceValid("handoverFailed")) {
1501                     Log.addEvent(call, LogUtils.Events.HANDOVER_FAILED,
1502                             Log.piiHandle(call.getHandle()));
1503                     try {
1504                         mServiceInterface.handoverFailed(
1505                                 callId,
1506                                 new ConnectionRequest(
1507                                         call.getTargetPhoneAccount(),
1508                                         call.getHandle(),
1509                                         call.getIntentExtras(),
1510                                         call.getVideoState(),
1511                                         callId,
1512                                         false),
1513                                 reason,
1514                                 Log.getExternalSession(TELECOM_ABBREVIATION));
1515                     } catch (RemoteException e) {
1516                     }
1517                 }
1518             }
1519 
1520             @Override
1521             public void onFailure() {
1522                 // Binding failed.
1523                 Log.w(this, "onFailure - could not bind to CS for call %s",
1524                         call.getId());
1525             }
1526         };
1527 
1528         mBinder.bind(callback, call);
1529     }
1530 
handoverComplete(final Call call)1531     void handoverComplete(final Call call) {
1532         Log.d(this, "handoverComplete(%s) via %s.", call, getComponentName());
1533         BindCallback callback = new BindCallback() {
1534             @Override
1535             public void onSuccess() {
1536                 final String callId = mCallIdMapper.getCallId(call);
1537                 // If still bound, tell the connection service create connection has failed.
1538                 if (callId != null && isServiceValid("handoverComplete")) {
1539                     try {
1540                         mServiceInterface.handoverComplete(
1541                                 callId,
1542                                 Log.getExternalSession(TELECOM_ABBREVIATION));
1543                     } catch (RemoteException e) {
1544                     }
1545                 }
1546             }
1547 
1548             @Override
1549             public void onFailure() {
1550                 // Binding failed.
1551                 Log.w(this, "onFailure - could not bind to CS for call %s",
1552                         call.getId());
1553             }
1554         };
1555 
1556         mBinder.bind(callback, call);
1557     }
1558 
1559     /** @see IConnectionService#abort(String, Session.Info)  */
abort(Call call)1560     void abort(Call call) {
1561         // Clear out any pending outgoing call data
1562         final String callId = mCallIdMapper.getCallId(call);
1563 
1564         // If still bound, tell the connection service to abort.
1565         if (callId != null && isServiceValid("abort")) {
1566             try {
1567                 logOutgoing("abort %s", callId);
1568                 mServiceInterface.abort(callId, Log.getExternalSession(TELECOM_ABBREVIATION));
1569             } catch (RemoteException e) {
1570             }
1571         }
1572 
1573         removeCall(call, new DisconnectCause(DisconnectCause.LOCAL));
1574     }
1575 
1576     /** @see IConnectionService#silence(String, Session.Info) */
silence(Call call)1577     void silence(Call call) {
1578         final String callId = mCallIdMapper.getCallId(call);
1579         if (callId != null && isServiceValid("silence")) {
1580             try {
1581                 logOutgoing("silence %s", callId);
1582                 mServiceInterface.silence(callId, Log.getExternalSession(TELECOM_ABBREVIATION));
1583             } catch (RemoteException e) {
1584             }
1585         }
1586     }
1587 
1588     /** @see IConnectionService#hold(String, Session.Info) */
hold(Call call)1589     void hold(Call call) {
1590         final String callId = mCallIdMapper.getCallId(call);
1591         if (callId != null && isServiceValid("hold")) {
1592             try {
1593                 logOutgoing("hold %s", callId);
1594                 mServiceInterface.hold(callId, Log.getExternalSession(TELECOM_ABBREVIATION));
1595             } catch (RemoteException e) {
1596             }
1597         }
1598     }
1599 
1600     /** @see IConnectionService#unhold(String, Session.Info) */
unhold(Call call)1601     void unhold(Call call) {
1602         final String callId = mCallIdMapper.getCallId(call);
1603         if (callId != null && isServiceValid("unhold")) {
1604             try {
1605                 logOutgoing("unhold %s", callId);
1606                 mServiceInterface.unhold(callId, Log.getExternalSession(TELECOM_ABBREVIATION));
1607             } catch (RemoteException e) {
1608             }
1609         }
1610     }
1611 
1612     /** @see IConnectionService#onCallAudioStateChanged(String, CallAudioState, Session.Info) */
1613     @VisibleForTesting
onCallAudioStateChanged(Call activeCall, CallAudioState audioState)1614     public void onCallAudioStateChanged(Call activeCall, CallAudioState audioState) {
1615         final String callId = mCallIdMapper.getCallId(activeCall);
1616         if (callId != null && isServiceValid("onCallAudioStateChanged")) {
1617             try {
1618                 logOutgoing("onCallAudioStateChanged %s %s", callId, audioState);
1619                 mServiceInterface.onCallAudioStateChanged(callId, audioState,
1620                         Log.getExternalSession(TELECOM_ABBREVIATION));
1621             } catch (RemoteException e) {
1622             }
1623         }
1624     }
1625 
1626     /** @see IConnectionService#onUsingAlternativeUi(String, boolean, Session.Info) */
1627     @VisibleForTesting
onUsingAlternativeUi(Call activeCall, boolean isUsingAlternativeUi)1628     public void onUsingAlternativeUi(Call activeCall, boolean isUsingAlternativeUi) {
1629         final String callId = mCallIdMapper.getCallId(activeCall);
1630         if (callId != null && isServiceValid("onUsingAlternativeUi")) {
1631             try {
1632                 logOutgoing("onUsingAlternativeUi %s", isUsingAlternativeUi);
1633                 mServiceInterface.onUsingAlternativeUi(callId, isUsingAlternativeUi,
1634                         Log.getExternalSession(TELECOM_ABBREVIATION));
1635             } catch (RemoteException e) {
1636             }
1637         }
1638     }
1639 
1640     /** @see IConnectionService#onTrackedByNonUiService(String, boolean, Session.Info) */
1641     @VisibleForTesting
onTrackedByNonUiService(Call activeCall, boolean isTracked)1642     public void onTrackedByNonUiService(Call activeCall, boolean isTracked) {
1643         final String callId = mCallIdMapper.getCallId(activeCall);
1644         if (callId != null && isServiceValid("onTrackedByNonUiService")) {
1645             try {
1646                 logOutgoing("onTrackedByNonUiService %s", isTracked);
1647                 mServiceInterface.onTrackedByNonUiService(callId, isTracked,
1648                         Log.getExternalSession(TELECOM_ABBREVIATION));
1649             } catch (RemoteException e) {
1650             }
1651         }
1652     }
1653 
1654     /** @see IConnectionService#disconnect(String, Session.Info) */
disconnect(Call call)1655     void disconnect(Call call) {
1656         final String callId = mCallIdMapper.getCallId(call);
1657         if (callId != null && isServiceValid("disconnect")) {
1658             try {
1659                 logOutgoing("disconnect %s", callId);
1660                 mServiceInterface.disconnect(callId, Log.getExternalSession(TELECOM_ABBREVIATION));
1661             } catch (RemoteException e) {
1662             }
1663         }
1664     }
1665 
1666     /** @see IConnectionService#answer(String, Session.Info) */
answer(Call call, int videoState)1667     void answer(Call call, int videoState) {
1668         final String callId = mCallIdMapper.getCallId(call);
1669         if (callId != null && isServiceValid("answer")) {
1670             try {
1671                 logOutgoing("answer %s %d", callId, videoState);
1672                 if (VideoProfile.isAudioOnly(videoState)) {
1673                     mServiceInterface.answer(callId, Log.getExternalSession(TELECOM_ABBREVIATION));
1674                 } else {
1675                     mServiceInterface.answerVideo(callId, videoState,
1676                             Log.getExternalSession(TELECOM_ABBREVIATION));
1677                 }
1678             } catch (RemoteException e) {
1679             }
1680         }
1681     }
1682 
1683     /** @see IConnectionService#deflect(String, Uri , Session.Info) */
deflect(Call call, Uri address)1684     void deflect(Call call, Uri address) {
1685         final String callId = mCallIdMapper.getCallId(call);
1686         if (callId != null && isServiceValid("deflect")) {
1687             try {
1688                 logOutgoing("deflect %s", callId);
1689                 mServiceInterface.deflect(callId, address,
1690                         Log.getExternalSession(TELECOM_ABBREVIATION));
1691             } catch (RemoteException e) {
1692             }
1693         }
1694     }
1695 
1696     /** @see IConnectionService#reject(String, Session.Info) */
reject(Call call, boolean rejectWithMessage, String message)1697     void reject(Call call, boolean rejectWithMessage, String message) {
1698         final String callId = mCallIdMapper.getCallId(call);
1699         if (callId != null && isServiceValid("reject")) {
1700             try {
1701                 logOutgoing("reject %s", callId);
1702 
1703                 if (rejectWithMessage && call.can(
1704                         Connection.CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION)) {
1705                     mServiceInterface.rejectWithMessage(callId, message,
1706                             Log.getExternalSession(TELECOM_ABBREVIATION));
1707                 } else {
1708                     mServiceInterface.reject(callId, Log.getExternalSession(TELECOM_ABBREVIATION));
1709                 }
1710             } catch (RemoteException e) {
1711             }
1712         }
1713     }
1714 
1715     /** @see IConnectionService#reject(String, Session.Info) */
rejectWithReason(Call call, @android.telecom.Call.RejectReason int rejectReason)1716     void rejectWithReason(Call call, @android.telecom.Call.RejectReason int rejectReason) {
1717         final String callId = mCallIdMapper.getCallId(call);
1718         if (callId != null && isServiceValid("rejectReason")) {
1719             try {
1720                 logOutgoing("rejectReason %s, %d", callId, rejectReason);
1721 
1722                 mServiceInterface.rejectWithReason(callId, rejectReason,
1723                         Log.getExternalSession(TELECOM_ABBREVIATION));
1724             } catch (RemoteException e) {
1725             }
1726         }
1727     }
1728 
1729     /** @see IConnectionService#transfer(String, Uri , boolean, Session.Info) */
transfer(Call call, Uri number, boolean isConfirmationRequired)1730     void transfer(Call call, Uri number, boolean isConfirmationRequired) {
1731         final String callId = mCallIdMapper.getCallId(call);
1732         if (callId != null && isServiceValid("transfer")) {
1733             try {
1734                 logOutgoing("transfer %s", callId);
1735                 mServiceInterface.transfer(callId, number, isConfirmationRequired,
1736                         Log.getExternalSession(TELECOM_ABBREVIATION));
1737             } catch (RemoteException e) {
1738             }
1739         }
1740     }
1741 
1742     /** @see IConnectionService#consultativeTransfer(String, String, Session.Info) */
transfer(Call call, Call otherCall)1743     void transfer(Call call, Call otherCall) {
1744         final String callId = mCallIdMapper.getCallId(call);
1745         final String otherCallId = mCallIdMapper.getCallId(otherCall);
1746         if (callId != null && otherCallId != null && isServiceValid("consultativeTransfer")) {
1747             try {
1748                 logOutgoing("consultativeTransfer %s", callId);
1749                 mServiceInterface.consultativeTransfer(callId, otherCallId,
1750                         Log.getExternalSession(TELECOM_ABBREVIATION));
1751             } catch (RemoteException e) {
1752             }
1753         }
1754     }
1755 
1756     /** @see IConnectionService#playDtmfTone(String, char, Session.Info) */
playDtmfTone(Call call, char digit)1757     void playDtmfTone(Call call, char digit) {
1758         final String callId = mCallIdMapper.getCallId(call);
1759         if (callId != null && isServiceValid("playDtmfTone")) {
1760             try {
1761                 logOutgoing("playDtmfTone %s %c", callId, digit);
1762                 mServiceInterface.playDtmfTone(callId, digit,
1763                         Log.getExternalSession(TELECOM_ABBREVIATION));
1764             } catch (RemoteException e) {
1765             }
1766         }
1767     }
1768 
1769     /** @see IConnectionService#stopDtmfTone(String, Session.Info) */
stopDtmfTone(Call call)1770     void stopDtmfTone(Call call) {
1771         final String callId = mCallIdMapper.getCallId(call);
1772         if (callId != null && isServiceValid("stopDtmfTone")) {
1773             try {
1774                 logOutgoing("stopDtmfTone %s", callId);
1775                 mServiceInterface.stopDtmfTone(callId,
1776                         Log.getExternalSession(TELECOM_ABBREVIATION));
1777             } catch (RemoteException e) {
1778             }
1779         }
1780     }
1781 
addCall(Call call)1782     void addCall(Call call) {
1783         if (mCallIdMapper.getCallId(call) == null) {
1784             mCallIdMapper.addCall(call);
1785         }
1786     }
1787 
1788     /**
1789      * Associates newCall with this connection service by replacing callToReplace.
1790      */
replaceCall(Call newCall, Call callToReplace)1791     void replaceCall(Call newCall, Call callToReplace) {
1792         Preconditions.checkState(callToReplace.getConnectionService() == this);
1793         mCallIdMapper.replaceCall(newCall, callToReplace);
1794     }
1795 
removeCall(Call call)1796     void removeCall(Call call) {
1797         removeCall(call, new DisconnectCause(DisconnectCause.ERROR));
1798     }
1799 
removeCall(String callId, DisconnectCause disconnectCause)1800     void removeCall(String callId, DisconnectCause disconnectCause) {
1801         CreateConnectionResponse response = mPendingResponses.remove(callId);
1802         if (response != null) {
1803             response.handleCreateConnectionFailure(disconnectCause);
1804         }
1805 
1806         mCallIdMapper.removeCall(callId);
1807     }
1808 
removeCall(Call call, DisconnectCause disconnectCause)1809     void removeCall(Call call, DisconnectCause disconnectCause) {
1810         CreateConnectionResponse response = mPendingResponses.remove(mCallIdMapper.getCallId(call));
1811         if (response != null) {
1812             response.handleCreateConnectionFailure(disconnectCause);
1813         }
1814 
1815         mCallIdMapper.removeCall(call);
1816     }
1817 
onPostDialContinue(Call call, boolean proceed)1818     void onPostDialContinue(Call call, boolean proceed) {
1819         final String callId = mCallIdMapper.getCallId(call);
1820         if (callId != null && isServiceValid("onPostDialContinue")) {
1821             try {
1822                 logOutgoing("onPostDialContinue %s %b", callId, proceed);
1823                 mServiceInterface.onPostDialContinue(callId, proceed,
1824                         Log.getExternalSession(TELECOM_ABBREVIATION));
1825             } catch (RemoteException ignored) {
1826             }
1827         }
1828     }
1829 
conference(final Call call, Call otherCall)1830     void conference(final Call call, Call otherCall) {
1831         final String callId = mCallIdMapper.getCallId(call);
1832         final String otherCallId = mCallIdMapper.getCallId(otherCall);
1833         if (callId != null && otherCallId != null && isServiceValid("conference")) {
1834             try {
1835                 logOutgoing("conference %s %s", callId, otherCallId);
1836                 mServiceInterface.conference(callId, otherCallId,
1837                         Log.getExternalSession(TELECOM_ABBREVIATION));
1838             } catch (RemoteException ignored) {
1839             }
1840         }
1841     }
1842 
splitFromConference(Call call)1843     void splitFromConference(Call call) {
1844         final String callId = mCallIdMapper.getCallId(call);
1845         if (callId != null && isServiceValid("splitFromConference")) {
1846             try {
1847                 logOutgoing("splitFromConference %s", callId);
1848                 mServiceInterface.splitFromConference(callId,
1849                         Log.getExternalSession(TELECOM_ABBREVIATION));
1850             } catch (RemoteException ignored) {
1851             }
1852         }
1853     }
1854 
mergeConference(Call call)1855     void mergeConference(Call call) {
1856         final String callId = mCallIdMapper.getCallId(call);
1857         if (callId != null && isServiceValid("mergeConference")) {
1858             try {
1859                 logOutgoing("mergeConference %s", callId);
1860                 mServiceInterface.mergeConference(callId,
1861                         Log.getExternalSession(TELECOM_ABBREVIATION));
1862             } catch (RemoteException ignored) {
1863             }
1864         }
1865     }
1866 
swapConference(Call call)1867     void swapConference(Call call) {
1868         final String callId = mCallIdMapper.getCallId(call);
1869         if (callId != null && isServiceValid("swapConference")) {
1870             try {
1871                 logOutgoing("swapConference %s", callId);
1872                 mServiceInterface.swapConference(callId,
1873                         Log.getExternalSession(TELECOM_ABBREVIATION));
1874             } catch (RemoteException ignored) {
1875             }
1876         }
1877     }
1878 
addConferenceParticipants(Call call, List<Uri> participants)1879     void addConferenceParticipants(Call call, List<Uri> participants) {
1880         final String callId = mCallIdMapper.getCallId(call);
1881         if (callId != null && isServiceValid("addConferenceParticipants")) {
1882             try {
1883                 logOutgoing("addConferenceParticipants %s", callId);
1884                 mServiceInterface.addConferenceParticipants(callId, participants,
1885                         Log.getExternalSession(TELECOM_ABBREVIATION));
1886             } catch (RemoteException ignored) {
1887             }
1888         }
1889     }
1890 
1891     @VisibleForTesting
pullExternalCall(Call call)1892     public void pullExternalCall(Call call) {
1893         final String callId = mCallIdMapper.getCallId(call);
1894         if (callId != null && isServiceValid("pullExternalCall")) {
1895             try {
1896                 logOutgoing("pullExternalCall %s", callId);
1897                 mServiceInterface.pullExternalCall(callId,
1898                         Log.getExternalSession(TELECOM_ABBREVIATION));
1899             } catch (RemoteException ignored) {
1900             }
1901         }
1902     }
1903 
sendCallEvent(Call call, String event, Bundle extras)1904     void sendCallEvent(Call call, String event, Bundle extras) {
1905         final String callId = mCallIdMapper.getCallId(call);
1906         if (callId != null && isServiceValid("sendCallEvent")) {
1907             try {
1908                 logOutgoing("sendCallEvent %s %s", callId, event);
1909                 mServiceInterface.sendCallEvent(callId, event, extras,
1910                         Log.getExternalSession(TELECOM_ABBREVIATION));
1911             } catch (RemoteException ignored) {
1912             }
1913         }
1914     }
1915 
onCallFilteringCompleted(Call call, Connection.CallFilteringCompletionInfo completionInfo)1916     void onCallFilteringCompleted(Call call,
1917             Connection.CallFilteringCompletionInfo completionInfo) {
1918         final String callId = mCallIdMapper.getCallId(call);
1919         if (callId != null && isServiceValid("onCallFilteringCompleted")) {
1920             try {
1921                 logOutgoing("onCallFilteringCompleted %s", completionInfo);
1922                 int contactsPermission = mContext.getPackageManager()
1923                         .checkPermission(Manifest.permission.READ_CONTACTS,
1924                                 getComponentName().getPackageName());
1925                 if (contactsPermission == PackageManager.PERMISSION_GRANTED) {
1926                     mServiceInterface.onCallFilteringCompleted(callId, completionInfo,
1927                             Log.getExternalSession(TELECOM_ABBREVIATION));
1928                 } else {
1929                     logOutgoing("Skipping call filtering complete message for %s due"
1930                             + " to lack of READ_CONTACTS", getComponentName().getPackageName());
1931                 }
1932             } catch (RemoteException e) {
1933                 Log.e(this, e, "Remote exception calling onCallFilteringCompleted");
1934             }
1935         }
1936     }
1937 
onExtrasChanged(Call call, Bundle extras)1938     void onExtrasChanged(Call call, Bundle extras) {
1939         final String callId = mCallIdMapper.getCallId(call);
1940         if (callId != null && isServiceValid("onExtrasChanged")) {
1941             try {
1942                 logOutgoing("onExtrasChanged %s %s", callId, extras);
1943                 mServiceInterface.onExtrasChanged(callId, extras,
1944                         Log.getExternalSession(TELECOM_ABBREVIATION));
1945             } catch (RemoteException ignored) {
1946             }
1947         }
1948     }
1949 
startRtt(Call call, ParcelFileDescriptor fromInCall, ParcelFileDescriptor toInCall)1950     void startRtt(Call call, ParcelFileDescriptor fromInCall, ParcelFileDescriptor toInCall) {
1951         final String callId = mCallIdMapper.getCallId(call);
1952         if (callId != null && isServiceValid("startRtt")) {
1953             try {
1954                 logOutgoing("startRtt: %s %s %s", callId, fromInCall, toInCall);
1955                 mServiceInterface.startRtt(callId, fromInCall, toInCall,
1956                         Log.getExternalSession(TELECOM_ABBREVIATION));
1957             } catch (RemoteException ignored) {
1958             }
1959         }
1960     }
1961 
stopRtt(Call call)1962     void stopRtt(Call call) {
1963         final String callId = mCallIdMapper.getCallId(call);
1964         if (callId != null && isServiceValid("stopRtt")) {
1965             try {
1966                 logOutgoing("stopRtt: %s", callId);
1967                 mServiceInterface.stopRtt(callId, Log.getExternalSession(TELECOM_ABBREVIATION));
1968             } catch (RemoteException ignored) {
1969             }
1970         }
1971     }
1972 
respondToRttRequest( Call call, ParcelFileDescriptor fromInCall, ParcelFileDescriptor toInCall)1973     void respondToRttRequest(
1974             Call call, ParcelFileDescriptor fromInCall, ParcelFileDescriptor toInCall) {
1975         final String callId = mCallIdMapper.getCallId(call);
1976         if (callId != null && isServiceValid("respondToRttRequest")) {
1977             try {
1978                 logOutgoing("respondToRttRequest: %s %s %s", callId, fromInCall, toInCall);
1979                 mServiceInterface.respondToRttUpgradeRequest(
1980                         callId, fromInCall, toInCall, Log.getExternalSession(TELECOM_ABBREVIATION));
1981             } catch (RemoteException ignored) {
1982             }
1983         }
1984     }
1985 
1986     /** {@inheritDoc} */
1987     @Override
setServiceInterface(IBinder binder)1988     protected void setServiceInterface(IBinder binder) {
1989         mServiceInterface = IConnectionService.Stub.asInterface(binder);
1990         Log.v(this, "Adding Connection Service Adapter.");
1991         addConnectionServiceAdapter(mAdapter);
1992     }
1993 
1994     /** {@inheritDoc} */
1995     @Override
removeServiceInterface()1996     protected void removeServiceInterface() {
1997         Log.v(this, "Removing Connection Service Adapter.");
1998         removeConnectionServiceAdapter(mAdapter);
1999         // We have lost our service connection. Notify the world that this service is done.
2000         // We must notify the adapter before CallsManager. The adapter will force any pending
2001         // outgoing calls to try the next service. This needs to happen before CallsManager
2002         // tries to clean up any calls still associated with this service.
2003         handleConnectionServiceDeath();
2004         mCallsManager.handleConnectionServiceDeath(this);
2005         mServiceInterface = null;
2006     }
2007 
2008     @Override
connectionServiceFocusLost()2009     public void connectionServiceFocusLost() {
2010         // Immediately response to the Telecom that it has released the call resources.
2011         // TODO(mpq): Change back to the default implementation once b/69651192 done.
2012         if (mConnSvrFocusListener != null) {
2013             mConnSvrFocusListener.onConnectionServiceReleased(ConnectionServiceWrapper.this);
2014         }
2015         BindCallback callback = new BindCallback() {
2016             @Override
2017             public void onSuccess() {
2018                 try {
2019                     mServiceInterface.connectionServiceFocusLost(
2020                             Log.getExternalSession(TELECOM_ABBREVIATION));
2021                 } catch (RemoteException ignored) {
2022                     Log.d(this, "failed to inform the focus lost event");
2023                 }
2024             }
2025 
2026             @Override
2027             public void onFailure() {}
2028         };
2029         mBinder.bind(callback, null /* null call */);
2030     }
2031 
2032     @Override
connectionServiceFocusGained()2033     public void connectionServiceFocusGained() {
2034         BindCallback callback = new BindCallback() {
2035             @Override
2036             public void onSuccess() {
2037                 try {
2038                     mServiceInterface.connectionServiceFocusGained(
2039                             Log.getExternalSession(TELECOM_ABBREVIATION));
2040                 } catch (RemoteException ignored) {
2041                     Log.d(this, "failed to inform the focus gained event");
2042                 }
2043             }
2044 
2045             @Override
2046             public void onFailure() {}
2047         };
2048         mBinder.bind(callback, null /* null call */);
2049     }
2050 
2051     @Override
setConnectionServiceFocusListener( ConnectionServiceFocusManager.ConnectionServiceFocusListener listener)2052     public void setConnectionServiceFocusListener(
2053             ConnectionServiceFocusManager.ConnectionServiceFocusListener listener) {
2054         mConnSvrFocusListener = listener;
2055     }
2056 
handleCreateConnectionComplete( String callId, ConnectionRequest request, ParcelableConnection connection)2057     private void handleCreateConnectionComplete(
2058             String callId,
2059             ConnectionRequest request,
2060             ParcelableConnection connection) {
2061         // TODO: Note we are not using parameter "request", which is a side effect of our tacit
2062         // assumption that we have at most one outgoing connection attempt per ConnectionService.
2063         // This may not continue to be the case.
2064         if (connection.getState() == Connection.STATE_DISCONNECTED) {
2065             // A connection that begins in the DISCONNECTED state is an indication of
2066             // failure to connect; we handle all failures uniformly
2067             Call foundCall = mCallIdMapper.getCall(callId);
2068 
2069             if (connection.getConnectTimeMillis() != 0) {
2070                 foundCall.setConnectTimeMillis(connection.getConnectTimeMillis());
2071             }
2072 
2073             if (foundCall != null) {
2074                 // The post-dial digits are created when the call is first created.  Normally
2075                 // the ConnectionService is responsible for stripping them from the address, but
2076                 // since a failed connection will not have done this, we could end up with duplicate
2077                 // post-dial digits.
2078                 foundCall.clearPostDialDigits();
2079             }
2080             removeCall(callId, connection.getDisconnectCause());
2081         } else {
2082             // Successful connection
2083             if (mPendingResponses.containsKey(callId)) {
2084                 mPendingResponses.remove(callId)
2085                         .handleCreateConnectionSuccess(mCallIdMapper, connection);
2086             }
2087         }
2088     }
2089 
handleCreateConferenceComplete( String callId, ConnectionRequest request, ParcelableConference conference)2090     private void handleCreateConferenceComplete(
2091             String callId,
2092             ConnectionRequest request,
2093             ParcelableConference conference) {
2094         // TODO: Note we are not using parameter "request", which is a side effect of our tacit
2095         // assumption that we have at most one outgoing conference attempt per ConnectionService.
2096         // This may not continue to be the case.
2097         if (conference.getState() == Connection.STATE_DISCONNECTED) {
2098             // A conference that begins in the DISCONNECTED state is an indication of
2099             // failure to connect; we handle all failures uniformly
2100             removeCall(callId, conference.getDisconnectCause());
2101         } else {
2102             // Successful connection
2103             if (mPendingResponses.containsKey(callId)) {
2104                 mPendingResponses.remove(callId)
2105                         .handleCreateConferenceSuccess(mCallIdMapper, conference);
2106             }
2107         }
2108     }
2109 
2110     /**
2111      * Called when the associated connection service dies.
2112      */
handleConnectionServiceDeath()2113     private void handleConnectionServiceDeath() {
2114         if (!mPendingResponses.isEmpty()) {
2115             CreateConnectionResponse[] responses = mPendingResponses.values().toArray(
2116                     new CreateConnectionResponse[mPendingResponses.values().size()]);
2117             mPendingResponses.clear();
2118             for (int i = 0; i < responses.length; i++) {
2119                 responses[i].handleCreateConnectionFailure(
2120                         new DisconnectCause(DisconnectCause.ERROR, "CS_DEATH"));
2121             }
2122         }
2123         mCallIdMapper.clear();
2124 
2125         if (mConnSvrFocusListener != null) {
2126             mConnSvrFocusListener.onConnectionServiceDeath(this);
2127         }
2128     }
2129 
logIncoming(String msg, Object... params)2130     private void logIncoming(String msg, Object... params) {
2131         // Keep these as debug; the incoming logging is traced on a package level through the
2132         // session logging.
2133         Log.d(this, "CS -> TC[" + Log.getPackageAbbreviation(mComponentName) + "]: "
2134                 + msg, params);
2135     }
2136 
logOutgoing(String msg, Object... params)2137     private void logOutgoing(String msg, Object... params) {
2138         Log.d(this, "TC -> CS[" + Log.getPackageAbbreviation(mComponentName) + "]: "
2139                 + msg, params);
2140     }
2141 
queryRemoteConnectionServices(final UserHandle userHandle, final String callingPackage, final RemoteServiceCallback callback)2142     private void queryRemoteConnectionServices(final UserHandle userHandle,
2143             final String callingPackage, final RemoteServiceCallback callback) {
2144         boolean isCallerConnectionManager = false;
2145         // For each Sim ConnectionService, use its subid to find the correct connection manager for
2146         // that ConnectionService; return those Sim ConnectionServices which match the connection
2147         // manager.
2148         final Set<ConnectionServiceWrapper> simServices = Collections.newSetFromMap(
2149                 new ConcurrentHashMap<ConnectionServiceWrapper, Boolean>(8, 0.9f, 1));
2150         for (PhoneAccountHandle handle : mPhoneAccountRegistrar.getSimPhoneAccounts(userHandle)) {
2151             int subId = mPhoneAccountRegistrar.getSubscriptionIdForPhoneAccount(handle);
2152             PhoneAccountHandle connectionMgrHandle = mPhoneAccountRegistrar.getSimCallManager(subId,
2153                     userHandle);
2154             if (connectionMgrHandle == null
2155                     || !connectionMgrHandle.getComponentName().getPackageName().equals(
2156                             callingPackage)) {
2157                 Log.v(this, "queryRemoteConnectionServices: callingPackage=%s skipped; "
2158                                 + "doesn't match mgr %s for tfa %s",
2159                         callingPackage, connectionMgrHandle, handle);
2160             } else {
2161                 isCallerConnectionManager = true;
2162             }
2163             ConnectionServiceWrapper service = mConnectionServiceRepository.getService(
2164                     handle.getComponentName(), handle.getUserHandle());
2165             if (service != null && service != this) {
2166                 simServices.add(service);
2167             } else {
2168                 // This is unexpected, normally PhoneAccounts with CAPABILITY_CALL_PROVIDER are not
2169                 // also CAPABILITY_CONNECTION_MANAGER
2170                 Log.w(this, "call provider also detected as SIM call manager: " + service);
2171             }
2172         }
2173 
2174         // Bail early if the caller isn't the sim connection mgr.
2175         if (!isCallerConnectionManager) {
2176             Log.d(this, "queryRemoteConnectionServices: none; not sim call mgr.");
2177             noRemoteServices(callback);
2178             return;
2179         }
2180 
2181         final List<ComponentName> simServiceComponentNames = new ArrayList<>();
2182         final List<IBinder> simServiceBinders = new ArrayList<>();
2183 
2184         Log.i(this, "queryRemoteConnectionServices, simServices = %s", simServices);
2185 
2186         for (ConnectionServiceWrapper simService : simServices) {
2187             final ConnectionServiceWrapper currentSimService = simService;
2188 
2189             currentSimService.mBinder.bind(new BindCallback() {
2190                 @Override
2191                 public void onSuccess() {
2192                     Log.d(this, "queryRemoteConnectionServices: Adding simService %s",
2193                             currentSimService.getComponentName());
2194                     if (currentSimService.mServiceInterface == null) {
2195                         // The remote ConnectionService died, so do not add it.
2196                         // We will still perform maybeComplete() and notify the caller with an empty
2197                         // list of sim services via maybeComplete().
2198                         Log.w(this, "queryRemoteConnectionServices: simService %s died - Skipping.",
2199                                 currentSimService.getComponentName());
2200                     } else {
2201                         simServiceComponentNames.add(currentSimService.getComponentName());
2202                         simServiceBinders.add(currentSimService.mServiceInterface.asBinder());
2203                     }
2204                     maybeComplete();
2205                 }
2206 
2207                 @Override
2208                 public void onFailure() {
2209                     Log.d(this, "queryRemoteConnectionServices: Failed simService %s",
2210                             currentSimService.getComponentName());
2211                     // We know maybeComplete() will always be a no-op from now on, so go ahead and
2212                     // signal failure of the entire request
2213                     noRemoteServices(callback);
2214                 }
2215 
2216                 private void maybeComplete() {
2217                     if (simServiceComponentNames.size() == simServices.size()) {
2218                         setRemoteServices(callback, simServiceComponentNames, simServiceBinders);
2219                     }
2220                 }
2221             }, null);
2222         }
2223     }
2224 
setRemoteServices( RemoteServiceCallback callback, List<ComponentName> componentNames, List<IBinder> binders)2225     private void setRemoteServices(
2226             RemoteServiceCallback callback,
2227             List<ComponentName> componentNames,
2228             List<IBinder> binders) {
2229         try {
2230             callback.onResult(componentNames, binders);
2231         } catch (RemoteException e) {
2232             Log.e(this, e, "setRemoteServices: Contacting ConnectionService %s",
2233                     ConnectionServiceWrapper.this.getComponentName());
2234         }
2235     }
2236 
noRemoteServices(RemoteServiceCallback callback)2237     private void noRemoteServices(RemoteServiceCallback callback) {
2238         setRemoteServices(callback, Collections.EMPTY_LIST, Collections.EMPTY_LIST);
2239     }
2240 
2241     @Override
toString()2242     public String toString() {
2243         StringBuilder sb = new StringBuilder();
2244         sb.append("[ConnectionServiceWrapper componentName=");
2245         sb.append(mComponentName);
2246         sb.append("]");
2247         return sb.toString();
2248     }
2249 }
2250