blob: 45008c06fb434058756bfeeb4f1d9657942b0ced [file] [log] [blame]
/*
* Copyright 2014, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.telecomm;
import android.telecomm.PhoneAccount;
import android.telephony.DisconnectCause;
import android.telecomm.ConnectionRequest;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* This class creates connections to place new outgoing calls to attached to an existing incoming
* call. In either case, this class cycles through a set of connection services until:
* - a connection service returns a newly created connection in which case the call is displayed
* to the user
* - a connection service cancels the process, in which case the call is aborted
*/
final class CreateConnectionProcessor {
private final Call mCall;
private final ConnectionServiceRepository mRepository;
private List<PhoneAccount> mPhoneAccounts;
private Iterator<PhoneAccount> mPhoneAccountIterator;
private CreateConnectionResponse mResponse;
private int mLastErrorCode = DisconnectCause.ERROR_UNSPECIFIED;
private String mLastErrorMsg;
CreateConnectionProcessor(
Call call, ConnectionServiceRepository repository, CreateConnectionResponse response) {
mCall = call;
mRepository = repository;
mResponse = response;
}
void process() {
Log.v(this, "process");
mPhoneAccounts = new ArrayList<>();
if (mCall.getPhoneAccount() != null) {
mPhoneAccounts.add(mCall.getPhoneAccount());
}
adjustPhoneAccountsForEmergency();
mPhoneAccountIterator = mPhoneAccounts.iterator();
attemptNextPhoneAccount();
}
void abort() {
Log.v(this, "abort");
// Clear the response first to prevent attemptNextConnectionService from attempting any
// more services.
CreateConnectionResponse response = mResponse;
mResponse = null;
ConnectionServiceWrapper service = mCall.getConnectionService();
if (service != null) {
service.abort(mCall);
mCall.clearConnectionService();
}
if (response != null) {
response.handleCreateConnectionCancelled();
}
}
private void attemptNextPhoneAccount() {
Log.v(this, "attemptNextPhoneAccount");
if (mResponse != null && mPhoneAccountIterator.hasNext()) {
PhoneAccount account = mPhoneAccountIterator.next();
Log.i(this, "Trying account %s", account);
ConnectionServiceWrapper service = mRepository.getService(account.getComponentName());
if (service == null) {
Log.i(this, "Found no connection service for account %s", account);
attemptNextPhoneAccount();
} else {
mCall.setPhoneAccount(account);
mCall.setConnectionService(service);
Log.i(this, "Attempting to call from %s", service.getComponentName());
service.createConnection(mCall, new Response(service));
}
} else {
Log.v(this, "attemptNextPhoneAccount, no more accounts, failing");
if (mResponse != null) {
mResponse.handleCreateConnectionFailed(mLastErrorCode, mLastErrorMsg);
mResponse = null;
mCall.clearConnectionService();
}
}
}
// If we are possibly attempting to call a local emergency number, ensure that the
// plain PSTN connection services are listed, and nothing else.
private void adjustPhoneAccountsForEmergency() {
if (TelephonyUtil.shouldProcessAsEmergency(TelecommApp.getInstance(), mCall.getHandle())) {
Log.i(this, "Emergency number detected");
mPhoneAccounts.clear();
List<PhoneAccount> allAccounts = TelecommApp.getInstance().getPhoneAccountRegistrar()
.getEnabledPhoneAccounts();
for (int i = 0; i < allAccounts.size(); i++) {
if (TelephonyUtil.isPstnComponentName(allAccounts.get(i).getComponentName())) {
Log.i(this, "Will try PSTN account %s for emergency", allAccounts.get(i));
mPhoneAccounts.add(allAccounts.get(i));
}
}
}
}
private class Response implements CreateConnectionResponse {
private final ConnectionServiceWrapper mService;
Response(ConnectionServiceWrapper service) {
mService = service;
}
@Override
public void handleCreateConnectionSuccessful(ConnectionRequest request) {
if (mResponse == null) {
mService.abort(mCall);
} else {
mResponse.handleCreateConnectionSuccessful(request);
mResponse= null;
}
}
@Override
public void handleCreateConnectionFailed(int code, String msg) {
mLastErrorCode = code;
mLastErrorMsg = msg;
Log.d(CreateConnectionProcessor.this, "Connection failed: %d (%s)", code, msg);
attemptNextPhoneAccount();
}
@Override
public void handleCreateConnectionCancelled() {
if (mResponse != null) {
mResponse.handleCreateConnectionCancelled();
mResponse = null;
}
}
}
}