blob: d82240e684d6cac4291feab0bb369f0ff0b4f598 [file] [log] [blame]
Sailesh Nepal664837f2014-07-14 16:31:51 -07001/*
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
Tyler Gunn7cc70b42014-09-12 22:17:27 -070017package com.android.server.telecom;
Sailesh Nepal664837f2014-07-14 16:31:51 -070018
Tyler Gunn91d43cf2014-09-17 12:19:39 -070019import android.content.Context;
Tony Mak240656f2015-12-04 11:36:22 +000020import android.os.UserHandle;
Andrew Lee701dc002014-09-11 21:29:12 -070021import android.telecom.DisconnectCause;
Tyler Gunn7cc70b42014-09-12 22:17:27 -070022import android.telecom.ParcelableConnection;
23import android.telecom.PhoneAccount;
24import android.telecom.PhoneAccountHandle;
Sailesh Nepal664837f2014-07-14 16:31:51 -070025
Tyler Gunn91d43cf2014-09-17 12:19:39 -070026// TODO: Needed for move to system service: import com.android.internal.R;
27
Brad Ebingerf1900072015-11-12 17:25:06 -080028import com.android.internal.annotations.VisibleForTesting;
29
Sailesh Nepal664837f2014-07-14 16:31:51 -070030import java.util.ArrayList;
Sailesh Nepal646fa3d2015-01-28 02:55:36 -080031import java.util.Collection;
32import java.util.HashSet;
Sailesh Nepal664837f2014-07-14 16:31:51 -070033import java.util.Iterator;
34import java.util.List;
Ihab Awad293edf22014-07-24 17:52:29 -070035import java.util.Objects;
Sailesh Nepal664837f2014-07-14 16:31:51 -070036
37/**
Yorke Lee9250e5f2014-10-01 13:39:09 -070038 * This class creates connections to place new outgoing calls or to attach to an existing incoming
Sailesh Nepal664837f2014-07-14 16:31:51 -070039 * call. In either case, this class cycles through a set of connection services until:
40 * - a connection service returns a newly created connection in which case the call is displayed
41 * to the user
42 * - a connection service cancels the process, in which case the call is aborted
43 */
Brad Ebingerf1900072015-11-12 17:25:06 -080044@VisibleForTesting
45public class CreateConnectionProcessor implements CreateConnectionResponse {
Ihab Awad293edf22014-07-24 17:52:29 -070046
47 // Describes information required to attempt to make a phone call
48 private static class CallAttemptRecord {
49 // The PhoneAccount describing the target connection service which we will
50 // contact in order to process an attempt
Ihab Awadb78b2762014-07-25 15:16:23 -070051 public final PhoneAccountHandle connectionManagerPhoneAccount;
Ihab Awad293edf22014-07-24 17:52:29 -070052 // The PhoneAccount which we will tell the target connection service to use
53 // for attempting to make the actual phone call
Ihab Awadb78b2762014-07-25 15:16:23 -070054 public final PhoneAccountHandle targetPhoneAccount;
Ihab Awad293edf22014-07-24 17:52:29 -070055
56 public CallAttemptRecord(
Ihab Awadb78b2762014-07-25 15:16:23 -070057 PhoneAccountHandle connectionManagerPhoneAccount,
58 PhoneAccountHandle targetPhoneAccount) {
59 this.connectionManagerPhoneAccount = connectionManagerPhoneAccount;
60 this.targetPhoneAccount = targetPhoneAccount;
Ihab Awad293edf22014-07-24 17:52:29 -070061 }
62
63 @Override
64 public String toString() {
65 return "CallAttemptRecord("
Ihab Awadb78b2762014-07-25 15:16:23 -070066 + Objects.toString(connectionManagerPhoneAccount) + ","
67 + Objects.toString(targetPhoneAccount) + ")";
Ihab Awad293edf22014-07-24 17:52:29 -070068 }
Tyler Gunn6e6f6d12014-08-20 15:22:18 -070069
70 /**
71 * Determines if this instance of {@code CallAttemptRecord} has the same underlying
72 * {@code PhoneAccountHandle}s as another instance.
73 *
74 * @param obj The other instance to compare against.
75 * @return {@code True} if the {@code CallAttemptRecord}s are equal.
76 */
77 @Override
78 public boolean equals(Object obj) {
79 if (obj instanceof CallAttemptRecord) {
80 CallAttemptRecord other = (CallAttemptRecord) obj;
81 return Objects.equals(connectionManagerPhoneAccount,
82 other.connectionManagerPhoneAccount) &&
83 Objects.equals(targetPhoneAccount, other.targetPhoneAccount);
84 }
85 return false;
86 }
Ihab Awad293edf22014-07-24 17:52:29 -070087 }
88
Sailesh Nepal664837f2014-07-14 16:31:51 -070089 private final Call mCall;
90 private final ConnectionServiceRepository mRepository;
Ihab Awad293edf22014-07-24 17:52:29 -070091 private List<CallAttemptRecord> mAttemptRecords;
92 private Iterator<CallAttemptRecord> mAttemptRecordIterator;
Brad Ebingerf1900072015-11-12 17:25:06 -080093 private CreateConnectionResponse mCallResponse;
Andrew Lee701dc002014-09-11 21:29:12 -070094 private DisconnectCause mLastErrorDisconnectCause;
Tyler Gunn91d43cf2014-09-17 12:19:39 -070095 private final PhoneAccountRegistrar mPhoneAccountRegistrar;
96 private final Context mContext;
Sailesh Nepal646fa3d2015-01-28 02:55:36 -080097 private CreateConnectionTimeout mTimeout;
Brad Ebingerf1900072015-11-12 17:25:06 -080098 private ConnectionServiceWrapper mService;
Sailesh Nepal664837f2014-07-14 16:31:51 -070099
Brad Ebingerf1900072015-11-12 17:25:06 -0800100 @VisibleForTesting
101 public CreateConnectionProcessor(
Tyler Gunn91d43cf2014-09-17 12:19:39 -0700102 Call call, ConnectionServiceRepository repository, CreateConnectionResponse response,
103 PhoneAccountRegistrar phoneAccountRegistrar, Context context) {
Ihab Awad8de76912015-02-17 12:25:52 -0800104 Log.v(this, "CreateConnectionProcessor created for Call = %s", call);
Sailesh Nepal664837f2014-07-14 16:31:51 -0700105 mCall = call;
106 mRepository = repository;
Brad Ebingerf1900072015-11-12 17:25:06 -0800107 mCallResponse = response;
Tyler Gunn91d43cf2014-09-17 12:19:39 -0700108 mPhoneAccountRegistrar = phoneAccountRegistrar;
109 mContext = context;
Sailesh Nepal664837f2014-07-14 16:31:51 -0700110 }
111
Sailesh Nepal752cacb2014-11-06 12:35:26 -0800112 boolean isProcessingComplete() {
Brad Ebingerf1900072015-11-12 17:25:06 -0800113 return mCallResponse == null;
Sailesh Nepal752cacb2014-11-06 12:35:26 -0800114 }
115
Sailesh Nepal646fa3d2015-01-28 02:55:36 -0800116 boolean isCallTimedOut() {
117 return mTimeout != null && mTimeout.isCallTimedOut();
118 }
119
Brad Ebingerf1900072015-11-12 17:25:06 -0800120 @VisibleForTesting
121 public void process() {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700122 Log.v(this, "process");
Sailesh Nepal646fa3d2015-01-28 02:55:36 -0800123 clearTimeout();
Ihab Awad293edf22014-07-24 17:52:29 -0700124 mAttemptRecords = new ArrayList<>();
Ihab Awadb78b2762014-07-25 15:16:23 -0700125 if (mCall.getTargetPhoneAccount() != null) {
Sailesh Nepal7957f9c2014-08-09 17:13:19 -0700126 mAttemptRecords.add(new CallAttemptRecord(
127 mCall.getTargetPhoneAccount(), mCall.getTargetPhoneAccount()));
Sailesh Nepal664837f2014-07-14 16:31:51 -0700128 }
Sailesh Nepal7957f9c2014-08-09 17:13:19 -0700129 adjustAttemptsForConnectionManager();
Ihab Awad293edf22014-07-24 17:52:29 -0700130 adjustAttemptsForEmergency();
131 mAttemptRecordIterator = mAttemptRecords.iterator();
Ihab Awad69eb0f52014-07-18 11:20:37 -0700132 attemptNextPhoneAccount();
Sailesh Nepal664837f2014-07-14 16:31:51 -0700133 }
134
Sailesh Nepal752cacb2014-11-06 12:35:26 -0800135 boolean hasMorePhoneAccounts() {
136 return mAttemptRecordIterator.hasNext();
137 }
138
139 void continueProcessingIfPossible(CreateConnectionResponse response,
140 DisconnectCause disconnectCause) {
141 Log.v(this, "continueProcessingIfPossible");
Brad Ebingerf1900072015-11-12 17:25:06 -0800142 mCallResponse = response;
Sailesh Nepal752cacb2014-11-06 12:35:26 -0800143 mLastErrorDisconnectCause = disconnectCause;
144 attemptNextPhoneAccount();
145 }
146
Sailesh Nepal664837f2014-07-14 16:31:51 -0700147 void abort() {
148 Log.v(this, "abort");
149
150 // Clear the response first to prevent attemptNextConnectionService from attempting any
151 // more services.
Brad Ebingerf1900072015-11-12 17:25:06 -0800152 CreateConnectionResponse response = mCallResponse;
153 mCallResponse = null;
Sailesh Nepal646fa3d2015-01-28 02:55:36 -0800154 clearTimeout();
Sailesh Nepal664837f2014-07-14 16:31:51 -0700155
156 ConnectionServiceWrapper service = mCall.getConnectionService();
157 if (service != null) {
158 service.abort(mCall);
159 mCall.clearConnectionService();
160 }
161 if (response != null) {
Andrew Lee701dc002014-09-11 21:29:12 -0700162 response.handleCreateConnectionFailure(new DisconnectCause(DisconnectCause.LOCAL));
Sailesh Nepal664837f2014-07-14 16:31:51 -0700163 }
164 }
165
Ihab Awad69eb0f52014-07-18 11:20:37 -0700166 private void attemptNextPhoneAccount() {
167 Log.v(this, "attemptNextPhoneAccount");
Tyler Gunncb59b672014-08-20 09:02:11 -0700168 CallAttemptRecord attempt = null;
169 if (mAttemptRecordIterator.hasNext()) {
170 attempt = mAttemptRecordIterator.next();
Sailesh Nepal664837f2014-07-14 16:31:51 -0700171
Santos Cordon6a212642015-05-08 16:35:23 -0700172 if (!mPhoneAccountRegistrar.phoneAccountRequiresBindPermission(
Tyler Gunn91d43cf2014-09-17 12:19:39 -0700173 attempt.connectionManagerPhoneAccount)) {
Tyler Gunncb59b672014-08-20 09:02:11 -0700174 Log.w(this,
Yorke Lee7bb8ce92015-05-13 16:28:29 -0700175 "Connection mgr does not have BIND_TELECOM_CONNECTION_SERVICE for "
176 + "attempt: %s", attempt);
Tyler Gunncb59b672014-08-20 09:02:11 -0700177 attemptNextPhoneAccount();
178 return;
179 }
180
181 // If the target PhoneAccount differs from the ConnectionManager phone acount, ensure it
Yorke Lee7bb8ce92015-05-13 16:28:29 -0700182 // also requires the BIND_TELECOM_CONNECTION_SERVICE permission.
Tyler Gunncb59b672014-08-20 09:02:11 -0700183 if (!attempt.connectionManagerPhoneAccount.equals(attempt.targetPhoneAccount) &&
Santos Cordon6a212642015-05-08 16:35:23 -0700184 !mPhoneAccountRegistrar.phoneAccountRequiresBindPermission(
185 attempt.targetPhoneAccount)) {
Tyler Gunncb59b672014-08-20 09:02:11 -0700186 Log.w(this,
Yorke Lee7bb8ce92015-05-13 16:28:29 -0700187 "Target PhoneAccount does not have BIND_TELECOM_CONNECTION_SERVICE for "
188 + "attempt: %s", attempt);
Tyler Gunncb59b672014-08-20 09:02:11 -0700189 attemptNextPhoneAccount();
190 return;
191 }
192 }
193
Brad Ebingerf1900072015-11-12 17:25:06 -0800194 if (mCallResponse != null && attempt != null) {
Ihab Awad293edf22014-07-24 17:52:29 -0700195 Log.i(this, "Trying attempt %s", attempt);
Evan Charlton105d9772014-11-25 14:08:53 -0800196 PhoneAccountHandle phoneAccount = attempt.connectionManagerPhoneAccount;
Brad Ebingerf1900072015-11-12 17:25:06 -0800197 mService = mRepository.getService(phoneAccount.getComponentName(),
198 phoneAccount.getUserHandle());
199 if (mService == null) {
Ihab Awad293edf22014-07-24 17:52:29 -0700200 Log.i(this, "Found no connection service for attempt %s", attempt);
Ihab Awad69eb0f52014-07-18 11:20:37 -0700201 attemptNextPhoneAccount();
Sailesh Nepal664837f2014-07-14 16:31:51 -0700202 } else {
Ihab Awadb78b2762014-07-25 15:16:23 -0700203 mCall.setConnectionManagerPhoneAccount(attempt.connectionManagerPhoneAccount);
204 mCall.setTargetPhoneAccount(attempt.targetPhoneAccount);
Brad Ebingerf1900072015-11-12 17:25:06 -0800205 mCall.setConnectionService(mService);
206 setTimeoutIfNeeded(mService, attempt);
Sailesh Nepal646fa3d2015-01-28 02:55:36 -0800207
Brad Ebingerf1900072015-11-12 17:25:06 -0800208 mService.createConnection(mCall, this);
Sailesh Nepal664837f2014-07-14 16:31:51 -0700209 }
210 } else {
Ihab Awad69eb0f52014-07-18 11:20:37 -0700211 Log.v(this, "attemptNextPhoneAccount, no more accounts, failing");
Brad Ebingerf1900072015-11-12 17:25:06 -0800212 DisconnectCause disconnectCause = mLastErrorDisconnectCause != null ?
213 mLastErrorDisconnectCause : new DisconnectCause(DisconnectCause.ERROR);
214 notifyCallConnectionFailure(disconnectCause);
Sailesh Nepal664837f2014-07-14 16:31:51 -0700215 }
216 }
217
Sailesh Nepal646fa3d2015-01-28 02:55:36 -0800218 private void setTimeoutIfNeeded(ConnectionServiceWrapper service, CallAttemptRecord attempt) {
219 clearTimeout();
220
221 CreateConnectionTimeout timeout = new CreateConnectionTimeout(
222 mContext, mPhoneAccountRegistrar, service, mCall);
223 if (timeout.isTimeoutNeededForCall(getConnectionServices(mAttemptRecords),
224 attempt.connectionManagerPhoneAccount)) {
225 mTimeout = timeout;
226 timeout.registerTimeout();
227 }
228 }
229
230 private void clearTimeout() {
231 if (mTimeout != null) {
232 mTimeout.unregisterTimeout();
233 mTimeout = null;
234 }
235 }
236
Sailesh Nepal7957f9c2014-08-09 17:13:19 -0700237 private boolean shouldSetConnectionManager() {
238 if (mAttemptRecords.size() == 0) {
239 return false;
Ihab Awad293edf22014-07-24 17:52:29 -0700240 }
Ihab Awadc17294c2014-08-04 19:23:37 -0700241
Sailesh Nepal7957f9c2014-08-09 17:13:19 -0700242 if (mAttemptRecords.size() > 1) {
243 Log.d(this, "shouldSetConnectionManager, error, mAttemptRecords should not have more "
244 + "than 1 record");
245 return false;
246 }
247
Tony Mak240656f2015-12-04 11:36:22 +0000248 PhoneAccountHandle connectionManager =
249 mPhoneAccountRegistrar.getSimCallManagerFromCall(mCall);
Sailesh Nepal7957f9c2014-08-09 17:13:19 -0700250 if (connectionManager == null) {
251 return false;
252 }
253
254 PhoneAccountHandle targetPhoneAccountHandle = mAttemptRecords.get(0).targetPhoneAccount;
255 if (Objects.equals(connectionManager, targetPhoneAccountHandle)) {
256 return false;
257 }
258
259 // Connection managers are only allowed to manage SIM subscriptions.
Santos Cordon6a212642015-05-08 16:35:23 -0700260 // TODO: Should this really be checking the "calling user" test for phone account?
Tony Mak240656f2015-12-04 11:36:22 +0000261 PhoneAccount targetPhoneAccount = mPhoneAccountRegistrar
262 .getPhoneAccountUnchecked(targetPhoneAccountHandle);
Sailesh Nepal91fc8092015-02-14 15:44:55 -0800263 if (targetPhoneAccount == null) {
264 Log.d(this, "shouldSetConnectionManager, phone account not found");
265 return false;
266 }
Sailesh Nepal7957f9c2014-08-09 17:13:19 -0700267 boolean isSimSubscription = (targetPhoneAccount.getCapabilities() &
268 PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION) != 0;
269 if (!isSimSubscription) {
270 return false;
271 }
272
273 return true;
274 }
275
276 // If there exists a registered connection manager then use it.
277 private void adjustAttemptsForConnectionManager() {
278 if (shouldSetConnectionManager()) {
279 CallAttemptRecord record = new CallAttemptRecord(
Tony Mak240656f2015-12-04 11:36:22 +0000280 mPhoneAccountRegistrar.getSimCallManagerFromCall(mCall),
Sailesh Nepal7957f9c2014-08-09 17:13:19 -0700281 mAttemptRecords.get(0).targetPhoneAccount);
mike dooley10a58312014-11-06 13:46:19 -0800282 Log.v(this, "setConnectionManager, changing %s -> %s", mAttemptRecords.get(0), record);
Brad Ebingerf1900072015-11-12 17:25:06 -0800283 mAttemptRecords.add(0, record);
Sailesh Nepal7957f9c2014-08-09 17:13:19 -0700284 } else {
285 Log.v(this, "setConnectionManager, not changing");
Ihab Awad293edf22014-07-24 17:52:29 -0700286 }
287 }
288
Sailesh Nepal664837f2014-07-14 16:31:51 -0700289 // If we are possibly attempting to call a local emergency number, ensure that the
Ihab Awad69eb0f52014-07-18 11:20:37 -0700290 // plain PSTN connection services are listed, and nothing else.
Tony Mak240656f2015-12-04 11:36:22 +0000291 private void adjustAttemptsForEmergency() {
Tyler Gunn6ffe5312015-08-12 08:19:20 -0700292 if (mCall.isEmergencyCall()) {
Ihab Awad69eb0f52014-07-18 11:20:37 -0700293 Log.i(this, "Emergency number detected");
Ihab Awad293edf22014-07-24 17:52:29 -0700294 mAttemptRecords.clear();
Tony Mak240656f2015-12-04 11:36:22 +0000295 // Phone accounts in profile do not handle emergency call, use phone accounts in
296 // current user.
297 List<PhoneAccount> allAccounts = mPhoneAccountRegistrar
298 .getAllPhoneAccountsOfCurrentUser();
Yorke Leec1272112014-10-16 09:50:00 -0700299
300 if (allAccounts.isEmpty()) {
301 // If the list of phone accounts is empty at this point, it means Telephony hasn't
302 // registered any phone accounts yet. Add a fallback emergency phone account so
303 // that emergency calls can still go through. We create a new ArrayLists here just
304 // in case the implementation of PhoneAccountRegistrar ever returns an unmodifiable
305 // list.
306 allAccounts = new ArrayList<PhoneAccount>();
307 allAccounts.add(TelephonyUtil.getDefaultEmergencyPhoneAccount());
308 }
309
Tyler Gunn8e0fef42014-09-08 18:34:44 -0700310 // First, add SIM phone accounts which can place emergency calls.
311 for (PhoneAccount phoneAccount : allAccounts) {
312 if (phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS) &&
313 phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
314 Log.i(this, "Will try PSTN account %s for emergency",
315 phoneAccount.getAccountHandle());
Ihab Awad293edf22014-07-24 17:52:29 -0700316 mAttemptRecords.add(
317 new CallAttemptRecord(
Tyler Gunn8e0fef42014-09-08 18:34:44 -0700318 phoneAccount.getAccountHandle(),
319 phoneAccount.getAccountHandle()));
Sailesh Nepal664837f2014-07-14 16:31:51 -0700320 }
321 }
Tyler Gunn6e6f6d12014-08-20 15:22:18 -0700322
Tyler Gunn8e0fef42014-09-08 18:34:44 -0700323 // Next, add the connection manager account as a backup if it can place emergency calls.
Tony Mak240656f2015-12-04 11:36:22 +0000324 PhoneAccountHandle callManagerHandle =
325 mPhoneAccountRegistrar.getSimCallManagerOfCurrentUser();
Brad Ebingerf1900072015-11-12 17:25:06 -0800326 if (callManagerHandle != null) {
327 // TODO: Should this really be checking the "calling user" test for phone account?
Tyler Gunn91d43cf2014-09-17 12:19:39 -0700328 PhoneAccount callManager = mPhoneAccountRegistrar
Tony Mak240656f2015-12-04 11:36:22 +0000329 .getPhoneAccountUnchecked(callManagerHandle);
Sailesh Nepal91fc8092015-02-14 15:44:55 -0800330 if (callManager != null && callManager.hasCapabilities(
331 PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS)) {
Tyler Gunn8e0fef42014-09-08 18:34:44 -0700332 CallAttemptRecord callAttemptRecord = new CallAttemptRecord(callManagerHandle,
Tony Mak240656f2015-12-04 11:36:22 +0000333 mPhoneAccountRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(
334 mCall.getHandle().getScheme()));
Tyler Gunn8e0fef42014-09-08 18:34:44 -0700335 if (!mAttemptRecords.contains(callAttemptRecord)) {
336 Log.i(this, "Will try Connection Manager account %s for emergency",
337 callManager);
338 mAttemptRecords.add(callAttemptRecord);
339 }
340 }
Tyler Gunn6e6f6d12014-08-20 15:22:18 -0700341 }
Sailesh Nepal664837f2014-07-14 16:31:51 -0700342 }
343 }
344
Sailesh Nepal646fa3d2015-01-28 02:55:36 -0800345 /** Returns all connection services used by the call attempt records. */
346 private static Collection<PhoneAccountHandle> getConnectionServices(
347 List<CallAttemptRecord> records) {
348 HashSet<PhoneAccountHandle> result = new HashSet<>();
349 for (CallAttemptRecord record : records) {
350 result.add(record.connectionManagerPhoneAccount);
351 }
352 return result;
353 }
354
Tony Mak240656f2015-12-04 11:36:22 +0000355
Brad Ebingerf1900072015-11-12 17:25:06 -0800356 private void notifyCallConnectionFailure(DisconnectCause errorDisconnectCause) {
357 if (mCallResponse != null) {
358 clearTimeout();
359 mCallResponse.handleCreateConnectionFailure(errorDisconnectCause);
360 mCallResponse = null;
361 mCall.clearConnectionService();
Sailesh Nepal664837f2014-07-14 16:31:51 -0700362 }
Brad Ebingerf1900072015-11-12 17:25:06 -0800363 }
Sailesh Nepal664837f2014-07-14 16:31:51 -0700364
Brad Ebingerf1900072015-11-12 17:25:06 -0800365 @Override
366 public void handleCreateConnectionSuccess(
367 CallIdMapper idMapper,
368 ParcelableConnection connection) {
369 if (mCallResponse == null) {
370 // Nobody is listening for this connection attempt any longer; ask the responsible
371 // ConnectionService to tear down any resources associated with the call
372 mService.abort(mCall);
373 } else {
374 // Success -- share the good news and remember that we are no longer interested
375 // in hearing about any more attempts
376 mCallResponse.handleCreateConnectionSuccess(idMapper, connection);
377 mCallResponse = null;
378 // If there's a timeout running then don't clear it. The timeout can be triggered
379 // after the call has successfully been created but before it has become active.
Sailesh Nepal664837f2014-07-14 16:31:51 -0700380 }
Brad Ebingerf1900072015-11-12 17:25:06 -0800381 }
Sailesh Nepal664837f2014-07-14 16:31:51 -0700382
Brad Ebingerf1900072015-11-12 17:25:06 -0800383 private boolean shouldFailCallIfConnectionManagerFails(DisconnectCause cause) {
384 // Connection Manager does not exist or does not match registered Connection Manager
385 // Since Connection manager is a proxy for SIM, fall back to SIM
386 PhoneAccountHandle handle = mCall.getConnectionManagerPhoneAccount();
387 if (handle == null || !handle.equals(mPhoneAccountRegistrar.getSimCallManagerFromCall(
388 mCall))) {
Sailesh Nepalbafadce2014-11-05 18:40:21 -0800389 return false;
390 }
391
Brad Ebingerf1900072015-11-12 17:25:06 -0800392 // The Call's Connection Service does not exist
393 ConnectionServiceWrapper connectionManager = mCall.getConnectionService();
394 if (connectionManager == null) {
395 return true;
Sailesh Nepal664837f2014-07-14 16:31:51 -0700396 }
Brad Ebingerf1900072015-11-12 17:25:06 -0800397
398 // In this case, fall back to a sim because connection manager declined
399 if (cause.getCode() == DisconnectCause.CONNECTION_MANAGER_NOT_SUPPORTED) {
400 Log.d(CreateConnectionProcessor.this, "Connection manager declined to handle the "
401 + "call, falling back to not using a connection manager");
402 return false;
403 }
404
405 if (!connectionManager.isServiceValid("createConnection")) {
406 Log.d(CreateConnectionProcessor.this, "Connection manager unbound while trying "
407 + "create a connection, falling back to not using a connection manager");
408 return false;
409 }
410
411 // Do not fall back from connection manager and simply fail call if the failure reason is
412 // other
413 Log.d(CreateConnectionProcessor.this, "Connection Manager denied call with the following " +
414 "error: " + cause.getReason() + ". Not falling back to SIM.");
415 return true;
416 }
417
418 @Override
419 public void handleCreateConnectionFailure(DisconnectCause errorDisconnectCause) {
420 // Failure of some sort; record the reasons for failure and try again if possible
421 Log.d(CreateConnectionProcessor.this, "Connection failed: (%s)", errorDisconnectCause);
422 if(shouldFailCallIfConnectionManagerFails(errorDisconnectCause)){
423 notifyCallConnectionFailure(errorDisconnectCause);
424 return;
425 }
426 attemptNextPhoneAccount();
Sailesh Nepal664837f2014-07-14 16:31:51 -0700427 }
428}