CreateConnectionProcessor.java revision 664837f9a8a98f98876417a0bfff64834e8032fa
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
19664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepalimport android.content.ComponentName;
20664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepalimport android.net.Uri;
21664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepalimport android.telephony.DisconnectCause;
22664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepalimport android.telephony.PhoneNumberUtils;
23664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepalimport android.telecomm.ConnectionRequest;
24664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal
25664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepalimport java.util.ArrayList;
26664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepalimport java.util.Iterator;
27664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepalimport java.util.List;
28664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepalimport java.util.Map;
29664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal
30664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal/**
31664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal * This class creates connections to place new outgoing calls to attached to an existing incoming
32664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal * call. In either case, this class cycles through a set of connection services until:
33664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal *   - a connection service returns a newly created connection in which case the call is displayed
34664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal *     to the user
35664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal *   - a connection service cancels the process, in which case the call is aborted
36664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal */
37664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepalfinal class CreateConnectionProcessor {
38664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal    private final Call mCall;
39664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal    private final ConnectionServiceRepository mRepository;
40664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal    private List<ComponentName> mServiceComponentNames;
41664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal    private Iterator<ComponentName> mServiceComponentNameIterator;
42664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal    private CreateConnectionResponse mResponse;
43664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal    private int mLastErrorCode = DisconnectCause.ERROR_UNSPECIFIED;
44664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal    private String mLastErrorMsg;
45664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal
46664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal    CreateConnectionProcessor(
47664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            Call call, ConnectionServiceRepository repository, CreateConnectionResponse response) {
48664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        mCall = call;
49664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        mRepository = repository;
50664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        mResponse = response;
51664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal    }
52664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal
53664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal    void process() {
54664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        Log.v(this, "process");
55664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal
56664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        mServiceComponentNames = new ArrayList<>();
57664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal
58664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        // TODO(sail): Remove once there's a way to pick the service.
59664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        ArrayList<ComponentName> priorityComponents = new ArrayList<>();
60664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        priorityComponents.add(new ComponentName("com.android.phone",
61664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal                "com.android.services.telephony.sip.SipConnectionService"));
62664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        priorityComponents.add(new ComponentName("com.google.android.talk",
63664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal                "com.google.android.apps.babel.telephony.TeleConnectionService"));
64664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        priorityComponents.add(new ComponentName("com.android.telecomm.tests",
65664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal                "com.android.telecomm.testapps.TestConnectionService"));
66664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal
67664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        for (ConnectionServiceWrapper service : mRepository.lookupServices()) {
68664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            ComponentName serviceName = service.getComponentName();
69664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            if (priorityComponents.contains(serviceName)) {
70664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal                Log.i(this, "Moving connection service %s to top of list", serviceName);
71664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal                mServiceComponentNames .add(0, serviceName);
72664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            } else {
73664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal                mServiceComponentNames.add(serviceName);
74664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            }
75664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        }
76664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal
77664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        adjustComponentNamesForEmergency();
78664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        mServiceComponentNameIterator = mServiceComponentNames.iterator();
79664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        attemptNextConnectionService();
80664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal    }
81664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal
82664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal    void abort() {
83664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        Log.v(this, "abort");
84664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal
85664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        // Clear the response first to prevent attemptNextConnectionService from attempting any
86664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        // more services.
87664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        CreateConnectionResponse response = mResponse;
88664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        mResponse = null;
89664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal
90664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        ConnectionServiceWrapper service = mCall.getConnectionService();
91664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        if (service != null) {
92664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            service.abort(mCall);
93664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            mCall.clearConnectionService();
94664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        }
95664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        if (response != null) {
96664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            response.handleCreateConnectionCancelled();
97664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        }
98664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal    }
99664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal
100664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal    private void attemptNextConnectionService() {
101664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        Log.v(this, "attemptNextConnectionService");
102664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal
103664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        if (mResponse != null && mServiceComponentNameIterator.hasNext()) {
104664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            ComponentName component = mServiceComponentNameIterator.next();
105664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            ConnectionServiceWrapper service = mRepository.getService(component);
106664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            if (service == null) {
107664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal                attemptNextConnectionService();
108664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            } else {
109664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal                mCall.setConnectionService(service);
110664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal                Log.i(this, "Attempting to call from %s", service.getComponentName());
111664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal                service.createConnection(mCall, new Response(service));
112664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            }
113664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        } else {
114664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            Log.v(this, "attemptNextConnectionService, no more services, failing");
115664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            if (mResponse != null) {
116664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal                mResponse.handleCreateConnectionFailed(mLastErrorCode, mLastErrorMsg);
117664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal                mResponse = null;
118664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal                mCall.clearConnectionService();
119664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            }
120664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        }
121664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal    }
122664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal
123664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal    // If we are possibly attempting to call a local emergency number, ensure that the
124664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal    // plain PSTN connection service, if it exists, is attempted first.
125664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal    private void adjustComponentNamesForEmergency()  {
126664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        if (shouldProcessAsEmergency(mCall.getHandle())) {
127664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            for (int i = 0; i < mServiceComponentNames.size(); i++) {
128664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal                if (TelephonyUtil.isPstnComponentName(mServiceComponentNames.get(i))) {
129664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal                    mServiceComponentNames.add(0, mServiceComponentNames.remove(i));
130664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal                    return;
131664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal                }
132664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            }
133664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        }
134664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal    }
135664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal
136664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal    private boolean shouldProcessAsEmergency(Uri handle) {
137664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        return handle != null && PhoneNumberUtils.isPotentialLocalEmergencyNumber(
138664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal                TelecommApp.getInstance(), handle.getSchemeSpecificPart());
139664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal    }
140664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal
141664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal    private class Response implements CreateConnectionResponse {
142664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        private final ConnectionServiceWrapper mService;
143664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal
144664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        Response(ConnectionServiceWrapper service) {
145664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            mService = service;
146664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        }
147664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal
148664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        @Override
149664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        public void handleCreateConnectionSuccessful(ConnectionRequest request) {
150664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            if (mResponse == null) {
151664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal                mService.abort(mCall);
152664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            } else {
153664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal                mResponse.handleCreateConnectionSuccessful(request);
154664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal                mResponse= null;
155664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            }
156664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        }
157664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal
158664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        @Override
159664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        public void handleCreateConnectionFailed(int code, String msg) {
160664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            mLastErrorCode = code;
161664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            mLastErrorMsg = msg;
162664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            attemptNextConnectionService();
163664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        }
164664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal
165664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        @Override
166664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        public void handleCreateConnectionCancelled() {
167664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            if (mResponse != null) {
168664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal                mResponse.handleCreateConnectionCancelled();
169664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal                mResponse = null;
170664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal            }
171664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal        }
172664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal    }
173664837f9a8a98f98876417a0bfff64834e8032faSailesh Nepal}
174