CreateConnectionProcessor.java revision b78b27693afbe9736f0a54ec473328955251f885
1664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal/*
2664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal * Copyright 2014, The Android Open Source Project
3664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal *
4664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal * Licensed under the Apache License, Version 2.0 (the "License");
5664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal * you may not use this file except in compliance with the License.
6664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal * You may obtain a copy of the License at
7664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal *
8664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal *     http://www.apache.org/licenses/LICENSE-2.0
9664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal *
10664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal * Unless required by applicable law or agreed to in writing, software
11664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal * distributed under the License is distributed on an "AS IS" BASIS,
12664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal * See the License for the specific language governing permissions and
14664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal * limitations under the License.
15664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal */
16664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal
17664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepalpackage com.android.telecomm;
18664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal
1972890ce844f92f45c56f3cccd1f2fd03ff12c3c2Santos Cordonimport android.telecomm.ConnectionRequest;
2072890ce844f92f45c56f3cccd1f2fd03ff12c3c2Santos Cordonimport android.telecomm.ParcelableConnection;
2189176375c8d97db25588f720952a4fadbce2f9a3Evan Charltonimport android.telecomm.PhoneAccountHandle;
22664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepalimport android.telephony.DisconnectCause;
23664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal
24664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepalimport java.util.ArrayList;
25664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepalimport java.util.Iterator;
26664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepalimport java.util.List;
27293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awadimport java.util.Objects;
28664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal
29664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal/**
30664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal * This class creates connections to place new outgoing calls to attached to an existing incoming
31664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal * call. In either case, this class cycles through a set of connection services until:
32664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal *   - a connection service returns a newly created connection in which case the call is displayed
33664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal *     to the user
34664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal *   - a connection service cancels the process, in which case the call is aborted
35664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal */
36664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepalfinal class CreateConnectionProcessor {
37293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad
38293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad    // Describes information required to attempt to make a phone call
39293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad    private static class CallAttemptRecord {
40293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        // The PhoneAccount describing the target connection service which we will
41293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        // contact in order to process an attempt
42b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        public final PhoneAccountHandle connectionManagerPhoneAccount;
43293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        // The PhoneAccount which we will tell the target connection service to use
44293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        // for attempting to make the actual phone call
45b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        public final PhoneAccountHandle targetPhoneAccount;
46293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad
47293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        public CallAttemptRecord(
48b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                PhoneAccountHandle connectionManagerPhoneAccount,
49b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                PhoneAccountHandle targetPhoneAccount) {
50b78b27693afbe9736f0a54ec473328955251f885Ihab Awad            this.connectionManagerPhoneAccount = connectionManagerPhoneAccount;
51b78b27693afbe9736f0a54ec473328955251f885Ihab Awad            this.targetPhoneAccount = targetPhoneAccount;
52293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        }
53293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad
54293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        @Override
55293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        public String toString() {
56293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad            return "CallAttemptRecord("
57b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                    + Objects.toString(connectionManagerPhoneAccount) + ","
58b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                    + Objects.toString(targetPhoneAccount) + ")";
59293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        }
60293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad    }
61293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad
62664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal    private final Call mCall;
63664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal    private final ConnectionServiceRepository mRepository;
64293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad    private List<CallAttemptRecord> mAttemptRecords;
65293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad    private Iterator<CallAttemptRecord> mAttemptRecordIterator;
66664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal    private CreateConnectionResponse mResponse;
67fd6ca447a45c47aeb3956964103770475c655a26Santos Cordon    private int mLastErrorCode = DisconnectCause.OUTGOING_FAILURE;
68664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal    private String mLastErrorMsg;
69664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal
70664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal    CreateConnectionProcessor(
71664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            Call call, ConnectionServiceRepository repository, CreateConnectionResponse response) {
72664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        mCall = call;
73664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        mRepository = repository;
74664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        mResponse = response;
75664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal    }
76664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal
77664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal    void process() {
78664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        Log.v(this, "process");
79293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        mAttemptRecords = new ArrayList<>();
80b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        if (mCall.getTargetPhoneAccount() != null) {
81293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad            mAttemptRecords.add(
82b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                    new CallAttemptRecord(mCall.getTargetPhoneAccount(), mCall.getTargetPhoneAccount()));
83664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        }
84293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        adjustAttemptsForWifi();
85293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        adjustAttemptsForEmergency();
86293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        mAttemptRecordIterator = mAttemptRecords.iterator();
8769eb0f582babcedc1dc5e6613a27867be6e8d0e0Ihab Awad        attemptNextPhoneAccount();
88664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal    }
89664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal
90664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal    void abort() {
91664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        Log.v(this, "abort");
92664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal
93664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        // Clear the response first to prevent attemptNextConnectionService from attempting any
94664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        // more services.
95664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        CreateConnectionResponse response = mResponse;
96664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        mResponse = null;
97664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal
98664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        ConnectionServiceWrapper service = mCall.getConnectionService();
99664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        if (service != null) {
100664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            service.abort(mCall);
101664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            mCall.clearConnectionService();
102664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        }
103664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        if (response != null) {
104664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            response.handleCreateConnectionCancelled();
105664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        }
106664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal    }
107664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal
10869eb0f582babcedc1dc5e6613a27867be6e8d0e0Ihab Awad    private void attemptNextPhoneAccount() {
10969eb0f582babcedc1dc5e6613a27867be6e8d0e0Ihab Awad        Log.v(this, "attemptNextPhoneAccount");
110664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal
111293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        if (mResponse != null && mAttemptRecordIterator.hasNext()) {
112293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad            CallAttemptRecord attempt = mAttemptRecordIterator.next();
113293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad            Log.i(this, "Trying attempt %s", attempt);
11494d01629010a61f6112713f22330d5fd4baae851Evan Charlton            ConnectionServiceWrapper service =
115b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                    mRepository.getService(
116b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                            attempt.connectionManagerPhoneAccount.getComponentName());
117664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            if (service == null) {
118293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad                Log.i(this, "Found no connection service for attempt %s", attempt);
11969eb0f582babcedc1dc5e6613a27867be6e8d0e0Ihab Awad                attemptNextPhoneAccount();
120664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            } else {
121b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                mCall.setConnectionManagerPhoneAccount(attempt.connectionManagerPhoneAccount);
122b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                mCall.setTargetPhoneAccount(attempt.targetPhoneAccount);
123664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal                mCall.setConnectionService(service);
124664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal                Log.i(this, "Attempting to call from %s", service.getComponentName());
125664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal                service.createConnection(mCall, new Response(service));
126664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            }
127664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        } else {
12869eb0f582babcedc1dc5e6613a27867be6e8d0e0Ihab Awad            Log.v(this, "attemptNextPhoneAccount, no more accounts, failing");
129664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            if (mResponse != null) {
130664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal                mResponse.handleCreateConnectionFailed(mLastErrorCode, mLastErrorMsg);
131664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal                mResponse = null;
132664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal                mCall.clearConnectionService();
133664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            }
134664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        }
135664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal    }
136664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal
137293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad    // If there exists a registered Wi-Fi calling service, use it.
138293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad    private void adjustAttemptsForWifi() {
139293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        switch (mAttemptRecords.size()) {
140293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad            case 0:
141293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad                return;
142293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad            case 1:
143293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad                break;
144293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad            default:
145293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad                Log.d(this, "Unexpectedly have > 1 attempt: %s", mAttemptRecords);
146293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad                return;
147293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        }
148293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        PhoneAccountHandle simCallManager =
149293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad                TelecommApp.getInstance().getPhoneAccountRegistrar().getSimCallManager();
150293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        if (simCallManager != null &&
151b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                !Objects.equals(simCallManager, mAttemptRecords.get(0).targetPhoneAccount)) {
152293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad            mAttemptRecords.set(
153293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad                    0,
154293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad                    new CallAttemptRecord(
155293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad                            simCallManager,
156b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                            mAttemptRecords.get(0).targetPhoneAccount));
157293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        }
158293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad    }
159293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad
160664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal    // If we are possibly attempting to call a local emergency number, ensure that the
16169eb0f582babcedc1dc5e6613a27867be6e8d0e0Ihab Awad    // plain PSTN connection services are listed, and nothing else.
162293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad    private void adjustAttemptsForEmergency()  {
16369eb0f582babcedc1dc5e6613a27867be6e8d0e0Ihab Awad        if (TelephonyUtil.shouldProcessAsEmergency(TelecommApp.getInstance(), mCall.getHandle())) {
16469eb0f582babcedc1dc5e6613a27867be6e8d0e0Ihab Awad            Log.i(this, "Emergency number detected");
165293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad            mAttemptRecords.clear();
16694d01629010a61f6112713f22330d5fd4baae851Evan Charlton            List<PhoneAccountHandle> allAccountHandles = TelecommApp.getInstance()
16794d01629010a61f6112713f22330d5fd4baae851Evan Charlton                    .getPhoneAccountRegistrar().getEnabledPhoneAccounts();
16894d01629010a61f6112713f22330d5fd4baae851Evan Charlton            for (int i = 0; i < allAccountHandles.size(); i++) {
16994d01629010a61f6112713f22330d5fd4baae851Evan Charlton                if (TelephonyUtil.isPstnComponentName(
17094d01629010a61f6112713f22330d5fd4baae851Evan Charlton                        allAccountHandles.get(i).getComponentName())) {
17194d01629010a61f6112713f22330d5fd4baae851Evan Charlton                    Log.i(this, "Will try PSTN account %s for emergency", allAccountHandles.get(i));
172293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad                    mAttemptRecords.add(
173293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad                            new CallAttemptRecord(
174293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad                                    allAccountHandles.get(i),
175293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad                                    allAccountHandles.get(i)));
176664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal                }
177664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            }
178664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        }
179664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal    }
180664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal
181664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal    private class Response implements CreateConnectionResponse {
182664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        private final ConnectionServiceWrapper mService;
183664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal
184664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        Response(ConnectionServiceWrapper service) {
185664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            mService = service;
186664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        }
187664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal
188664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        @Override
18972890ce844f92f45c56f3cccd1f2fd03ff12c3c2Santos Cordon        public void handleCreateConnectionSuccessful(
19072890ce844f92f45c56f3cccd1f2fd03ff12c3c2Santos Cordon                ConnectionRequest request, ParcelableConnection connection) {
191664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            if (mResponse == null) {
192664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal                mService.abort(mCall);
193664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            } else {
19472890ce844f92f45c56f3cccd1f2fd03ff12c3c2Santos Cordon                mResponse.handleCreateConnectionSuccessful(request, connection);
19572890ce844f92f45c56f3cccd1f2fd03ff12c3c2Santos Cordon                mResponse = null;
196664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            }
197664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        }
198664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal
199664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        @Override
200664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        public void handleCreateConnectionFailed(int code, String msg) {
201664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            mLastErrorCode = code;
202664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            mLastErrorMsg = msg;
20369eb0f582babcedc1dc5e6613a27867be6e8d0e0Ihab Awad            Log.d(CreateConnectionProcessor.this, "Connection failed: %d (%s)", code, msg);
20469eb0f582babcedc1dc5e6613a27867be6e8d0e0Ihab Awad            attemptNextPhoneAccount();
205664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        }
206664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal
207664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        @Override
208664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        public void handleCreateConnectionCancelled() {
209664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            if (mResponse != null) {
210664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal                mResponse.handleCreateConnectionCancelled();
211664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal                mResponse = null;
212664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            }
213664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        }
214664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal    }
215664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal}
216