Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 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 | |
Tyler Gunn | 7cc70b4 | 2014-09-12 22:17:27 -0700 | [diff] [blame] | 17 | package com.android.server.telecom; |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 18 | |
Tyler Gunn | 91d43cf | 2014-09-17 12:19:39 -0700 | [diff] [blame] | 19 | import android.content.Context; |
Tony Mak | 240656f | 2015-12-04 11:36:22 +0000 | [diff] [blame] | 20 | import android.os.UserHandle; |
Andrew Lee | 701dc00 | 2014-09-11 21:29:12 -0700 | [diff] [blame] | 21 | import android.telecom.DisconnectCause; |
Tyler Gunn | 7cc70b4 | 2014-09-12 22:17:27 -0700 | [diff] [blame] | 22 | import android.telecom.ParcelableConnection; |
| 23 | import android.telecom.PhoneAccount; |
| 24 | import android.telecom.PhoneAccountHandle; |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 25 | |
Tyler Gunn | 91d43cf | 2014-09-17 12:19:39 -0700 | [diff] [blame] | 26 | // TODO: Needed for move to system service: import com.android.internal.R; |
| 27 | |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 28 | import com.android.internal.annotations.VisibleForTesting; |
| 29 | |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 30 | import java.util.ArrayList; |
Sailesh Nepal | 646fa3d | 2015-01-28 02:55:36 -0800 | [diff] [blame] | 31 | import java.util.Collection; |
| 32 | import java.util.HashSet; |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 33 | import java.util.Iterator; |
| 34 | import java.util.List; |
Ihab Awad | 293edf2 | 2014-07-24 17:52:29 -0700 | [diff] [blame] | 35 | import java.util.Objects; |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 36 | |
| 37 | /** |
Yorke Lee | 9250e5f | 2014-10-01 13:39:09 -0700 | [diff] [blame] | 38 | * This class creates connections to place new outgoing calls or to attach to an existing incoming |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 39 | * 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 Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 44 | @VisibleForTesting |
| 45 | public class CreateConnectionProcessor implements CreateConnectionResponse { |
Ihab Awad | 293edf2 | 2014-07-24 17:52:29 -0700 | [diff] [blame] | 46 | |
| 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 Awad | b78b276 | 2014-07-25 15:16:23 -0700 | [diff] [blame] | 51 | public final PhoneAccountHandle connectionManagerPhoneAccount; |
Ihab Awad | 293edf2 | 2014-07-24 17:52:29 -0700 | [diff] [blame] | 52 | // The PhoneAccount which we will tell the target connection service to use |
| 53 | // for attempting to make the actual phone call |
Ihab Awad | b78b276 | 2014-07-25 15:16:23 -0700 | [diff] [blame] | 54 | public final PhoneAccountHandle targetPhoneAccount; |
Ihab Awad | 293edf2 | 2014-07-24 17:52:29 -0700 | [diff] [blame] | 55 | |
| 56 | public CallAttemptRecord( |
Ihab Awad | b78b276 | 2014-07-25 15:16:23 -0700 | [diff] [blame] | 57 | PhoneAccountHandle connectionManagerPhoneAccount, |
| 58 | PhoneAccountHandle targetPhoneAccount) { |
| 59 | this.connectionManagerPhoneAccount = connectionManagerPhoneAccount; |
| 60 | this.targetPhoneAccount = targetPhoneAccount; |
Ihab Awad | 293edf2 | 2014-07-24 17:52:29 -0700 | [diff] [blame] | 61 | } |
| 62 | |
| 63 | @Override |
| 64 | public String toString() { |
| 65 | return "CallAttemptRecord(" |
Ihab Awad | b78b276 | 2014-07-25 15:16:23 -0700 | [diff] [blame] | 66 | + Objects.toString(connectionManagerPhoneAccount) + "," |
| 67 | + Objects.toString(targetPhoneAccount) + ")"; |
Ihab Awad | 293edf2 | 2014-07-24 17:52:29 -0700 | [diff] [blame] | 68 | } |
Tyler Gunn | 6e6f6d1 | 2014-08-20 15:22:18 -0700 | [diff] [blame] | 69 | |
| 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 Awad | 293edf2 | 2014-07-24 17:52:29 -0700 | [diff] [blame] | 87 | } |
| 88 | |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 89 | private final Call mCall; |
| 90 | private final ConnectionServiceRepository mRepository; |
Ihab Awad | 293edf2 | 2014-07-24 17:52:29 -0700 | [diff] [blame] | 91 | private List<CallAttemptRecord> mAttemptRecords; |
| 92 | private Iterator<CallAttemptRecord> mAttemptRecordIterator; |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 93 | private CreateConnectionResponse mCallResponse; |
Andrew Lee | 701dc00 | 2014-09-11 21:29:12 -0700 | [diff] [blame] | 94 | private DisconnectCause mLastErrorDisconnectCause; |
Tyler Gunn | 91d43cf | 2014-09-17 12:19:39 -0700 | [diff] [blame] | 95 | private final PhoneAccountRegistrar mPhoneAccountRegistrar; |
| 96 | private final Context mContext; |
Sailesh Nepal | 646fa3d | 2015-01-28 02:55:36 -0800 | [diff] [blame] | 97 | private CreateConnectionTimeout mTimeout; |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 98 | private ConnectionServiceWrapper mService; |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 99 | |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 100 | @VisibleForTesting |
| 101 | public CreateConnectionProcessor( |
Tyler Gunn | 91d43cf | 2014-09-17 12:19:39 -0700 | [diff] [blame] | 102 | Call call, ConnectionServiceRepository repository, CreateConnectionResponse response, |
| 103 | PhoneAccountRegistrar phoneAccountRegistrar, Context context) { |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 104 | Log.v(this, "CreateConnectionProcessor created for Call = %s", call); |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 105 | mCall = call; |
| 106 | mRepository = repository; |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 107 | mCallResponse = response; |
Tyler Gunn | 91d43cf | 2014-09-17 12:19:39 -0700 | [diff] [blame] | 108 | mPhoneAccountRegistrar = phoneAccountRegistrar; |
| 109 | mContext = context; |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 110 | } |
| 111 | |
Sailesh Nepal | 752cacb | 2014-11-06 12:35:26 -0800 | [diff] [blame] | 112 | boolean isProcessingComplete() { |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 113 | return mCallResponse == null; |
Sailesh Nepal | 752cacb | 2014-11-06 12:35:26 -0800 | [diff] [blame] | 114 | } |
| 115 | |
Sailesh Nepal | 646fa3d | 2015-01-28 02:55:36 -0800 | [diff] [blame] | 116 | boolean isCallTimedOut() { |
| 117 | return mTimeout != null && mTimeout.isCallTimedOut(); |
| 118 | } |
| 119 | |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 120 | @VisibleForTesting |
| 121 | public void process() { |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 122 | Log.v(this, "process"); |
Sailesh Nepal | 646fa3d | 2015-01-28 02:55:36 -0800 | [diff] [blame] | 123 | clearTimeout(); |
Ihab Awad | 293edf2 | 2014-07-24 17:52:29 -0700 | [diff] [blame] | 124 | mAttemptRecords = new ArrayList<>(); |
Ihab Awad | b78b276 | 2014-07-25 15:16:23 -0700 | [diff] [blame] | 125 | if (mCall.getTargetPhoneAccount() != null) { |
Sailesh Nepal | 7957f9c | 2014-08-09 17:13:19 -0700 | [diff] [blame] | 126 | mAttemptRecords.add(new CallAttemptRecord( |
| 127 | mCall.getTargetPhoneAccount(), mCall.getTargetPhoneAccount())); |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 128 | } |
Sailesh Nepal | 7957f9c | 2014-08-09 17:13:19 -0700 | [diff] [blame] | 129 | adjustAttemptsForConnectionManager(); |
Ihab Awad | 293edf2 | 2014-07-24 17:52:29 -0700 | [diff] [blame] | 130 | adjustAttemptsForEmergency(); |
| 131 | mAttemptRecordIterator = mAttemptRecords.iterator(); |
Ihab Awad | 69eb0f5 | 2014-07-18 11:20:37 -0700 | [diff] [blame] | 132 | attemptNextPhoneAccount(); |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 133 | } |
| 134 | |
Sailesh Nepal | 752cacb | 2014-11-06 12:35:26 -0800 | [diff] [blame] | 135 | boolean hasMorePhoneAccounts() { |
| 136 | return mAttemptRecordIterator.hasNext(); |
| 137 | } |
| 138 | |
| 139 | void continueProcessingIfPossible(CreateConnectionResponse response, |
| 140 | DisconnectCause disconnectCause) { |
| 141 | Log.v(this, "continueProcessingIfPossible"); |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 142 | mCallResponse = response; |
Sailesh Nepal | 752cacb | 2014-11-06 12:35:26 -0800 | [diff] [blame] | 143 | mLastErrorDisconnectCause = disconnectCause; |
| 144 | attemptNextPhoneAccount(); |
| 145 | } |
| 146 | |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 147 | void abort() { |
| 148 | Log.v(this, "abort"); |
| 149 | |
| 150 | // Clear the response first to prevent attemptNextConnectionService from attempting any |
| 151 | // more services. |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 152 | CreateConnectionResponse response = mCallResponse; |
| 153 | mCallResponse = null; |
Sailesh Nepal | 646fa3d | 2015-01-28 02:55:36 -0800 | [diff] [blame] | 154 | clearTimeout(); |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 155 | |
| 156 | ConnectionServiceWrapper service = mCall.getConnectionService(); |
| 157 | if (service != null) { |
| 158 | service.abort(mCall); |
| 159 | mCall.clearConnectionService(); |
| 160 | } |
| 161 | if (response != null) { |
Andrew Lee | 701dc00 | 2014-09-11 21:29:12 -0700 | [diff] [blame] | 162 | response.handleCreateConnectionFailure(new DisconnectCause(DisconnectCause.LOCAL)); |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 163 | } |
| 164 | } |
| 165 | |
Ihab Awad | 69eb0f5 | 2014-07-18 11:20:37 -0700 | [diff] [blame] | 166 | private void attemptNextPhoneAccount() { |
| 167 | Log.v(this, "attemptNextPhoneAccount"); |
Tyler Gunn | cb59b67 | 2014-08-20 09:02:11 -0700 | [diff] [blame] | 168 | CallAttemptRecord attempt = null; |
| 169 | if (mAttemptRecordIterator.hasNext()) { |
| 170 | attempt = mAttemptRecordIterator.next(); |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 171 | |
Santos Cordon | 6a21264 | 2015-05-08 16:35:23 -0700 | [diff] [blame] | 172 | if (!mPhoneAccountRegistrar.phoneAccountRequiresBindPermission( |
Tyler Gunn | 91d43cf | 2014-09-17 12:19:39 -0700 | [diff] [blame] | 173 | attempt.connectionManagerPhoneAccount)) { |
Tyler Gunn | cb59b67 | 2014-08-20 09:02:11 -0700 | [diff] [blame] | 174 | Log.w(this, |
Yorke Lee | 7bb8ce9 | 2015-05-13 16:28:29 -0700 | [diff] [blame] | 175 | "Connection mgr does not have BIND_TELECOM_CONNECTION_SERVICE for " |
| 176 | + "attempt: %s", attempt); |
Tyler Gunn | cb59b67 | 2014-08-20 09:02:11 -0700 | [diff] [blame] | 177 | attemptNextPhoneAccount(); |
| 178 | return; |
| 179 | } |
| 180 | |
| 181 | // If the target PhoneAccount differs from the ConnectionManager phone acount, ensure it |
Yorke Lee | 7bb8ce9 | 2015-05-13 16:28:29 -0700 | [diff] [blame] | 182 | // also requires the BIND_TELECOM_CONNECTION_SERVICE permission. |
Tyler Gunn | cb59b67 | 2014-08-20 09:02:11 -0700 | [diff] [blame] | 183 | if (!attempt.connectionManagerPhoneAccount.equals(attempt.targetPhoneAccount) && |
Santos Cordon | 6a21264 | 2015-05-08 16:35:23 -0700 | [diff] [blame] | 184 | !mPhoneAccountRegistrar.phoneAccountRequiresBindPermission( |
| 185 | attempt.targetPhoneAccount)) { |
Tyler Gunn | cb59b67 | 2014-08-20 09:02:11 -0700 | [diff] [blame] | 186 | Log.w(this, |
Yorke Lee | 7bb8ce9 | 2015-05-13 16:28:29 -0700 | [diff] [blame] | 187 | "Target PhoneAccount does not have BIND_TELECOM_CONNECTION_SERVICE for " |
| 188 | + "attempt: %s", attempt); |
Tyler Gunn | cb59b67 | 2014-08-20 09:02:11 -0700 | [diff] [blame] | 189 | attemptNextPhoneAccount(); |
| 190 | return; |
| 191 | } |
| 192 | } |
| 193 | |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 194 | if (mCallResponse != null && attempt != null) { |
Ihab Awad | 293edf2 | 2014-07-24 17:52:29 -0700 | [diff] [blame] | 195 | Log.i(this, "Trying attempt %s", attempt); |
Evan Charlton | 105d977 | 2014-11-25 14:08:53 -0800 | [diff] [blame] | 196 | PhoneAccountHandle phoneAccount = attempt.connectionManagerPhoneAccount; |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 197 | mService = mRepository.getService(phoneAccount.getComponentName(), |
| 198 | phoneAccount.getUserHandle()); |
| 199 | if (mService == null) { |
Ihab Awad | 293edf2 | 2014-07-24 17:52:29 -0700 | [diff] [blame] | 200 | Log.i(this, "Found no connection service for attempt %s", attempt); |
Ihab Awad | 69eb0f5 | 2014-07-18 11:20:37 -0700 | [diff] [blame] | 201 | attemptNextPhoneAccount(); |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 202 | } else { |
Ihab Awad | b78b276 | 2014-07-25 15:16:23 -0700 | [diff] [blame] | 203 | mCall.setConnectionManagerPhoneAccount(attempt.connectionManagerPhoneAccount); |
| 204 | mCall.setTargetPhoneAccount(attempt.targetPhoneAccount); |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 205 | mCall.setConnectionService(mService); |
| 206 | setTimeoutIfNeeded(mService, attempt); |
Sailesh Nepal | 646fa3d | 2015-01-28 02:55:36 -0800 | [diff] [blame] | 207 | |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 208 | mService.createConnection(mCall, this); |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 209 | } |
| 210 | } else { |
Ihab Awad | 69eb0f5 | 2014-07-18 11:20:37 -0700 | [diff] [blame] | 211 | Log.v(this, "attemptNextPhoneAccount, no more accounts, failing"); |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 212 | DisconnectCause disconnectCause = mLastErrorDisconnectCause != null ? |
| 213 | mLastErrorDisconnectCause : new DisconnectCause(DisconnectCause.ERROR); |
| 214 | notifyCallConnectionFailure(disconnectCause); |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 215 | } |
| 216 | } |
| 217 | |
Sailesh Nepal | 646fa3d | 2015-01-28 02:55:36 -0800 | [diff] [blame] | 218 | 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 Nepal | 7957f9c | 2014-08-09 17:13:19 -0700 | [diff] [blame] | 237 | private boolean shouldSetConnectionManager() { |
| 238 | if (mAttemptRecords.size() == 0) { |
| 239 | return false; |
Ihab Awad | 293edf2 | 2014-07-24 17:52:29 -0700 | [diff] [blame] | 240 | } |
Ihab Awad | c17294c | 2014-08-04 19:23:37 -0700 | [diff] [blame] | 241 | |
Sailesh Nepal | 7957f9c | 2014-08-09 17:13:19 -0700 | [diff] [blame] | 242 | 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 Mak | 240656f | 2015-12-04 11:36:22 +0000 | [diff] [blame] | 248 | PhoneAccountHandle connectionManager = |
| 249 | mPhoneAccountRegistrar.getSimCallManagerFromCall(mCall); |
Sailesh Nepal | 7957f9c | 2014-08-09 17:13:19 -0700 | [diff] [blame] | 250 | 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 Cordon | 6a21264 | 2015-05-08 16:35:23 -0700 | [diff] [blame] | 260 | // TODO: Should this really be checking the "calling user" test for phone account? |
Tony Mak | 240656f | 2015-12-04 11:36:22 +0000 | [diff] [blame] | 261 | PhoneAccount targetPhoneAccount = mPhoneAccountRegistrar |
| 262 | .getPhoneAccountUnchecked(targetPhoneAccountHandle); |
Sailesh Nepal | 91fc809 | 2015-02-14 15:44:55 -0800 | [diff] [blame] | 263 | if (targetPhoneAccount == null) { |
| 264 | Log.d(this, "shouldSetConnectionManager, phone account not found"); |
| 265 | return false; |
| 266 | } |
Sailesh Nepal | 7957f9c | 2014-08-09 17:13:19 -0700 | [diff] [blame] | 267 | 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 Mak | 240656f | 2015-12-04 11:36:22 +0000 | [diff] [blame] | 280 | mPhoneAccountRegistrar.getSimCallManagerFromCall(mCall), |
Sailesh Nepal | 7957f9c | 2014-08-09 17:13:19 -0700 | [diff] [blame] | 281 | mAttemptRecords.get(0).targetPhoneAccount); |
mike dooley | 10a5831 | 2014-11-06 13:46:19 -0800 | [diff] [blame] | 282 | Log.v(this, "setConnectionManager, changing %s -> %s", mAttemptRecords.get(0), record); |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 283 | mAttemptRecords.add(0, record); |
Sailesh Nepal | 7957f9c | 2014-08-09 17:13:19 -0700 | [diff] [blame] | 284 | } else { |
| 285 | Log.v(this, "setConnectionManager, not changing"); |
Ihab Awad | 293edf2 | 2014-07-24 17:52:29 -0700 | [diff] [blame] | 286 | } |
| 287 | } |
| 288 | |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 289 | // If we are possibly attempting to call a local emergency number, ensure that the |
Ihab Awad | 69eb0f5 | 2014-07-18 11:20:37 -0700 | [diff] [blame] | 290 | // plain PSTN connection services are listed, and nothing else. |
Tony Mak | 240656f | 2015-12-04 11:36:22 +0000 | [diff] [blame] | 291 | private void adjustAttemptsForEmergency() { |
Tyler Gunn | 6ffe531 | 2015-08-12 08:19:20 -0700 | [diff] [blame] | 292 | if (mCall.isEmergencyCall()) { |
Ihab Awad | 69eb0f5 | 2014-07-18 11:20:37 -0700 | [diff] [blame] | 293 | Log.i(this, "Emergency number detected"); |
Ihab Awad | 293edf2 | 2014-07-24 17:52:29 -0700 | [diff] [blame] | 294 | mAttemptRecords.clear(); |
Tony Mak | 240656f | 2015-12-04 11:36:22 +0000 | [diff] [blame] | 295 | // Phone accounts in profile do not handle emergency call, use phone accounts in |
| 296 | // current user. |
| 297 | List<PhoneAccount> allAccounts = mPhoneAccountRegistrar |
| 298 | .getAllPhoneAccountsOfCurrentUser(); |
Yorke Lee | c127211 | 2014-10-16 09:50:00 -0700 | [diff] [blame] | 299 | |
| 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 Gunn | 8e0fef4 | 2014-09-08 18:34:44 -0700 | [diff] [blame] | 310 | // 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 Awad | 293edf2 | 2014-07-24 17:52:29 -0700 | [diff] [blame] | 316 | mAttemptRecords.add( |
| 317 | new CallAttemptRecord( |
Tyler Gunn | 8e0fef4 | 2014-09-08 18:34:44 -0700 | [diff] [blame] | 318 | phoneAccount.getAccountHandle(), |
| 319 | phoneAccount.getAccountHandle())); |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 320 | } |
| 321 | } |
Tyler Gunn | 6e6f6d1 | 2014-08-20 15:22:18 -0700 | [diff] [blame] | 322 | |
Tyler Gunn | 8e0fef4 | 2014-09-08 18:34:44 -0700 | [diff] [blame] | 323 | // Next, add the connection manager account as a backup if it can place emergency calls. |
Tony Mak | 240656f | 2015-12-04 11:36:22 +0000 | [diff] [blame] | 324 | PhoneAccountHandle callManagerHandle = |
| 325 | mPhoneAccountRegistrar.getSimCallManagerOfCurrentUser(); |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 326 | if (callManagerHandle != null) { |
| 327 | // TODO: Should this really be checking the "calling user" test for phone account? |
Tyler Gunn | 91d43cf | 2014-09-17 12:19:39 -0700 | [diff] [blame] | 328 | PhoneAccount callManager = mPhoneAccountRegistrar |
Tony Mak | 240656f | 2015-12-04 11:36:22 +0000 | [diff] [blame] | 329 | .getPhoneAccountUnchecked(callManagerHandle); |
Sailesh Nepal | 91fc809 | 2015-02-14 15:44:55 -0800 | [diff] [blame] | 330 | if (callManager != null && callManager.hasCapabilities( |
| 331 | PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS)) { |
Tyler Gunn | 8e0fef4 | 2014-09-08 18:34:44 -0700 | [diff] [blame] | 332 | CallAttemptRecord callAttemptRecord = new CallAttemptRecord(callManagerHandle, |
Tony Mak | 240656f | 2015-12-04 11:36:22 +0000 | [diff] [blame] | 333 | mPhoneAccountRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser( |
| 334 | mCall.getHandle().getScheme())); |
Tyler Gunn | 8e0fef4 | 2014-09-08 18:34:44 -0700 | [diff] [blame] | 335 | 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 Gunn | 6e6f6d1 | 2014-08-20 15:22:18 -0700 | [diff] [blame] | 341 | } |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 342 | } |
| 343 | } |
| 344 | |
Sailesh Nepal | 646fa3d | 2015-01-28 02:55:36 -0800 | [diff] [blame] | 345 | /** 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 Mak | 240656f | 2015-12-04 11:36:22 +0000 | [diff] [blame] | 355 | |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 356 | private void notifyCallConnectionFailure(DisconnectCause errorDisconnectCause) { |
| 357 | if (mCallResponse != null) { |
| 358 | clearTimeout(); |
| 359 | mCallResponse.handleCreateConnectionFailure(errorDisconnectCause); |
| 360 | mCallResponse = null; |
| 361 | mCall.clearConnectionService(); |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 362 | } |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 363 | } |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 364 | |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 365 | @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 Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 380 | } |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 381 | } |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 382 | |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 383 | 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 Nepal | bafadce | 2014-11-05 18:40:21 -0800 | [diff] [blame] | 389 | return false; |
| 390 | } |
| 391 | |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 392 | // The Call's Connection Service does not exist |
| 393 | ConnectionServiceWrapper connectionManager = mCall.getConnectionService(); |
| 394 | if (connectionManager == null) { |
| 395 | return true; |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 396 | } |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 397 | |
| 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 | } |
Santos Cordon | 8ff99f3 | 2016-02-12 15:30:44 -0800 | [diff] [blame^] | 426 | mLastErrorDisconnectCause = errorDisconnectCause; |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 427 | attemptNextPhoneAccount(); |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 428 | } |
| 429 | } |