• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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                         // Check to see if this Connection has already been added.
924                         Call alreadyAddedConnection = mCallsManager
925                                 .getAlreadyAddedConnection(connectIdToCheck);
926 
927                         if (alreadyAddedConnection != null
928                                 && mCallIdMapper.getCall(callId) == null) {
929                             mCallIdMapper.addCall(alreadyAddedConnection, callId);
930                             alreadyAddedConnection
931                                     .replaceConnectionService(ConnectionServiceWrapper.this);
932                             return;
933                         }
934 
935                         Call existingCall = mCallsManager
936                                 .createCallForExistingConnection(callId, connection);
937                         mCallIdMapper.addCall(existingCall, callId);
938                         existingCall.setConnectionService(ConnectionServiceWrapper.this);
939                     } else {
940                         Log.e(this, new RemoteException("The PhoneAccount being used is not " +
941                                 "currently registered with Telecom."), "Unable to " +
942                                 "addExistingConnection.");
943                     }
944                 }
945             } catch (Throwable t) {
946                 Log.e(ConnectionServiceWrapper.this, t, "");
947                 throw t;
948             } finally {
949                 Binder.restoreCallingIdentity(token);
950                 Log.endSession();
951             }
952         }
953 
954         @Override
onConnectionEvent(String callId, String event, Bundle extras, Session.Info sessionInfo)955         public void onConnectionEvent(String callId, String event, Bundle extras,
956                 Session.Info sessionInfo) {
957             Log.startSession(sessionInfo, "CSW.oCE", mPackageAbbreviation);
958             long token = Binder.clearCallingIdentity();
959             try {
960                 synchronized (mLock) {
961                     Bundle.setDefusable(extras, true);
962                     Call call = mCallIdMapper.getCall(callId);
963                     if (call != null) {
964                         call.onConnectionEvent(event, extras);
965                     }
966                 }
967             } catch (Throwable t) {
968                 Log.e(ConnectionServiceWrapper.this, t, "");
969                 throw t;
970             } finally {
971                 Binder.restoreCallingIdentity(token);
972                 Log.endSession();
973             }
974         }
975 
976         @Override
onRttInitiationSuccess(String callId, Session.Info sessionInfo)977         public void onRttInitiationSuccess(String callId, Session.Info sessionInfo)
978                 throws RemoteException {
979 
980         }
981 
982         @Override
onRttInitiationFailure(String callId, int reason, Session.Info sessionInfo)983         public void onRttInitiationFailure(String callId, int reason, Session.Info sessionInfo)
984                 throws RemoteException {
985             Log.startSession(sessionInfo, "CSW.oRIF", mPackageAbbreviation);
986             long token = Binder.clearCallingIdentity();
987             try {
988                 synchronized (mLock) {
989                     Call call = mCallIdMapper.getCall(callId);
990                     if (call != null) {
991                         call.onRttConnectionFailure(reason);
992                     }
993                 }
994             } catch (Throwable t) {
995                 Log.e(ConnectionServiceWrapper.this, t, "");
996                 throw t;
997             } finally {
998                 Binder.restoreCallingIdentity(token);
999                 Log.endSession();
1000             }
1001         }
1002 
1003         @Override
onRttSessionRemotelyTerminated(String callId, Session.Info sessionInfo)1004         public void onRttSessionRemotelyTerminated(String callId, Session.Info sessionInfo)
1005                 throws RemoteException {
1006 
1007         }
1008 
1009         @Override
onRemoteRttRequest(String callId, Session.Info sessionInfo)1010         public void onRemoteRttRequest(String callId, Session.Info sessionInfo)
1011                 throws RemoteException {
1012             Log.startSession(sessionInfo, "CSW.oRRR", mPackageAbbreviation);
1013             long token = Binder.clearCallingIdentity();
1014             try {
1015                 synchronized (mLock) {
1016                     Call call = mCallIdMapper.getCall(callId);
1017                     if (call != null) {
1018                         call.onRemoteRttRequest();
1019                     }
1020                 }
1021             } catch (Throwable t) {
1022                 Log.e(ConnectionServiceWrapper.this, t, "");
1023                 throw t;
1024             } finally {
1025                 Binder.restoreCallingIdentity(token);
1026                 Log.endSession();
1027             }
1028         }
1029 
1030         @Override
onPhoneAccountChanged(String callId, PhoneAccountHandle pHandle, Session.Info sessionInfo)1031         public void onPhoneAccountChanged(String callId, PhoneAccountHandle pHandle,
1032                 Session.Info sessionInfo) throws RemoteException {
1033             // Check that the Calling Package matches PhoneAccountHandle's Component Package
1034             if (pHandle != null) {
1035                 mAppOpsManager.checkPackage(Binder.getCallingUid(),
1036                         pHandle.getComponentName().getPackageName());
1037             }
1038             Log.startSession(sessionInfo, "CSW.oPAC", mPackageAbbreviation);
1039             long token = Binder.clearCallingIdentity();
1040             try {
1041                 synchronized (mLock) {
1042                     Call call = mCallIdMapper.getCall(callId);
1043                     if (call != null) {
1044                         call.setTargetPhoneAccount(pHandle);
1045                     }
1046                 }
1047             } catch (Throwable t) {
1048                 Log.e(ConnectionServiceWrapper.this, t, "");
1049                 throw t;
1050             } finally {
1051                 Binder.restoreCallingIdentity(token);
1052                 Log.endSession();
1053             }
1054         }
1055 
1056         @Override
onConnectionServiceFocusReleased(Session.Info sessionInfo)1057         public void onConnectionServiceFocusReleased(Session.Info sessionInfo)
1058                 throws RemoteException {
1059             Log.startSession(sessionInfo, "CSW.oCSFR", mPackageAbbreviation);
1060             long token = Binder.clearCallingIdentity();
1061             try {
1062                 synchronized (mLock) {
1063                     mConnSvrFocusListener.onConnectionServiceReleased(
1064                             ConnectionServiceWrapper.this);
1065                 }
1066             } catch (Throwable t) {
1067                 Log.e(ConnectionServiceWrapper.this, t, "");
1068                 throw t;
1069             } finally {
1070                 Binder.restoreCallingIdentity(token);
1071                 Log.endSession();
1072             }
1073         }
1074 
1075         @Override
setConferenceState(String callId, boolean isConference, Session.Info sessionInfo)1076         public void setConferenceState(String callId, boolean isConference,
1077                 Session.Info sessionInfo) throws RemoteException {
1078             Log.startSession(sessionInfo, "CSW.sCS", mPackageAbbreviation);
1079 
1080             if (mContext.checkCallingOrSelfPermission(MODIFY_PHONE_STATE)
1081                     != PackageManager.PERMISSION_GRANTED) {
1082                 Log.w(this, "setConferenceState from caller without permission.");
1083                 Log.endSession();
1084                 return;
1085             }
1086 
1087             long token = Binder.clearCallingIdentity();
1088             try {
1089                 synchronized (mLock) {
1090                     Call call = mCallIdMapper.getCall(callId);
1091                     if (call != null) {
1092                         call.setConferenceState(isConference);
1093                     }
1094                 }
1095             } catch (Throwable t) {
1096                 Log.e(ConnectionServiceWrapper.this, t, "");
1097                 throw t;
1098             } finally {
1099                 Binder.restoreCallingIdentity(token);
1100                 Log.endSession();
1101             }
1102         }
1103 
1104         @Override
setCallDirection(String callId, int direction, Session.Info sessionInfo)1105         public void setCallDirection(String callId, int direction, Session.Info sessionInfo) {
1106             Log.startSession(sessionInfo, "CSW.sCD", mPackageAbbreviation);
1107 
1108             if (mContext.checkCallingOrSelfPermission(MODIFY_PHONE_STATE)
1109                     != PackageManager.PERMISSION_GRANTED) {
1110                 Log.w(this, "setCallDirection from caller without permission.");
1111                 Log.endSession();
1112                 return;
1113             }
1114 
1115             long token = Binder.clearCallingIdentity();
1116             try {
1117                 synchronized (mLock) {
1118                     logIncoming("setCallDirection %s %d", callId, direction);
1119                     Call call = mCallIdMapper.getCall(callId);
1120                     if (call != null) {
1121                         call.setCallDirection(Call.getRemappedCallDirection(direction));
1122                     }
1123                 }
1124             } catch (Throwable t) {
1125                 Log.e(ConnectionServiceWrapper.this, t, "");
1126                 throw t;
1127             } finally {
1128                 Binder.restoreCallingIdentity(token);
1129                 Log.endSession();
1130             }
1131         }
1132     }
1133 
1134     private final Adapter mAdapter = new Adapter();
1135     private final CallIdMapper mCallIdMapper = new CallIdMapper(Call::getConnectionId);
1136     private final Map<String, CreateConnectionResponse> mPendingResponses = new HashMap<>();
1137 
1138     private Binder2 mBinder = new Binder2();
1139     private IConnectionService mServiceInterface;
1140     private final ConnectionServiceRepository mConnectionServiceRepository;
1141     private final PhoneAccountRegistrar mPhoneAccountRegistrar;
1142     private final CallsManager mCallsManager;
1143     private final AppOpsManager mAppOpsManager;
1144     private final Context mContext;
1145 
1146     private ConnectionServiceFocusManager.ConnectionServiceFocusListener mConnSvrFocusListener;
1147 
1148     /**
1149      * Creates a connection service.
1150      *
1151      * @param componentName The component name of the service with which to bind.
1152      * @param connectionServiceRepository Connection service repository.
1153      * @param phoneAccountRegistrar Phone account registrar
1154      * @param callsManager Calls manager
1155      * @param context The context.
1156      * @param userHandle The {@link UserHandle} to use when binding.
1157      */
ConnectionServiceWrapper( ComponentName componentName, ConnectionServiceRepository connectionServiceRepository, PhoneAccountRegistrar phoneAccountRegistrar, CallsManager callsManager, Context context, TelecomSystem.SyncRoot lock, UserHandle userHandle)1158     ConnectionServiceWrapper(
1159             ComponentName componentName,
1160             ConnectionServiceRepository connectionServiceRepository,
1161             PhoneAccountRegistrar phoneAccountRegistrar,
1162             CallsManager callsManager,
1163             Context context,
1164             TelecomSystem.SyncRoot lock,
1165             UserHandle userHandle) {
1166         super(ConnectionService.SERVICE_INTERFACE, componentName, context, lock, userHandle);
1167         mConnectionServiceRepository = connectionServiceRepository;
1168         phoneAccountRegistrar.addListener(new PhoneAccountRegistrar.Listener() {
1169             // TODO -- Upon changes to PhoneAccountRegistrar, need to re-wire connections
1170             // To do this, we must proxy remote ConnectionService objects
1171         });
1172         mPhoneAccountRegistrar = phoneAccountRegistrar;
1173         mCallsManager = callsManager;
1174         mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
1175         mContext = context;
1176     }
1177 
1178     /** See {@link IConnectionService#addConnectionServiceAdapter}. */
addConnectionServiceAdapter(IConnectionServiceAdapter adapter)1179     private void addConnectionServiceAdapter(IConnectionServiceAdapter adapter) {
1180         if (isServiceValid("addConnectionServiceAdapter")) {
1181             try {
1182                 logOutgoing("addConnectionServiceAdapter %s", adapter);
1183                 mServiceInterface.addConnectionServiceAdapter(adapter, Log.getExternalSession());
1184             } catch (RemoteException e) {
1185             }
1186         }
1187     }
1188 
1189     /** See {@link IConnectionService#removeConnectionServiceAdapter}. */
removeConnectionServiceAdapter(IConnectionServiceAdapter adapter)1190     private void removeConnectionServiceAdapter(IConnectionServiceAdapter adapter) {
1191         if (isServiceValid("removeConnectionServiceAdapter")) {
1192             try {
1193                 logOutgoing("removeConnectionServiceAdapter %s", adapter);
1194                 mServiceInterface.removeConnectionServiceAdapter(adapter, Log.getExternalSession());
1195             } catch (RemoteException e) {
1196             }
1197         }
1198     }
1199 
1200     /**
1201      * Creates a conference for a new outgoing call or attach to an existing incoming call.
1202      */
createConference(final Call call, final CreateConnectionResponse response)1203     public void createConference(final Call call, final CreateConnectionResponse response) {
1204         Log.d(this, "createConference(%s) via %s.", call, getComponentName());
1205         BindCallback callback = new BindCallback() {
1206             @Override
1207             public void onSuccess() {
1208                 String callId = mCallIdMapper.getCallId(call);
1209                 mPendingResponses.put(callId, response);
1210 
1211                 Bundle extras = call.getIntentExtras();
1212                 if (extras == null) {
1213                     extras = new Bundle();
1214                 }
1215                 extras.putString(Connection.EXTRA_ORIGINAL_CONNECTION_ID, callId);
1216 
1217                 Log.addEvent(call, LogUtils.Events.START_CONFERENCE,
1218                         Log.piiHandle(call.getHandle()));
1219 
1220                 ConnectionRequest connectionRequest = new ConnectionRequest.Builder()
1221                         .setAccountHandle(call.getTargetPhoneAccount())
1222                         .setAddress(call.getHandle())
1223                         .setExtras(extras)
1224                         .setVideoState(call.getVideoState())
1225                         .setTelecomCallId(callId)
1226                         // For self-managed incoming calls, if there is another ongoing call Telecom
1227                         // is responsible for showing a UI to ask the user if they'd like to answer
1228                         // this new incoming call.
1229                         .setShouldShowIncomingCallUi(
1230                                 !mCallsManager.shouldShowSystemIncomingCallUi(call))
1231                         .setRttPipeFromInCall(call.getInCallToCsRttPipeForCs())
1232                         .setRttPipeToInCall(call.getCsToInCallRttPipeForCs())
1233                         .setParticipants(call.getParticipants())
1234                         .setIsAdhocConferenceCall(call.isAdhocConferenceCall())
1235                         .build();
1236 
1237                 try {
1238                     mServiceInterface.createConference(
1239                             call.getConnectionManagerPhoneAccount(),
1240                             callId,
1241                             connectionRequest,
1242                             call.shouldAttachToExistingConnection(),
1243                             call.isUnknown(),
1244                             Log.getExternalSession(TELECOM_ABBREVIATION));
1245 
1246                 } catch (RemoteException e) {
1247                     Log.e(this, e, "Failure to createConference -- %s", getComponentName());
1248                     mPendingResponses.remove(callId).handleCreateConferenceFailure(
1249                             new DisconnectCause(DisconnectCause.ERROR, e.toString()));
1250                 }
1251             }
1252 
1253             @Override
1254             public void onFailure() {
1255                 Log.e(this, new Exception(), "Failure to conference %s", getComponentName());
1256                 response.handleCreateConferenceFailure(new DisconnectCause(DisconnectCause.ERROR));
1257             }
1258         };
1259 
1260         mBinder.bind(callback, call);
1261 
1262     }
1263 
1264     /**
1265      * Creates a new connection for a new outgoing call or to attach to an existing incoming call.
1266      */
1267     @VisibleForTesting
createConnection(final Call call, final CreateConnectionResponse response)1268     public void createConnection(final Call call, final CreateConnectionResponse response) {
1269         Log.i(this, "createConnection(%s) via %s.", call, getComponentName());
1270         BindCallback callback = new BindCallback() {
1271             @Override
1272             public void onSuccess() {
1273                 String callId = mCallIdMapper.getCallId(call);
1274                 if (callId == null) {
1275                     Log.w(ConnectionServiceWrapper.this, "Call not present"
1276                             + " in call id mapper, maybe it was aborted before the bind"
1277                             + " completed successfully?");
1278                     response.handleCreateConnectionFailure(
1279                             new DisconnectCause(DisconnectCause.CANCELED));
1280                     return;
1281                 }
1282                 mPendingResponses.put(callId, response);
1283 
1284                 GatewayInfo gatewayInfo = call.getGatewayInfo();
1285                 Bundle extras = call.getIntentExtras();
1286                 if (gatewayInfo != null && gatewayInfo.getGatewayProviderPackageName() != null &&
1287                         gatewayInfo.getOriginalAddress() != null) {
1288                     extras = (Bundle) extras.clone();
1289                     extras.putString(
1290                             TelecomManager.GATEWAY_PROVIDER_PACKAGE,
1291                             gatewayInfo.getGatewayProviderPackageName());
1292                     extras.putParcelable(
1293                             TelecomManager.GATEWAY_ORIGINAL_ADDRESS,
1294                             gatewayInfo.getOriginalAddress());
1295                 }
1296 
1297                 if (call.isIncoming() && mCallsManager.getEmergencyCallHelper()
1298                         .getLastEmergencyCallTimeMillis() > 0) {
1299                   // Add the last emergency call time to the connection request for incoming calls
1300                   if (extras == call.getIntentExtras()) {
1301                     extras = (Bundle) extras.clone();
1302                   }
1303                   extras.putLong(android.telecom.Call.EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS,
1304                       mCallsManager.getEmergencyCallHelper().getLastEmergencyCallTimeMillis());
1305                 }
1306 
1307                 // Call is incoming and added because we're handing over from another; tell CS
1308                 // that its expected to handover.
1309                 if (call.isIncoming() && call.getHandoverSourceCall() != null) {
1310                     extras.putBoolean(TelecomManager.EXTRA_IS_HANDOVER, true);
1311                     extras.putParcelable(TelecomManager.EXTRA_HANDOVER_FROM_PHONE_ACCOUNT,
1312                             call.getHandoverSourceCall().getTargetPhoneAccount());
1313                 }
1314 
1315                 Log.addEvent(call, LogUtils.Events.START_CONNECTION,
1316                         Log.piiHandle(call.getHandle()) + " via:" +
1317                                 getComponentName().getPackageName());
1318 
1319                 ConnectionRequest connectionRequest = new ConnectionRequest.Builder()
1320                         .setAccountHandle(call.getTargetPhoneAccount())
1321                         .setAddress(call.getHandle())
1322                         .setExtras(extras)
1323                         .setVideoState(call.getVideoState())
1324                         .setTelecomCallId(callId)
1325                         // For self-managed incoming calls, if there is another ongoing call Telecom
1326                         // is responsible for showing a UI to ask the user if they'd like to answer
1327                         // this new incoming call.
1328                         .setShouldShowIncomingCallUi(
1329                                 !mCallsManager.shouldShowSystemIncomingCallUi(call))
1330                         .setRttPipeFromInCall(call.getInCallToCsRttPipeForCs())
1331                         .setRttPipeToInCall(call.getCsToInCallRttPipeForCs())
1332                         .build();
1333 
1334                 try {
1335                     mServiceInterface.createConnection(
1336                             call.getConnectionManagerPhoneAccount(),
1337                             callId,
1338                             connectionRequest,
1339                             call.shouldAttachToExistingConnection(),
1340                             call.isUnknown(),
1341                             Log.getExternalSession(TELECOM_ABBREVIATION));
1342 
1343                 } catch (RemoteException e) {
1344                     Log.e(this, e, "Failure to createConnection -- %s", getComponentName());
1345                     mPendingResponses.remove(callId).handleCreateConnectionFailure(
1346                             new DisconnectCause(DisconnectCause.ERROR, e.toString()));
1347                 }
1348             }
1349 
1350             @Override
1351             public void onFailure() {
1352                 Log.e(this, new Exception(), "Failure to call %s", getComponentName());
1353                 response.handleCreateConnectionFailure(new DisconnectCause(DisconnectCause.ERROR));
1354             }
1355         };
1356 
1357         mBinder.bind(callback, call);
1358     }
1359 
1360     /**
1361      * Notifies the {@link ConnectionService} associated with a {@link Call} that the request to
1362      * create a connection has been denied or failed.
1363      * @param call The call.
1364      */
1365     @VisibleForTesting
createConnectionFailed(final Call call)1366     public void createConnectionFailed(final Call call) {
1367         Log.d(this, "createConnectionFailed(%s) via %s.", call, getComponentName());
1368         BindCallback callback = new BindCallback() {
1369             @Override
1370             public void onSuccess() {
1371                 final String callId = mCallIdMapper.getCallId(call);
1372                 // If still bound, tell the connection service create connection has failed.
1373                 if (callId != null && isServiceValid("createConnectionFailed")) {
1374                     Log.addEvent(call, LogUtils.Events.CREATE_CONNECTION_FAILED,
1375                             Log.piiHandle(call.getHandle()));
1376                     try {
1377                         logOutgoing("createConnectionFailed %s", callId);
1378                         mServiceInterface.createConnectionFailed(
1379                                 call.getConnectionManagerPhoneAccount(),
1380                                 callId,
1381                                 new ConnectionRequest(
1382                                         call.getTargetPhoneAccount(),
1383                                         call.getHandle(),
1384                                         call.getIntentExtras(),
1385                                         call.getVideoState(),
1386                                         callId,
1387                                         false),
1388                                 call.isIncoming(),
1389                                 Log.getExternalSession(TELECOM_ABBREVIATION));
1390                         call.setDisconnectCause(new DisconnectCause(DisconnectCause.CANCELED));
1391                         call.disconnect();
1392                     } catch (RemoteException e) {
1393                     }
1394                 }
1395             }
1396 
1397             @Override
1398             public void onFailure() {
1399                 // Binding failed.  Oh no.
1400                 Log.w(this, "onFailure - could not bind to CS for call %s", call.getId());
1401             }
1402         };
1403 
1404         mBinder.bind(callback, call);
1405     }
1406 
1407     /**
1408      * Notifies the {@link ConnectionService} associated with a {@link Call} that the request to
1409      * create a conference has been denied or failed.
1410      * @param call The call.
1411      */
createConferenceFailed(final Call call)1412     void createConferenceFailed(final Call call) {
1413         Log.d(this, "createConferenceFailed(%s) via %s.", call, getComponentName());
1414         BindCallback callback = new BindCallback() {
1415             @Override
1416             public void onSuccess() {
1417                 final String callId = mCallIdMapper.getCallId(call);
1418                 // If still bound, tell the connection service create connection has failed.
1419                 if (callId != null && isServiceValid("createConferenceFailed")) {
1420                     Log.addEvent(call, LogUtils.Events.CREATE_CONFERENCE_FAILED,
1421                             Log.piiHandle(call.getHandle()));
1422                     try {
1423                         logOutgoing("createConferenceFailed %s", callId);
1424                         mServiceInterface.createConferenceFailed(
1425                                 call.getConnectionManagerPhoneAccount(),
1426                                 callId,
1427                                 new ConnectionRequest(
1428                                         call.getTargetPhoneAccount(),
1429                                         call.getHandle(),
1430                                         call.getIntentExtras(),
1431                                         call.getVideoState(),
1432                                         callId,
1433                                         false),
1434                                 call.isIncoming(),
1435                                 Log.getExternalSession(TELECOM_ABBREVIATION));
1436                         call.setDisconnectCause(new DisconnectCause(DisconnectCause.CANCELED));
1437                         call.disconnect();
1438                     } catch (RemoteException e) {
1439                     }
1440                 }
1441             }
1442 
1443             @Override
1444             public void onFailure() {
1445                 // Binding failed.  Oh no.
1446                 Log.w(this, "onFailure - could not bind to CS for conf call %s", call.getId());
1447             }
1448         };
1449 
1450         mBinder.bind(callback, call);
1451     }
1452 
1453 
handoverFailed(final Call call, final int reason)1454     void handoverFailed(final Call call, final int reason) {
1455         Log.d(this, "handoverFailed(%s) via %s.", call, getComponentName());
1456         BindCallback callback = new BindCallback() {
1457             @Override
1458             public void onSuccess() {
1459                 final String callId = mCallIdMapper.getCallId(call);
1460                 // If still bound, tell the connection service create connection has failed.
1461                 if (callId != null && isServiceValid("handoverFailed")) {
1462                     Log.addEvent(call, LogUtils.Events.HANDOVER_FAILED,
1463                             Log.piiHandle(call.getHandle()));
1464                     try {
1465                         mServiceInterface.handoverFailed(
1466                                 callId,
1467                                 new ConnectionRequest(
1468                                         call.getTargetPhoneAccount(),
1469                                         call.getHandle(),
1470                                         call.getIntentExtras(),
1471                                         call.getVideoState(),
1472                                         callId,
1473                                         false),
1474                                 reason,
1475                                 Log.getExternalSession(TELECOM_ABBREVIATION));
1476                     } catch (RemoteException e) {
1477                     }
1478                 }
1479             }
1480 
1481             @Override
1482             public void onFailure() {
1483                 // Binding failed.
1484                 Log.w(this, "onFailure - could not bind to CS for call %s",
1485                         call.getId());
1486             }
1487         };
1488 
1489         mBinder.bind(callback, call);
1490     }
1491 
handoverComplete(final Call call)1492     void handoverComplete(final Call call) {
1493         Log.d(this, "handoverComplete(%s) via %s.", call, getComponentName());
1494         BindCallback callback = new BindCallback() {
1495             @Override
1496             public void onSuccess() {
1497                 final String callId = mCallIdMapper.getCallId(call);
1498                 // If still bound, tell the connection service create connection has failed.
1499                 if (callId != null && isServiceValid("handoverComplete")) {
1500                     try {
1501                         mServiceInterface.handoverComplete(
1502                                 callId,
1503                                 Log.getExternalSession(TELECOM_ABBREVIATION));
1504                     } catch (RemoteException e) {
1505                     }
1506                 }
1507             }
1508 
1509             @Override
1510             public void onFailure() {
1511                 // Binding failed.
1512                 Log.w(this, "onFailure - could not bind to CS for call %s",
1513                         call.getId());
1514             }
1515         };
1516 
1517         mBinder.bind(callback, call);
1518     }
1519 
1520     /** @see IConnectionService#abort(String, Session.Info)  */
abort(Call call)1521     void abort(Call call) {
1522         // Clear out any pending outgoing call data
1523         final String callId = mCallIdMapper.getCallId(call);
1524 
1525         // If still bound, tell the connection service to abort.
1526         if (callId != null && isServiceValid("abort")) {
1527             try {
1528                 logOutgoing("abort %s", callId);
1529                 mServiceInterface.abort(callId, Log.getExternalSession(TELECOM_ABBREVIATION));
1530             } catch (RemoteException e) {
1531             }
1532         }
1533 
1534         removeCall(call, new DisconnectCause(DisconnectCause.LOCAL));
1535     }
1536 
1537     /** @see IConnectionService#silence(String, Session.Info) */
silence(Call call)1538     void silence(Call call) {
1539         final String callId = mCallIdMapper.getCallId(call);
1540         if (callId != null && isServiceValid("silence")) {
1541             try {
1542                 logOutgoing("silence %s", callId);
1543                 mServiceInterface.silence(callId, Log.getExternalSession(TELECOM_ABBREVIATION));
1544             } catch (RemoteException e) {
1545             }
1546         }
1547     }
1548 
1549     /** @see IConnectionService#hold(String, Session.Info) */
hold(Call call)1550     void hold(Call call) {
1551         final String callId = mCallIdMapper.getCallId(call);
1552         if (callId != null && isServiceValid("hold")) {
1553             try {
1554                 logOutgoing("hold %s", callId);
1555                 mServiceInterface.hold(callId, Log.getExternalSession(TELECOM_ABBREVIATION));
1556             } catch (RemoteException e) {
1557             }
1558         }
1559     }
1560 
1561     /** @see IConnectionService#unhold(String, Session.Info) */
unhold(Call call)1562     void unhold(Call call) {
1563         final String callId = mCallIdMapper.getCallId(call);
1564         if (callId != null && isServiceValid("unhold")) {
1565             try {
1566                 logOutgoing("unhold %s", callId);
1567                 mServiceInterface.unhold(callId, Log.getExternalSession(TELECOM_ABBREVIATION));
1568             } catch (RemoteException e) {
1569             }
1570         }
1571     }
1572 
1573     /** @see IConnectionService#onCallAudioStateChanged(String, CallAudioState, Session.Info) */
1574     @VisibleForTesting
onCallAudioStateChanged(Call activeCall, CallAudioState audioState)1575     public void onCallAudioStateChanged(Call activeCall, CallAudioState audioState) {
1576         final String callId = mCallIdMapper.getCallId(activeCall);
1577         if (callId != null && isServiceValid("onCallAudioStateChanged")) {
1578             try {
1579                 logOutgoing("onCallAudioStateChanged %s %s", callId, audioState);
1580                 mServiceInterface.onCallAudioStateChanged(callId, audioState,
1581                         Log.getExternalSession(TELECOM_ABBREVIATION));
1582             } catch (RemoteException e) {
1583             }
1584         }
1585     }
1586 
1587     /** @see IConnectionService#onUsingAlternativeUi(String, boolean, Session.Info) */
1588     @VisibleForTesting
onUsingAlternativeUi(Call activeCall, boolean isUsingAlternativeUi)1589     public void onUsingAlternativeUi(Call activeCall, boolean isUsingAlternativeUi) {
1590         final String callId = mCallIdMapper.getCallId(activeCall);
1591         if (callId != null && isServiceValid("onUsingAlternativeUi")) {
1592             try {
1593                 logOutgoing("onUsingAlternativeUi %s", isUsingAlternativeUi);
1594                 mServiceInterface.onUsingAlternativeUi(callId, isUsingAlternativeUi,
1595                         Log.getExternalSession(TELECOM_ABBREVIATION));
1596             } catch (RemoteException e) {
1597             }
1598         }
1599     }
1600 
1601     /** @see IConnectionService#onTrackedByNonUiService(String, boolean, Session.Info) */
1602     @VisibleForTesting
onTrackedByNonUiService(Call activeCall, boolean isTracked)1603     public void onTrackedByNonUiService(Call activeCall, boolean isTracked) {
1604         final String callId = mCallIdMapper.getCallId(activeCall);
1605         if (callId != null && isServiceValid("onTrackedByNonUiService")) {
1606             try {
1607                 logOutgoing("onTrackedByNonUiService %s", isTracked);
1608                 mServiceInterface.onTrackedByNonUiService(callId, isTracked,
1609                         Log.getExternalSession(TELECOM_ABBREVIATION));
1610             } catch (RemoteException e) {
1611             }
1612         }
1613     }
1614 
1615     /** @see IConnectionService#disconnect(String, Session.Info) */
disconnect(Call call)1616     void disconnect(Call call) {
1617         final String callId = mCallIdMapper.getCallId(call);
1618         if (callId != null && isServiceValid("disconnect")) {
1619             try {
1620                 logOutgoing("disconnect %s", callId);
1621                 mServiceInterface.disconnect(callId, Log.getExternalSession(TELECOM_ABBREVIATION));
1622             } catch (RemoteException e) {
1623             }
1624         }
1625     }
1626 
1627     /** @see IConnectionService#answer(String, Session.Info) */
answer(Call call, int videoState)1628     void answer(Call call, int videoState) {
1629         final String callId = mCallIdMapper.getCallId(call);
1630         if (callId != null && isServiceValid("answer")) {
1631             try {
1632                 logOutgoing("answer %s %d", callId, videoState);
1633                 if (VideoProfile.isAudioOnly(videoState)) {
1634                     mServiceInterface.answer(callId, Log.getExternalSession(TELECOM_ABBREVIATION));
1635                 } else {
1636                     mServiceInterface.answerVideo(callId, videoState,
1637                             Log.getExternalSession(TELECOM_ABBREVIATION));
1638                 }
1639             } catch (RemoteException e) {
1640             }
1641         }
1642     }
1643 
1644     /** @see IConnectionService#deflect(String, Uri , Session.Info) */
deflect(Call call, Uri address)1645     void deflect(Call call, Uri address) {
1646         final String callId = mCallIdMapper.getCallId(call);
1647         if (callId != null && isServiceValid("deflect")) {
1648             try {
1649                 logOutgoing("deflect %s", callId);
1650                 mServiceInterface.deflect(callId, address,
1651                         Log.getExternalSession(TELECOM_ABBREVIATION));
1652             } catch (RemoteException e) {
1653             }
1654         }
1655     }
1656 
1657     /** @see IConnectionService#reject(String, Session.Info) */
reject(Call call, boolean rejectWithMessage, String message)1658     void reject(Call call, boolean rejectWithMessage, String message) {
1659         final String callId = mCallIdMapper.getCallId(call);
1660         if (callId != null && isServiceValid("reject")) {
1661             try {
1662                 logOutgoing("reject %s", callId);
1663 
1664                 if (rejectWithMessage && call.can(
1665                         Connection.CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION)) {
1666                     mServiceInterface.rejectWithMessage(callId, message,
1667                             Log.getExternalSession(TELECOM_ABBREVIATION));
1668                 } else {
1669                     mServiceInterface.reject(callId, Log.getExternalSession(TELECOM_ABBREVIATION));
1670                 }
1671             } catch (RemoteException e) {
1672             }
1673         }
1674     }
1675 
1676     /** @see IConnectionService#reject(String, Session.Info) */
rejectWithReason(Call call, @android.telecom.Call.RejectReason int rejectReason)1677     void rejectWithReason(Call call, @android.telecom.Call.RejectReason int rejectReason) {
1678         final String callId = mCallIdMapper.getCallId(call);
1679         if (callId != null && isServiceValid("rejectReason")) {
1680             try {
1681                 logOutgoing("rejectReason %s, %d", callId, rejectReason);
1682 
1683                 mServiceInterface.rejectWithReason(callId, rejectReason,
1684                         Log.getExternalSession(TELECOM_ABBREVIATION));
1685             } catch (RemoteException e) {
1686             }
1687         }
1688     }
1689 
1690     /** @see IConnectionService#transfer(String, Uri , boolean, Session.Info) */
transfer(Call call, Uri number, boolean isConfirmationRequired)1691     void transfer(Call call, Uri number, boolean isConfirmationRequired) {
1692         final String callId = mCallIdMapper.getCallId(call);
1693         if (callId != null && isServiceValid("transfer")) {
1694             try {
1695                 logOutgoing("transfer %s", callId);
1696                 mServiceInterface.transfer(callId, number, isConfirmationRequired,
1697                         Log.getExternalSession(TELECOM_ABBREVIATION));
1698             } catch (RemoteException e) {
1699             }
1700         }
1701     }
1702 
1703     /** @see IConnectionService#consultativeTransfer(String, String, Session.Info) */
transfer(Call call, Call otherCall)1704     void transfer(Call call, Call otherCall) {
1705         final String callId = mCallIdMapper.getCallId(call);
1706         final String otherCallId = mCallIdMapper.getCallId(otherCall);
1707         if (callId != null && otherCallId != null && isServiceValid("consultativeTransfer")) {
1708             try {
1709                 logOutgoing("consultativeTransfer %s", callId);
1710                 mServiceInterface.consultativeTransfer(callId, otherCallId,
1711                         Log.getExternalSession(TELECOM_ABBREVIATION));
1712             } catch (RemoteException e) {
1713             }
1714         }
1715     }
1716 
1717     /** @see IConnectionService#playDtmfTone(String, char, Session.Info) */
playDtmfTone(Call call, char digit)1718     void playDtmfTone(Call call, char digit) {
1719         final String callId = mCallIdMapper.getCallId(call);
1720         if (callId != null && isServiceValid("playDtmfTone")) {
1721             try {
1722                 logOutgoing("playDtmfTone %s %c", callId, digit);
1723                 mServiceInterface.playDtmfTone(callId, digit,
1724                         Log.getExternalSession(TELECOM_ABBREVIATION));
1725             } catch (RemoteException e) {
1726             }
1727         }
1728     }
1729 
1730     /** @see IConnectionService#stopDtmfTone(String, Session.Info) */
stopDtmfTone(Call call)1731     void stopDtmfTone(Call call) {
1732         final String callId = mCallIdMapper.getCallId(call);
1733         if (callId != null && isServiceValid("stopDtmfTone")) {
1734             try {
1735                 logOutgoing("stopDtmfTone %s", callId);
1736                 mServiceInterface.stopDtmfTone(callId,
1737                         Log.getExternalSession(TELECOM_ABBREVIATION));
1738             } catch (RemoteException e) {
1739             }
1740         }
1741     }
1742 
addCall(Call call)1743     void addCall(Call call) {
1744         if (mCallIdMapper.getCallId(call) == null) {
1745             mCallIdMapper.addCall(call);
1746         }
1747     }
1748 
1749     /**
1750      * Associates newCall with this connection service by replacing callToReplace.
1751      */
replaceCall(Call newCall, Call callToReplace)1752     void replaceCall(Call newCall, Call callToReplace) {
1753         Preconditions.checkState(callToReplace.getConnectionService() == this);
1754         mCallIdMapper.replaceCall(newCall, callToReplace);
1755     }
1756 
removeCall(Call call)1757     void removeCall(Call call) {
1758         removeCall(call, new DisconnectCause(DisconnectCause.ERROR));
1759     }
1760 
removeCall(String callId, DisconnectCause disconnectCause)1761     void removeCall(String callId, DisconnectCause disconnectCause) {
1762         CreateConnectionResponse response = mPendingResponses.remove(callId);
1763         if (response != null) {
1764             response.handleCreateConnectionFailure(disconnectCause);
1765         }
1766 
1767         mCallIdMapper.removeCall(callId);
1768     }
1769 
removeCall(Call call, DisconnectCause disconnectCause)1770     void removeCall(Call call, DisconnectCause disconnectCause) {
1771         CreateConnectionResponse response = mPendingResponses.remove(mCallIdMapper.getCallId(call));
1772         if (response != null) {
1773             response.handleCreateConnectionFailure(disconnectCause);
1774         }
1775 
1776         mCallIdMapper.removeCall(call);
1777     }
1778 
onPostDialContinue(Call call, boolean proceed)1779     void onPostDialContinue(Call call, boolean proceed) {
1780         final String callId = mCallIdMapper.getCallId(call);
1781         if (callId != null && isServiceValid("onPostDialContinue")) {
1782             try {
1783                 logOutgoing("onPostDialContinue %s %b", callId, proceed);
1784                 mServiceInterface.onPostDialContinue(callId, proceed,
1785                         Log.getExternalSession(TELECOM_ABBREVIATION));
1786             } catch (RemoteException ignored) {
1787             }
1788         }
1789     }
1790 
conference(final Call call, Call otherCall)1791     void conference(final Call call, Call otherCall) {
1792         final String callId = mCallIdMapper.getCallId(call);
1793         final String otherCallId = mCallIdMapper.getCallId(otherCall);
1794         if (callId != null && otherCallId != null && isServiceValid("conference")) {
1795             try {
1796                 logOutgoing("conference %s %s", callId, otherCallId);
1797                 mServiceInterface.conference(callId, otherCallId,
1798                         Log.getExternalSession(TELECOM_ABBREVIATION));
1799             } catch (RemoteException ignored) {
1800             }
1801         }
1802     }
1803 
splitFromConference(Call call)1804     void splitFromConference(Call call) {
1805         final String callId = mCallIdMapper.getCallId(call);
1806         if (callId != null && isServiceValid("splitFromConference")) {
1807             try {
1808                 logOutgoing("splitFromConference %s", callId);
1809                 mServiceInterface.splitFromConference(callId,
1810                         Log.getExternalSession(TELECOM_ABBREVIATION));
1811             } catch (RemoteException ignored) {
1812             }
1813         }
1814     }
1815 
mergeConference(Call call)1816     void mergeConference(Call call) {
1817         final String callId = mCallIdMapper.getCallId(call);
1818         if (callId != null && isServiceValid("mergeConference")) {
1819             try {
1820                 logOutgoing("mergeConference %s", callId);
1821                 mServiceInterface.mergeConference(callId,
1822                         Log.getExternalSession(TELECOM_ABBREVIATION));
1823             } catch (RemoteException ignored) {
1824             }
1825         }
1826     }
1827 
swapConference(Call call)1828     void swapConference(Call call) {
1829         final String callId = mCallIdMapper.getCallId(call);
1830         if (callId != null && isServiceValid("swapConference")) {
1831             try {
1832                 logOutgoing("swapConference %s", callId);
1833                 mServiceInterface.swapConference(callId,
1834                         Log.getExternalSession(TELECOM_ABBREVIATION));
1835             } catch (RemoteException ignored) {
1836             }
1837         }
1838     }
1839 
addConferenceParticipants(Call call, List<Uri> participants)1840     void addConferenceParticipants(Call call, List<Uri> participants) {
1841         final String callId = mCallIdMapper.getCallId(call);
1842         if (callId != null && isServiceValid("addConferenceParticipants")) {
1843             try {
1844                 logOutgoing("addConferenceParticipants %s", callId);
1845                 mServiceInterface.addConferenceParticipants(callId, participants,
1846                         Log.getExternalSession(TELECOM_ABBREVIATION));
1847             } catch (RemoteException ignored) {
1848             }
1849         }
1850     }
1851 
1852     @VisibleForTesting
pullExternalCall(Call call)1853     public void pullExternalCall(Call call) {
1854         final String callId = mCallIdMapper.getCallId(call);
1855         if (callId != null && isServiceValid("pullExternalCall")) {
1856             try {
1857                 logOutgoing("pullExternalCall %s", callId);
1858                 mServiceInterface.pullExternalCall(callId,
1859                         Log.getExternalSession(TELECOM_ABBREVIATION));
1860             } catch (RemoteException ignored) {
1861             }
1862         }
1863     }
1864 
sendCallEvent(Call call, String event, Bundle extras)1865     void sendCallEvent(Call call, String event, Bundle extras) {
1866         final String callId = mCallIdMapper.getCallId(call);
1867         if (callId != null && isServiceValid("sendCallEvent")) {
1868             try {
1869                 logOutgoing("sendCallEvent %s %s", callId, event);
1870                 mServiceInterface.sendCallEvent(callId, event, extras,
1871                         Log.getExternalSession(TELECOM_ABBREVIATION));
1872             } catch (RemoteException ignored) {
1873             }
1874         }
1875     }
1876 
onCallFilteringCompleted(Call call, Connection.CallFilteringCompletionInfo completionInfo)1877     void onCallFilteringCompleted(Call call,
1878             Connection.CallFilteringCompletionInfo completionInfo) {
1879         final String callId = mCallIdMapper.getCallId(call);
1880         if (callId != null && isServiceValid("onCallFilteringCompleted")) {
1881             try {
1882                 logOutgoing("onCallFilteringCompleted %s", completionInfo);
1883                 int contactsPermission = mContext.getPackageManager()
1884                         .checkPermission(Manifest.permission.READ_CONTACTS,
1885                                 getComponentName().getPackageName());
1886                 if (contactsPermission == PackageManager.PERMISSION_GRANTED) {
1887                     mServiceInterface.onCallFilteringCompleted(callId, completionInfo,
1888                             Log.getExternalSession(TELECOM_ABBREVIATION));
1889                 } else {
1890                     logOutgoing("Skipping call filtering complete message for %s due"
1891                             + " to lack of READ_CONTACTS", getComponentName().getPackageName());
1892                 }
1893             } catch (RemoteException e) {
1894                 Log.e(this, e, "Remote exception calling onCallFilteringCompleted");
1895             }
1896         }
1897     }
1898 
onExtrasChanged(Call call, Bundle extras)1899     void onExtrasChanged(Call call, Bundle extras) {
1900         final String callId = mCallIdMapper.getCallId(call);
1901         if (callId != null && isServiceValid("onExtrasChanged")) {
1902             try {
1903                 logOutgoing("onExtrasChanged %s %s", callId, extras);
1904                 mServiceInterface.onExtrasChanged(callId, extras,
1905                         Log.getExternalSession(TELECOM_ABBREVIATION));
1906             } catch (RemoteException ignored) {
1907             }
1908         }
1909     }
1910 
startRtt(Call call, ParcelFileDescriptor fromInCall, ParcelFileDescriptor toInCall)1911     void startRtt(Call call, ParcelFileDescriptor fromInCall, ParcelFileDescriptor toInCall) {
1912         final String callId = mCallIdMapper.getCallId(call);
1913         if (callId != null && isServiceValid("startRtt")) {
1914             try {
1915                 logOutgoing("startRtt: %s %s %s", callId, fromInCall, toInCall);
1916                 mServiceInterface.startRtt(callId, fromInCall, toInCall,
1917                         Log.getExternalSession(TELECOM_ABBREVIATION));
1918             } catch (RemoteException ignored) {
1919             }
1920         }
1921     }
1922 
stopRtt(Call call)1923     void stopRtt(Call call) {
1924         final String callId = mCallIdMapper.getCallId(call);
1925         if (callId != null && isServiceValid("stopRtt")) {
1926             try {
1927                 logOutgoing("stopRtt: %s", callId);
1928                 mServiceInterface.stopRtt(callId, Log.getExternalSession(TELECOM_ABBREVIATION));
1929             } catch (RemoteException ignored) {
1930             }
1931         }
1932     }
1933 
respondToRttRequest( Call call, ParcelFileDescriptor fromInCall, ParcelFileDescriptor toInCall)1934     void respondToRttRequest(
1935             Call call, ParcelFileDescriptor fromInCall, ParcelFileDescriptor toInCall) {
1936         final String callId = mCallIdMapper.getCallId(call);
1937         if (callId != null && isServiceValid("respondToRttRequest")) {
1938             try {
1939                 logOutgoing("respondToRttRequest: %s %s %s", callId, fromInCall, toInCall);
1940                 mServiceInterface.respondToRttUpgradeRequest(
1941                         callId, fromInCall, toInCall, Log.getExternalSession(TELECOM_ABBREVIATION));
1942             } catch (RemoteException ignored) {
1943             }
1944         }
1945     }
1946 
1947     /** {@inheritDoc} */
1948     @Override
setServiceInterface(IBinder binder)1949     protected void setServiceInterface(IBinder binder) {
1950         mServiceInterface = IConnectionService.Stub.asInterface(binder);
1951         Log.v(this, "Adding Connection Service Adapter.");
1952         addConnectionServiceAdapter(mAdapter);
1953     }
1954 
1955     /** {@inheritDoc} */
1956     @Override
removeServiceInterface()1957     protected void removeServiceInterface() {
1958         Log.v(this, "Removing Connection Service Adapter.");
1959         removeConnectionServiceAdapter(mAdapter);
1960         // We have lost our service connection. Notify the world that this service is done.
1961         // We must notify the adapter before CallsManager. The adapter will force any pending
1962         // outgoing calls to try the next service. This needs to happen before CallsManager
1963         // tries to clean up any calls still associated with this service.
1964         handleConnectionServiceDeath();
1965         mCallsManager.handleConnectionServiceDeath(this);
1966         mServiceInterface = null;
1967     }
1968 
1969     @Override
connectionServiceFocusLost()1970     public void connectionServiceFocusLost() {
1971         // Immediately response to the Telecom that it has released the call resources.
1972         // TODO(mpq): Change back to the default implementation once b/69651192 done.
1973         if (mConnSvrFocusListener != null) {
1974             mConnSvrFocusListener.onConnectionServiceReleased(ConnectionServiceWrapper.this);
1975         }
1976         BindCallback callback = new BindCallback() {
1977             @Override
1978             public void onSuccess() {
1979                 try {
1980                     mServiceInterface.connectionServiceFocusLost(
1981                             Log.getExternalSession(TELECOM_ABBREVIATION));
1982                 } catch (RemoteException ignored) {
1983                     Log.d(this, "failed to inform the focus lost event");
1984                 }
1985             }
1986 
1987             @Override
1988             public void onFailure() {}
1989         };
1990         mBinder.bind(callback, null /* null call */);
1991     }
1992 
1993     @Override
connectionServiceFocusGained()1994     public void connectionServiceFocusGained() {
1995         BindCallback callback = new BindCallback() {
1996             @Override
1997             public void onSuccess() {
1998                 try {
1999                     mServiceInterface.connectionServiceFocusGained(
2000                             Log.getExternalSession(TELECOM_ABBREVIATION));
2001                 } catch (RemoteException ignored) {
2002                     Log.d(this, "failed to inform the focus gained event");
2003                 }
2004             }
2005 
2006             @Override
2007             public void onFailure() {}
2008         };
2009         mBinder.bind(callback, null /* null call */);
2010     }
2011 
2012     @Override
setConnectionServiceFocusListener( ConnectionServiceFocusManager.ConnectionServiceFocusListener listener)2013     public void setConnectionServiceFocusListener(
2014             ConnectionServiceFocusManager.ConnectionServiceFocusListener listener) {
2015         mConnSvrFocusListener = listener;
2016     }
2017 
handleCreateConnectionComplete( String callId, ConnectionRequest request, ParcelableConnection connection)2018     private void handleCreateConnectionComplete(
2019             String callId,
2020             ConnectionRequest request,
2021             ParcelableConnection connection) {
2022         // TODO: Note we are not using parameter "request", which is a side effect of our tacit
2023         // assumption that we have at most one outgoing connection attempt per ConnectionService.
2024         // This may not continue to be the case.
2025         if (connection.getState() == Connection.STATE_DISCONNECTED) {
2026             // A connection that begins in the DISCONNECTED state is an indication of
2027             // failure to connect; we handle all failures uniformly
2028             Call foundCall = mCallIdMapper.getCall(callId);
2029 
2030             if (connection.getConnectTimeMillis() != 0) {
2031                 foundCall.setConnectTimeMillis(connection.getConnectTimeMillis());
2032             }
2033 
2034             if (foundCall != null) {
2035                 // The post-dial digits are created when the call is first created.  Normally
2036                 // the ConnectionService is responsible for stripping them from the address, but
2037                 // since a failed connection will not have done this, we could end up with duplicate
2038                 // post-dial digits.
2039                 foundCall.clearPostDialDigits();
2040             }
2041             removeCall(callId, connection.getDisconnectCause());
2042         } else {
2043             // Successful connection
2044             if (mPendingResponses.containsKey(callId)) {
2045                 mPendingResponses.remove(callId)
2046                         .handleCreateConnectionSuccess(mCallIdMapper, connection);
2047             }
2048         }
2049     }
2050 
handleCreateConferenceComplete( String callId, ConnectionRequest request, ParcelableConference conference)2051     private void handleCreateConferenceComplete(
2052             String callId,
2053             ConnectionRequest request,
2054             ParcelableConference conference) {
2055         // TODO: Note we are not using parameter "request", which is a side effect of our tacit
2056         // assumption that we have at most one outgoing conference attempt per ConnectionService.
2057         // This may not continue to be the case.
2058         if (conference.getState() == Connection.STATE_DISCONNECTED) {
2059             // A conference that begins in the DISCONNECTED state is an indication of
2060             // failure to connect; we handle all failures uniformly
2061             removeCall(callId, conference.getDisconnectCause());
2062         } else {
2063             // Successful connection
2064             if (mPendingResponses.containsKey(callId)) {
2065                 mPendingResponses.remove(callId)
2066                         .handleCreateConferenceSuccess(mCallIdMapper, conference);
2067             }
2068         }
2069     }
2070 
2071     /**
2072      * Called when the associated connection service dies.
2073      */
handleConnectionServiceDeath()2074     private void handleConnectionServiceDeath() {
2075         if (!mPendingResponses.isEmpty()) {
2076             CreateConnectionResponse[] responses = mPendingResponses.values().toArray(
2077                     new CreateConnectionResponse[mPendingResponses.values().size()]);
2078             mPendingResponses.clear();
2079             for (int i = 0; i < responses.length; i++) {
2080                 responses[i].handleCreateConnectionFailure(
2081                         new DisconnectCause(DisconnectCause.ERROR, "CS_DEATH"));
2082             }
2083         }
2084         mCallIdMapper.clear();
2085 
2086         if (mConnSvrFocusListener != null) {
2087             mConnSvrFocusListener.onConnectionServiceDeath(this);
2088         }
2089     }
2090 
logIncoming(String msg, Object... params)2091     private void logIncoming(String msg, Object... params) {
2092         // Keep these as debug; the incoming logging is traced on a package level through the
2093         // session logging.
2094         Log.d(this, "CS -> TC[" + Log.getPackageAbbreviation(mComponentName) + "]: "
2095                 + msg, params);
2096     }
2097 
logOutgoing(String msg, Object... params)2098     private void logOutgoing(String msg, Object... params) {
2099         Log.d(this, "TC -> CS[" + Log.getPackageAbbreviation(mComponentName) + "]: "
2100                 + msg, params);
2101     }
2102 
queryRemoteConnectionServices(final UserHandle userHandle, final String callingPackage, final RemoteServiceCallback callback)2103     private void queryRemoteConnectionServices(final UserHandle userHandle,
2104             final String callingPackage, final RemoteServiceCallback callback) {
2105         boolean isCallerConnectionManager = false;
2106         // For each Sim ConnectionService, use its subid to find the correct connection manager for
2107         // that ConnectionService; return those Sim ConnectionServices which match the connection
2108         // manager.
2109         final Set<ConnectionServiceWrapper> simServices = Collections.newSetFromMap(
2110                 new ConcurrentHashMap<ConnectionServiceWrapper, Boolean>(8, 0.9f, 1));
2111         for (PhoneAccountHandle handle : mPhoneAccountRegistrar.getSimPhoneAccounts(userHandle)) {
2112             int subId = mPhoneAccountRegistrar.getSubscriptionIdForPhoneAccount(handle);
2113             PhoneAccountHandle connectionMgrHandle = mPhoneAccountRegistrar.getSimCallManager(subId,
2114                     userHandle);
2115             if (connectionMgrHandle == null
2116                     || !connectionMgrHandle.getComponentName().getPackageName().equals(
2117                             callingPackage)) {
2118                 Log.v(this, "queryRemoteConnectionServices: callingPackage=%s skipped; "
2119                                 + "doesn't match mgr %s for tfa %s",
2120                         callingPackage, connectionMgrHandle, handle);
2121             } else {
2122                 isCallerConnectionManager = true;
2123             }
2124             ConnectionServiceWrapper service = mConnectionServiceRepository.getService(
2125                     handle.getComponentName(), handle.getUserHandle());
2126             if (service != null && service != this) {
2127                 simServices.add(service);
2128             } else {
2129                 // This is unexpected, normally PhoneAccounts with CAPABILITY_CALL_PROVIDER are not
2130                 // also CAPABILITY_CONNECTION_MANAGER
2131                 Log.w(this, "call provider also detected as SIM call manager: " + service);
2132             }
2133         }
2134 
2135         // Bail early if the caller isn't the sim connection mgr.
2136         if (!isCallerConnectionManager) {
2137             Log.d(this, "queryRemoteConnectionServices: none; not sim call mgr.");
2138             noRemoteServices(callback);
2139             return;
2140         }
2141 
2142         final List<ComponentName> simServiceComponentNames = new ArrayList<>();
2143         final List<IBinder> simServiceBinders = new ArrayList<>();
2144 
2145         Log.i(this, "queryRemoteConnectionServices, simServices = %s", simServices);
2146 
2147         for (ConnectionServiceWrapper simService : simServices) {
2148             final ConnectionServiceWrapper currentSimService = simService;
2149 
2150             currentSimService.mBinder.bind(new BindCallback() {
2151                 @Override
2152                 public void onSuccess() {
2153                     Log.d(this, "queryRemoteConnectionServices: Adding simService %s",
2154                             currentSimService.getComponentName());
2155                     if (currentSimService.mServiceInterface == null) {
2156                         // The remote ConnectionService died, so do not add it.
2157                         // We will still perform maybeComplete() and notify the caller with an empty
2158                         // list of sim services via maybeComplete().
2159                         Log.w(this, "queryRemoteConnectionServices: simService %s died - Skipping.",
2160                                 currentSimService.getComponentName());
2161                     } else {
2162                         simServiceComponentNames.add(currentSimService.getComponentName());
2163                         simServiceBinders.add(currentSimService.mServiceInterface.asBinder());
2164                     }
2165                     maybeComplete();
2166                 }
2167 
2168                 @Override
2169                 public void onFailure() {
2170                     Log.d(this, "queryRemoteConnectionServices: Failed simService %s",
2171                             currentSimService.getComponentName());
2172                     // We know maybeComplete() will always be a no-op from now on, so go ahead and
2173                     // signal failure of the entire request
2174                     noRemoteServices(callback);
2175                 }
2176 
2177                 private void maybeComplete() {
2178                     if (simServiceComponentNames.size() == simServices.size()) {
2179                         setRemoteServices(callback, simServiceComponentNames, simServiceBinders);
2180                     }
2181                 }
2182             }, null);
2183         }
2184     }
2185 
setRemoteServices( RemoteServiceCallback callback, List<ComponentName> componentNames, List<IBinder> binders)2186     private void setRemoteServices(
2187             RemoteServiceCallback callback,
2188             List<ComponentName> componentNames,
2189             List<IBinder> binders) {
2190         try {
2191             callback.onResult(componentNames, binders);
2192         } catch (RemoteException e) {
2193             Log.e(this, e, "setRemoteServices: Contacting ConnectionService %s",
2194                     ConnectionServiceWrapper.this.getComponentName());
2195         }
2196     }
2197 
noRemoteServices(RemoteServiceCallback callback)2198     private void noRemoteServices(RemoteServiceCallback callback) {
2199         setRemoteServices(callback, Collections.EMPTY_LIST, Collections.EMPTY_LIST);
2200     }
2201 
2202     @Override
toString()2203     public String toString() {
2204         StringBuilder sb = new StringBuilder();
2205         sb.append("[ConnectionServiceWrapper componentName=");
2206         sb.append(mComponentName);
2207         sb.append("]");
2208         return sb.toString();
2209     }
2210 }
2211