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; |
Andrew Lee | 701dc00 | 2014-09-11 21:29:12 -0700 | [diff] [blame] | 20 | import android.telecom.DisconnectCause; |
Brad Ebinger | a3eccfe | 2016-10-05 15:45:22 -0700 | [diff] [blame^] | 21 | import android.telecom.Log; |
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; |
Brad Ebinger | 6e8f3d7 | 2016-06-20 11:35:42 -0700 | [diff] [blame] | 99 | private int mConnectionAttempt; |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 100 | |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 101 | @VisibleForTesting |
| 102 | public CreateConnectionProcessor( |
Tyler Gunn | 91d43cf | 2014-09-17 12:19:39 -0700 | [diff] [blame] | 103 | Call call, ConnectionServiceRepository repository, CreateConnectionResponse response, |
| 104 | PhoneAccountRegistrar phoneAccountRegistrar, Context context) { |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 105 | Log.v(this, "CreateConnectionProcessor created for Call = %s", call); |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 106 | mCall = call; |
| 107 | mRepository = repository; |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 108 | mCallResponse = response; |
Tyler Gunn | 91d43cf | 2014-09-17 12:19:39 -0700 | [diff] [blame] | 109 | mPhoneAccountRegistrar = phoneAccountRegistrar; |
| 110 | mContext = context; |
Brad Ebinger | 6e8f3d7 | 2016-06-20 11:35:42 -0700 | [diff] [blame] | 111 | mConnectionAttempt = 0; |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 112 | } |
| 113 | |
Sailesh Nepal | 752cacb | 2014-11-06 12:35:26 -0800 | [diff] [blame] | 114 | boolean isProcessingComplete() { |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 115 | return mCallResponse == null; |
Sailesh Nepal | 752cacb | 2014-11-06 12:35:26 -0800 | [diff] [blame] | 116 | } |
| 117 | |
Sailesh Nepal | 646fa3d | 2015-01-28 02:55:36 -0800 | [diff] [blame] | 118 | boolean isCallTimedOut() { |
| 119 | return mTimeout != null && mTimeout.isCallTimedOut(); |
| 120 | } |
| 121 | |
Brad Ebinger | 6e8f3d7 | 2016-06-20 11:35:42 -0700 | [diff] [blame] | 122 | public int getConnectionAttempt() { |
| 123 | return mConnectionAttempt; |
| 124 | } |
| 125 | |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 126 | @VisibleForTesting |
| 127 | public void process() { |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 128 | Log.v(this, "process"); |
Sailesh Nepal | 646fa3d | 2015-01-28 02:55:36 -0800 | [diff] [blame] | 129 | clearTimeout(); |
Ihab Awad | 293edf2 | 2014-07-24 17:52:29 -0700 | [diff] [blame] | 130 | mAttemptRecords = new ArrayList<>(); |
Ihab Awad | b78b276 | 2014-07-25 15:16:23 -0700 | [diff] [blame] | 131 | if (mCall.getTargetPhoneAccount() != null) { |
Sailesh Nepal | 7957f9c | 2014-08-09 17:13:19 -0700 | [diff] [blame] | 132 | mAttemptRecords.add(new CallAttemptRecord( |
| 133 | mCall.getTargetPhoneAccount(), mCall.getTargetPhoneAccount())); |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 134 | } |
Sailesh Nepal | 7957f9c | 2014-08-09 17:13:19 -0700 | [diff] [blame] | 135 | adjustAttemptsForConnectionManager(); |
Brad Ebinger | e6c481a | 2016-05-12 14:13:26 -0700 | [diff] [blame] | 136 | adjustAttemptsForEmergency(mCall.getTargetPhoneAccount()); |
Ihab Awad | 293edf2 | 2014-07-24 17:52:29 -0700 | [diff] [blame] | 137 | mAttemptRecordIterator = mAttemptRecords.iterator(); |
Ihab Awad | 69eb0f5 | 2014-07-18 11:20:37 -0700 | [diff] [blame] | 138 | attemptNextPhoneAccount(); |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 139 | } |
| 140 | |
Sailesh Nepal | 752cacb | 2014-11-06 12:35:26 -0800 | [diff] [blame] | 141 | boolean hasMorePhoneAccounts() { |
| 142 | return mAttemptRecordIterator.hasNext(); |
| 143 | } |
| 144 | |
| 145 | void continueProcessingIfPossible(CreateConnectionResponse response, |
| 146 | DisconnectCause disconnectCause) { |
| 147 | Log.v(this, "continueProcessingIfPossible"); |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 148 | mCallResponse = response; |
Sailesh Nepal | 752cacb | 2014-11-06 12:35:26 -0800 | [diff] [blame] | 149 | mLastErrorDisconnectCause = disconnectCause; |
| 150 | attemptNextPhoneAccount(); |
| 151 | } |
| 152 | |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 153 | void abort() { |
| 154 | Log.v(this, "abort"); |
| 155 | |
| 156 | // Clear the response first to prevent attemptNextConnectionService from attempting any |
| 157 | // more services. |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 158 | CreateConnectionResponse response = mCallResponse; |
| 159 | mCallResponse = null; |
Sailesh Nepal | 646fa3d | 2015-01-28 02:55:36 -0800 | [diff] [blame] | 160 | clearTimeout(); |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 161 | |
| 162 | ConnectionServiceWrapper service = mCall.getConnectionService(); |
| 163 | if (service != null) { |
| 164 | service.abort(mCall); |
| 165 | mCall.clearConnectionService(); |
| 166 | } |
| 167 | if (response != null) { |
Andrew Lee | 701dc00 | 2014-09-11 21:29:12 -0700 | [diff] [blame] | 168 | response.handleCreateConnectionFailure(new DisconnectCause(DisconnectCause.LOCAL)); |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 169 | } |
| 170 | } |
| 171 | |
Ihab Awad | 69eb0f5 | 2014-07-18 11:20:37 -0700 | [diff] [blame] | 172 | private void attemptNextPhoneAccount() { |
| 173 | Log.v(this, "attemptNextPhoneAccount"); |
Tyler Gunn | cb59b67 | 2014-08-20 09:02:11 -0700 | [diff] [blame] | 174 | CallAttemptRecord attempt = null; |
| 175 | if (mAttemptRecordIterator.hasNext()) { |
| 176 | attempt = mAttemptRecordIterator.next(); |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 177 | |
Santos Cordon | 6a21264 | 2015-05-08 16:35:23 -0700 | [diff] [blame] | 178 | if (!mPhoneAccountRegistrar.phoneAccountRequiresBindPermission( |
Tyler Gunn | 91d43cf | 2014-09-17 12:19:39 -0700 | [diff] [blame] | 179 | attempt.connectionManagerPhoneAccount)) { |
Tyler Gunn | cb59b67 | 2014-08-20 09:02:11 -0700 | [diff] [blame] | 180 | Log.w(this, |
Yorke Lee | 7bb8ce9 | 2015-05-13 16:28:29 -0700 | [diff] [blame] | 181 | "Connection mgr does not have BIND_TELECOM_CONNECTION_SERVICE for " |
| 182 | + "attempt: %s", attempt); |
Tyler Gunn | cb59b67 | 2014-08-20 09:02:11 -0700 | [diff] [blame] | 183 | attemptNextPhoneAccount(); |
| 184 | return; |
| 185 | } |
| 186 | |
| 187 | // If the target PhoneAccount differs from the ConnectionManager phone acount, ensure it |
Yorke Lee | 7bb8ce9 | 2015-05-13 16:28:29 -0700 | [diff] [blame] | 188 | // also requires the BIND_TELECOM_CONNECTION_SERVICE permission. |
Tyler Gunn | cb59b67 | 2014-08-20 09:02:11 -0700 | [diff] [blame] | 189 | if (!attempt.connectionManagerPhoneAccount.equals(attempt.targetPhoneAccount) && |
Santos Cordon | 6a21264 | 2015-05-08 16:35:23 -0700 | [diff] [blame] | 190 | !mPhoneAccountRegistrar.phoneAccountRequiresBindPermission( |
| 191 | attempt.targetPhoneAccount)) { |
Tyler Gunn | cb59b67 | 2014-08-20 09:02:11 -0700 | [diff] [blame] | 192 | Log.w(this, |
Yorke Lee | 7bb8ce9 | 2015-05-13 16:28:29 -0700 | [diff] [blame] | 193 | "Target PhoneAccount does not have BIND_TELECOM_CONNECTION_SERVICE for " |
| 194 | + "attempt: %s", attempt); |
Tyler Gunn | cb59b67 | 2014-08-20 09:02:11 -0700 | [diff] [blame] | 195 | attemptNextPhoneAccount(); |
| 196 | return; |
| 197 | } |
| 198 | } |
| 199 | |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 200 | if (mCallResponse != null && attempt != null) { |
Ihab Awad | 293edf2 | 2014-07-24 17:52:29 -0700 | [diff] [blame] | 201 | Log.i(this, "Trying attempt %s", attempt); |
Evan Charlton | 105d977 | 2014-11-25 14:08:53 -0800 | [diff] [blame] | 202 | PhoneAccountHandle phoneAccount = attempt.connectionManagerPhoneAccount; |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 203 | mService = mRepository.getService(phoneAccount.getComponentName(), |
| 204 | phoneAccount.getUserHandle()); |
| 205 | if (mService == null) { |
Ihab Awad | 293edf2 | 2014-07-24 17:52:29 -0700 | [diff] [blame] | 206 | Log.i(this, "Found no connection service for attempt %s", attempt); |
Ihab Awad | 69eb0f5 | 2014-07-18 11:20:37 -0700 | [diff] [blame] | 207 | attemptNextPhoneAccount(); |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 208 | } else { |
Brad Ebinger | 6e8f3d7 | 2016-06-20 11:35:42 -0700 | [diff] [blame] | 209 | mConnectionAttempt++; |
Ihab Awad | b78b276 | 2014-07-25 15:16:23 -0700 | [diff] [blame] | 210 | mCall.setConnectionManagerPhoneAccount(attempt.connectionManagerPhoneAccount); |
| 211 | mCall.setTargetPhoneAccount(attempt.targetPhoneAccount); |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 212 | mCall.setConnectionService(mService); |
| 213 | setTimeoutIfNeeded(mService, attempt); |
Sailesh Nepal | 646fa3d | 2015-01-28 02:55:36 -0800 | [diff] [blame] | 214 | |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 215 | mService.createConnection(mCall, this); |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 216 | } |
| 217 | } else { |
Ihab Awad | 69eb0f5 | 2014-07-18 11:20:37 -0700 | [diff] [blame] | 218 | Log.v(this, "attemptNextPhoneAccount, no more accounts, failing"); |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 219 | DisconnectCause disconnectCause = mLastErrorDisconnectCause != null ? |
| 220 | mLastErrorDisconnectCause : new DisconnectCause(DisconnectCause.ERROR); |
| 221 | notifyCallConnectionFailure(disconnectCause); |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 222 | } |
| 223 | } |
| 224 | |
Sailesh Nepal | 646fa3d | 2015-01-28 02:55:36 -0800 | [diff] [blame] | 225 | private void setTimeoutIfNeeded(ConnectionServiceWrapper service, CallAttemptRecord attempt) { |
| 226 | clearTimeout(); |
| 227 | |
| 228 | CreateConnectionTimeout timeout = new CreateConnectionTimeout( |
| 229 | mContext, mPhoneAccountRegistrar, service, mCall); |
| 230 | if (timeout.isTimeoutNeededForCall(getConnectionServices(mAttemptRecords), |
| 231 | attempt.connectionManagerPhoneAccount)) { |
| 232 | mTimeout = timeout; |
| 233 | timeout.registerTimeout(); |
| 234 | } |
| 235 | } |
| 236 | |
| 237 | private void clearTimeout() { |
| 238 | if (mTimeout != null) { |
| 239 | mTimeout.unregisterTimeout(); |
| 240 | mTimeout = null; |
| 241 | } |
| 242 | } |
| 243 | |
Sailesh Nepal | 7957f9c | 2014-08-09 17:13:19 -0700 | [diff] [blame] | 244 | private boolean shouldSetConnectionManager() { |
| 245 | if (mAttemptRecords.size() == 0) { |
| 246 | return false; |
Ihab Awad | 293edf2 | 2014-07-24 17:52:29 -0700 | [diff] [blame] | 247 | } |
Ihab Awad | c17294c | 2014-08-04 19:23:37 -0700 | [diff] [blame] | 248 | |
Sailesh Nepal | 7957f9c | 2014-08-09 17:13:19 -0700 | [diff] [blame] | 249 | if (mAttemptRecords.size() > 1) { |
| 250 | Log.d(this, "shouldSetConnectionManager, error, mAttemptRecords should not have more " |
| 251 | + "than 1 record"); |
| 252 | return false; |
| 253 | } |
| 254 | |
Tony Mak | 240656f | 2015-12-04 11:36:22 +0000 | [diff] [blame] | 255 | PhoneAccountHandle connectionManager = |
| 256 | mPhoneAccountRegistrar.getSimCallManagerFromCall(mCall); |
Sailesh Nepal | 7957f9c | 2014-08-09 17:13:19 -0700 | [diff] [blame] | 257 | if (connectionManager == null) { |
| 258 | return false; |
| 259 | } |
| 260 | |
| 261 | PhoneAccountHandle targetPhoneAccountHandle = mAttemptRecords.get(0).targetPhoneAccount; |
| 262 | if (Objects.equals(connectionManager, targetPhoneAccountHandle)) { |
| 263 | return false; |
| 264 | } |
| 265 | |
| 266 | // Connection managers are only allowed to manage SIM subscriptions. |
Santos Cordon | 6a21264 | 2015-05-08 16:35:23 -0700 | [diff] [blame] | 267 | // 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] | 268 | PhoneAccount targetPhoneAccount = mPhoneAccountRegistrar |
| 269 | .getPhoneAccountUnchecked(targetPhoneAccountHandle); |
Sailesh Nepal | 91fc809 | 2015-02-14 15:44:55 -0800 | [diff] [blame] | 270 | if (targetPhoneAccount == null) { |
| 271 | Log.d(this, "shouldSetConnectionManager, phone account not found"); |
| 272 | return false; |
| 273 | } |
Sailesh Nepal | 7957f9c | 2014-08-09 17:13:19 -0700 | [diff] [blame] | 274 | boolean isSimSubscription = (targetPhoneAccount.getCapabilities() & |
| 275 | PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION) != 0; |
| 276 | if (!isSimSubscription) { |
| 277 | return false; |
| 278 | } |
| 279 | |
| 280 | return true; |
| 281 | } |
| 282 | |
| 283 | // If there exists a registered connection manager then use it. |
| 284 | private void adjustAttemptsForConnectionManager() { |
| 285 | if (shouldSetConnectionManager()) { |
| 286 | CallAttemptRecord record = new CallAttemptRecord( |
Tony Mak | 240656f | 2015-12-04 11:36:22 +0000 | [diff] [blame] | 287 | mPhoneAccountRegistrar.getSimCallManagerFromCall(mCall), |
Sailesh Nepal | 7957f9c | 2014-08-09 17:13:19 -0700 | [diff] [blame] | 288 | mAttemptRecords.get(0).targetPhoneAccount); |
mike dooley | 10a5831 | 2014-11-06 13:46:19 -0800 | [diff] [blame] | 289 | Log.v(this, "setConnectionManager, changing %s -> %s", mAttemptRecords.get(0), record); |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 290 | mAttemptRecords.add(0, record); |
Sailesh Nepal | 7957f9c | 2014-08-09 17:13:19 -0700 | [diff] [blame] | 291 | } else { |
| 292 | Log.v(this, "setConnectionManager, not changing"); |
Ihab Awad | 293edf2 | 2014-07-24 17:52:29 -0700 | [diff] [blame] | 293 | } |
| 294 | } |
| 295 | |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 296 | // 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] | 297 | // plain PSTN connection services are listed, and nothing else. |
Brad Ebinger | e6c481a | 2016-05-12 14:13:26 -0700 | [diff] [blame] | 298 | private void adjustAttemptsForEmergency(PhoneAccountHandle preferredPAH) { |
Tyler Gunn | 6ffe531 | 2015-08-12 08:19:20 -0700 | [diff] [blame] | 299 | if (mCall.isEmergencyCall()) { |
Ihab Awad | 69eb0f5 | 2014-07-18 11:20:37 -0700 | [diff] [blame] | 300 | Log.i(this, "Emergency number detected"); |
Ihab Awad | 293edf2 | 2014-07-24 17:52:29 -0700 | [diff] [blame] | 301 | mAttemptRecords.clear(); |
Tony Mak | 240656f | 2015-12-04 11:36:22 +0000 | [diff] [blame] | 302 | // Phone accounts in profile do not handle emergency call, use phone accounts in |
| 303 | // current user. |
| 304 | List<PhoneAccount> allAccounts = mPhoneAccountRegistrar |
| 305 | .getAllPhoneAccountsOfCurrentUser(); |
Yorke Lee | c127211 | 2014-10-16 09:50:00 -0700 | [diff] [blame] | 306 | |
| 307 | if (allAccounts.isEmpty()) { |
| 308 | // If the list of phone accounts is empty at this point, it means Telephony hasn't |
| 309 | // registered any phone accounts yet. Add a fallback emergency phone account so |
| 310 | // that emergency calls can still go through. We create a new ArrayLists here just |
| 311 | // in case the implementation of PhoneAccountRegistrar ever returns an unmodifiable |
| 312 | // list. |
| 313 | allAccounts = new ArrayList<PhoneAccount>(); |
| 314 | allAccounts.add(TelephonyUtil.getDefaultEmergencyPhoneAccount()); |
| 315 | } |
| 316 | |
Brad Ebinger | e6c481a | 2016-05-12 14:13:26 -0700 | [diff] [blame] | 317 | // First, possibly add the SIM phone account that the user prefers |
| 318 | PhoneAccount preferredPA = mPhoneAccountRegistrar.getPhoneAccountUnchecked( |
| 319 | preferredPAH); |
| 320 | if (preferredPA != null && |
| 321 | preferredPA.hasCapabilities(PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS) && |
| 322 | preferredPA.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) { |
| 323 | Log.i(this, "Will try PSTN account %s for emergency", |
| 324 | preferredPA.getAccountHandle()); |
| 325 | mAttemptRecords.add(new CallAttemptRecord(preferredPAH, preferredPAH)); |
| 326 | } |
| 327 | |
| 328 | // Next, add all SIM phone accounts which can place emergency calls. |
| 329 | TelephonyUtil.sortSimPhoneAccounts(mContext, allAccounts); |
Tyler Gunn | 8e0fef4 | 2014-09-08 18:34:44 -0700 | [diff] [blame] | 330 | for (PhoneAccount phoneAccount : allAccounts) { |
| 331 | if (phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS) && |
| 332 | phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) { |
Brad Ebinger | e6c481a | 2016-05-12 14:13:26 -0700 | [diff] [blame] | 333 | PhoneAccountHandle phoneAccountHandle = phoneAccount.getAccountHandle(); |
| 334 | // Don't add the preferred account since it has already been added previously. |
| 335 | if (!phoneAccountHandle.equals(preferredPAH)) { |
| 336 | Log.i(this, "Will try PSTN account %s for emergency", phoneAccountHandle); |
| 337 | mAttemptRecords.add(new CallAttemptRecord(phoneAccountHandle, |
| 338 | phoneAccountHandle)); |
| 339 | } |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 340 | } |
| 341 | } |
Tyler Gunn | 6e6f6d1 | 2014-08-20 15:22:18 -0700 | [diff] [blame] | 342 | |
Tyler Gunn | 8e0fef4 | 2014-09-08 18:34:44 -0700 | [diff] [blame] | 343 | // 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] | 344 | PhoneAccountHandle callManagerHandle = |
| 345 | mPhoneAccountRegistrar.getSimCallManagerOfCurrentUser(); |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 346 | if (callManagerHandle != null) { |
| 347 | // 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] | 348 | PhoneAccount callManager = mPhoneAccountRegistrar |
Tony Mak | 240656f | 2015-12-04 11:36:22 +0000 | [diff] [blame] | 349 | .getPhoneAccountUnchecked(callManagerHandle); |
Sailesh Nepal | 91fc809 | 2015-02-14 15:44:55 -0800 | [diff] [blame] | 350 | if (callManager != null && callManager.hasCapabilities( |
| 351 | PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS)) { |
Tyler Gunn | 8e0fef4 | 2014-09-08 18:34:44 -0700 | [diff] [blame] | 352 | CallAttemptRecord callAttemptRecord = new CallAttemptRecord(callManagerHandle, |
Tony Mak | 240656f | 2015-12-04 11:36:22 +0000 | [diff] [blame] | 353 | mPhoneAccountRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser( |
| 354 | mCall.getHandle().getScheme())); |
Tyler Gunn | 8e0fef4 | 2014-09-08 18:34:44 -0700 | [diff] [blame] | 355 | if (!mAttemptRecords.contains(callAttemptRecord)) { |
| 356 | Log.i(this, "Will try Connection Manager account %s for emergency", |
| 357 | callManager); |
| 358 | mAttemptRecords.add(callAttemptRecord); |
| 359 | } |
| 360 | } |
Tyler Gunn | 6e6f6d1 | 2014-08-20 15:22:18 -0700 | [diff] [blame] | 361 | } |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 362 | } |
| 363 | } |
| 364 | |
Sailesh Nepal | 646fa3d | 2015-01-28 02:55:36 -0800 | [diff] [blame] | 365 | /** Returns all connection services used by the call attempt records. */ |
| 366 | private static Collection<PhoneAccountHandle> getConnectionServices( |
| 367 | List<CallAttemptRecord> records) { |
| 368 | HashSet<PhoneAccountHandle> result = new HashSet<>(); |
| 369 | for (CallAttemptRecord record : records) { |
| 370 | result.add(record.connectionManagerPhoneAccount); |
| 371 | } |
| 372 | return result; |
| 373 | } |
| 374 | |
Tony Mak | 240656f | 2015-12-04 11:36:22 +0000 | [diff] [blame] | 375 | |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 376 | private void notifyCallConnectionFailure(DisconnectCause errorDisconnectCause) { |
| 377 | if (mCallResponse != null) { |
| 378 | clearTimeout(); |
| 379 | mCallResponse.handleCreateConnectionFailure(errorDisconnectCause); |
| 380 | mCallResponse = null; |
| 381 | mCall.clearConnectionService(); |
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 | } |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 384 | |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 385 | @Override |
| 386 | public void handleCreateConnectionSuccess( |
| 387 | CallIdMapper idMapper, |
| 388 | ParcelableConnection connection) { |
| 389 | if (mCallResponse == null) { |
| 390 | // Nobody is listening for this connection attempt any longer; ask the responsible |
| 391 | // ConnectionService to tear down any resources associated with the call |
| 392 | mService.abort(mCall); |
| 393 | } else { |
| 394 | // Success -- share the good news and remember that we are no longer interested |
| 395 | // in hearing about any more attempts |
| 396 | mCallResponse.handleCreateConnectionSuccess(idMapper, connection); |
| 397 | mCallResponse = null; |
| 398 | // If there's a timeout running then don't clear it. The timeout can be triggered |
| 399 | // 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] | 400 | } |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 401 | } |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 402 | |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 403 | private boolean shouldFailCallIfConnectionManagerFails(DisconnectCause cause) { |
| 404 | // Connection Manager does not exist or does not match registered Connection Manager |
| 405 | // Since Connection manager is a proxy for SIM, fall back to SIM |
| 406 | PhoneAccountHandle handle = mCall.getConnectionManagerPhoneAccount(); |
| 407 | if (handle == null || !handle.equals(mPhoneAccountRegistrar.getSimCallManagerFromCall( |
| 408 | mCall))) { |
Sailesh Nepal | bafadce | 2014-11-05 18:40:21 -0800 | [diff] [blame] | 409 | return false; |
| 410 | } |
| 411 | |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 412 | // The Call's Connection Service does not exist |
| 413 | ConnectionServiceWrapper connectionManager = mCall.getConnectionService(); |
| 414 | if (connectionManager == null) { |
| 415 | return true; |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 416 | } |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 417 | |
| 418 | // In this case, fall back to a sim because connection manager declined |
| 419 | if (cause.getCode() == DisconnectCause.CONNECTION_MANAGER_NOT_SUPPORTED) { |
| 420 | Log.d(CreateConnectionProcessor.this, "Connection manager declined to handle the " |
| 421 | + "call, falling back to not using a connection manager"); |
| 422 | return false; |
| 423 | } |
| 424 | |
| 425 | if (!connectionManager.isServiceValid("createConnection")) { |
| 426 | Log.d(CreateConnectionProcessor.this, "Connection manager unbound while trying " |
| 427 | + "create a connection, falling back to not using a connection manager"); |
| 428 | return false; |
| 429 | } |
| 430 | |
| 431 | // Do not fall back from connection manager and simply fail call if the failure reason is |
| 432 | // other |
| 433 | Log.d(CreateConnectionProcessor.this, "Connection Manager denied call with the following " + |
| 434 | "error: " + cause.getReason() + ". Not falling back to SIM."); |
| 435 | return true; |
| 436 | } |
| 437 | |
| 438 | @Override |
| 439 | public void handleCreateConnectionFailure(DisconnectCause errorDisconnectCause) { |
| 440 | // Failure of some sort; record the reasons for failure and try again if possible |
| 441 | Log.d(CreateConnectionProcessor.this, "Connection failed: (%s)", errorDisconnectCause); |
Brad Ebinger | e6c481a | 2016-05-12 14:13:26 -0700 | [diff] [blame] | 442 | if (shouldFailCallIfConnectionManagerFails(errorDisconnectCause)) { |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 443 | notifyCallConnectionFailure(errorDisconnectCause); |
| 444 | return; |
| 445 | } |
Santos Cordon | 8ff99f3 | 2016-02-12 15:30:44 -0800 | [diff] [blame] | 446 | mLastErrorDisconnectCause = errorDisconnectCause; |
Brad Ebinger | f190007 | 2015-11-12 17:25:06 -0800 | [diff] [blame] | 447 | attemptNextPhoneAccount(); |
Sailesh Nepal | 664837f | 2014-07-14 16:31:51 -0700 | [diff] [blame] | 448 | } |
| 449 | } |