blob: bfe8cbce1f6495cc03f306b22bcc17c0611738d2 [file] [log] [blame]
Ben Gilad0bf5b912014-01-28 17:55:57 -08001/*
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
17package com.android.telecomm;
18
19import com.google.common.base.Preconditions;
20import com.google.common.collect.Maps;
Ben Giladd88323b2014-01-29 19:03:19 -080021import com.google.common.collect.Lists;
Ben Gilad0bf5b912014-01-28 17:55:57 -080022
Ben Giladd88323b2014-01-29 19:03:19 -080023import android.os.Handler;
24import android.os.Looper;
Ben Gilad0bf5b912014-01-28 17:55:57 -080025import android.os.RemoteException;
Santos Cordon681663d2014-01-30 04:32:15 -080026import android.telecomm.CallState;
Ben Giladc5b22692014-02-18 20:03:22 -080027import android.telecomm.CallServiceDescriptor;
Ben Giladd88323b2014-01-29 19:03:19 -080028import android.telecomm.ICallServiceSelectionResponse;
Ben Gilad0bf5b912014-01-28 17:55:57 -080029import android.telecomm.ICallServiceSelector;
Sailesh Nepalb6141ae2014-02-18 08:45:26 -080030
31import com.android.telecomm.ServiceBinder.BindCallback;
Ben Gilad0bf5b912014-01-28 17:55:57 -080032
33import java.util.Iterator;
34import java.util.List;
35import java.util.Map;
36import java.util.Set;
37
38/**
39 * Utility class to place a call using the specified set of call-services and ordered selectors.
Ben Giladc5b22692014-02-18 20:03:22 -080040 * Iterates through the selectors and gets a sorted list of supported call-service descriptors
41 * for each selector. Upon receiving each sorted list (one list per selector), each of the
42 * corresponding call services is then attempted until either the outgoing call is placed, the
43 * attempted call is aborted (by the switchboard), or the list is exhausted -- whichever occurs
44 * first.
Ben Gilad0bf5b912014-01-28 17:55:57 -080045 *
Santos Cordon681663d2014-01-30 04:32:15 -080046 * Except for the abort case, all other scenarios should terminate with the switchboard notified
47 * of the result.
Ben Giladd88323b2014-01-29 19:03:19 -080048 *
49 * NOTE(gilad): Currently operating under the assumption that we'll have one timeout per (outgoing)
50 * call attempt. If we (also) like to timeout individual selectors and/or call services, the code
51 * here will need to be re-factored (quite a bit) to support that.
Ben Gilad0bf5b912014-01-28 17:55:57 -080052 */
53final class OutgoingCallProcessor {
54
55 /**
Ben Gilad0bf5b912014-01-28 17:55:57 -080056 * The outgoing call this processor is tasked with placing.
57 */
58 private final Call mCall;
59
60 /**
Ben Giladc5b22692014-02-18 20:03:22 -080061 * The duplicate-free list of currently-available call-service descriptors.
Ben Gilad0bf5b912014-01-28 17:55:57 -080062 */
Ben Giladc5b22692014-02-18 20:03:22 -080063 private final List<CallServiceDescriptor> mCallServiceDescriptors = Lists.newArrayList();
Ben Gilad0bf5b912014-01-28 17:55:57 -080064
65 /**
Sailesh Nepalb6141ae2014-02-18 08:45:26 -080066 * The map of currently-available call-service implementations keyed by call-service ID.
Ben Gilad0bf5b912014-01-28 17:55:57 -080067 */
Sailesh Nepalb6141ae2014-02-18 08:45:26 -080068 private final Map<String, CallServiceWrapper> mCallServicesById = Maps.newHashMap();
Ben Gilad0bf5b912014-01-28 17:55:57 -080069
70 /**
71 * The set of currently-available call-service selector implementations.
72 */
73 private final List<ICallServiceSelector> mSelectors;
74
Ben Giladd88323b2014-01-29 19:03:19 -080075 /** Used to run code (e.g. messages, Runnables) on the main (UI) thread. */
76 private final Handler mHandler = new Handler(Looper.getMainLooper());
77
Santos Cordon681663d2014-01-30 04:32:15 -080078 /** Manages all outgoing call processors. */
79 private final OutgoingCallsManager mOutgoingCallsManager;
80
81 private final Switchboard mSwitchboard;
82
Ben Gilad0bf5b912014-01-28 17:55:57 -080083 /**
Ben Giladc5b22692014-02-18 20:03:22 -080084 * The iterator over the currently-selected ordered list of call-service descriptors.
Ben Gilad0bf5b912014-01-28 17:55:57 -080085 */
Ben Giladc5b22692014-02-18 20:03:22 -080086 private Iterator<CallServiceDescriptor> mCallServiceDescriptorIterator;
Ben Gilad0bf5b912014-01-28 17:55:57 -080087
88 private Iterator<ICallServiceSelector> mSelectorIterator;
89
Santos Cordon681663d2014-01-30 04:32:15 -080090 /**
91 * The last call service which we asked to place the call. If null, it indicates that there
92 * exists no call service that we expect to place this call.
93 */
Santos Cordonc195e362014-02-11 17:05:31 -080094 private CallServiceWrapper mCallService;
Santos Cordon681663d2014-01-30 04:32:15 -080095
Ben Gilad0bf5b912014-01-28 17:55:57 -080096 private boolean mIsAborted = false;
97
98 /**
99 * Persists the specified parameters and iterates through the prioritized list of selectors
100 * passing to each selector (read-only versions of) the call object and all available call-
Ben Giladc5b22692014-02-18 20:03:22 -0800101 * service descriptors. Stops once a matching selector is found. Calls with no matching
102 * selectors will eventually be killed by the cleanup/monitor switchboard handler, which will
103 * in turn call the abort method of this processor via {@link OutgoingCallsManager}.
Ben Gilad0bf5b912014-01-28 17:55:57 -0800104 *
105 * @param call The call to place.
106 * @param callServices The available call-service implementations.
107 * @param selectors The available call-service selector implementations.
Santos Cordon681663d2014-01-30 04:32:15 -0800108 * @param outgoingCallsManager Manager of all outgoing call processors.
109 * @param switchboard The switchboard.
Ben Gilad0bf5b912014-01-28 17:55:57 -0800110 */
111 OutgoingCallProcessor(
112 Call call,
Santos Cordonc195e362014-02-11 17:05:31 -0800113 Set<CallServiceWrapper> callServices,
Ben Gilad0bf5b912014-01-28 17:55:57 -0800114 List<ICallServiceSelector> selectors,
Santos Cordon681663d2014-01-30 04:32:15 -0800115 OutgoingCallsManager outgoingCallsManager,
Ben Gilad0bf5b912014-01-28 17:55:57 -0800116 Switchboard switchboard) {
117
Ben Giladd88323b2014-01-29 19:03:19 -0800118 ThreadUtil.checkOnMainThread();
119
Ben Gilad0bf5b912014-01-28 17:55:57 -0800120 Preconditions.checkNotNull(callServices);
121 Preconditions.checkNotNull(selectors);
122
123 mCall = call;
Ben Gilad0bf5b912014-01-28 17:55:57 -0800124 mSelectors = selectors;
Santos Cordon681663d2014-01-30 04:32:15 -0800125 mOutgoingCallsManager = outgoingCallsManager;
Ben Gilad0bf5b912014-01-28 17:55:57 -0800126 mSwitchboard = switchboard;
127
Ben Giladc5b22692014-02-18 20:03:22 -0800128 // Populate the list and map of call-service descriptors. The list is needed since
Ben Gilad0bf5b912014-01-28 17:55:57 -0800129 // it's being passed down to selectors.
Santos Cordonc195e362014-02-11 17:05:31 -0800130 for (CallServiceWrapper callService : callServices) {
Ben Giladc5b22692014-02-18 20:03:22 -0800131 CallServiceDescriptor descriptor = callService.getDescriptor();
132 mCallServiceDescriptors.add(descriptor);
133 mCallServicesById.put(descriptor.getCallServiceId(), callService);
Ben Gilad0bf5b912014-01-28 17:55:57 -0800134 }
135 }
136
137 /**
138 * Initiates the attempt to place the call. No-op beyond the first invocation.
139 */
140 void process() {
Ben Giladd88323b2014-01-29 19:03:19 -0800141 ThreadUtil.checkOnMainThread();
142
Ben Giladc5b22692014-02-18 20:03:22 -0800143 if (mSelectors.isEmpty() || mCallServiceDescriptors.isEmpty()) {
Ben Gilad0bf5b912014-01-28 17:55:57 -0800144 // TODO(gilad): Consider adding a failure message/type to differentiate the various
145 // cases, or potentially throw an exception in this case.
Santos Cordon681663d2014-01-30 04:32:15 -0800146 mOutgoingCallsManager.handleFailedOutgoingCall(mCall);
Ben Gilad0bf5b912014-01-28 17:55:57 -0800147 } else if (mSelectorIterator == null) {
148 mSelectorIterator = mSelectors.iterator();
149 attemptNextSelector();
150 }
151 }
152
153 /**
154 * Aborts the attempt to place the relevant call. Intended to be invoked by
Santos Cordon681663d2014-01-30 04:32:15 -0800155 * switchboard through the outgoing-calls manager.
Ben Gilad0bf5b912014-01-28 17:55:57 -0800156 */
157 void abort() {
Ben Giladd88323b2014-01-29 19:03:19 -0800158 ThreadUtil.checkOnMainThread();
Santos Cordon681663d2014-01-30 04:32:15 -0800159 resetCallService();
Ben Gilad0bf5b912014-01-28 17:55:57 -0800160 mIsAborted = true;
161 }
162
163 /**
Santos Cordon681663d2014-01-30 04:32:15 -0800164 * Completes the outgoing call sequence by setting the call service on the call object. This is
165 * invoked when the call service adapter receives positive confirmation that the call service
166 * placed the call.
167 */
168 void handleSuccessfulCallAttempt() {
169 abort(); // Technically not needed but playing it safe.
170 mCall.setCallService(mCallService);
171 mCall.setState(CallState.DIALING);
172 resetCallService();
173
174 mSwitchboard.handleSuccessfulOutgoingCall(mCall);
175 }
176
177 /**
178 * Attempts the next call service if the specified call service is the one currently being
179 * attempted.
180 *
181 * @param reason The call-service supplied reason for the failed call attempt.
182 */
183 void handleFailedCallAttempt(String reason) {
184 attemptNextCallService();
185 }
186
187 /**
Ben Gilad0bf5b912014-01-28 17:55:57 -0800188 * Attempts to place the call using the next selector, no-op if no other selectors
189 * are available.
190 */
191 private void attemptNextSelector() {
192 if (mIsAborted) {
193 return;
194 }
195
196 if (mSelectorIterator.hasNext()) {
197 ICallServiceSelector selector = mSelectorIterator.next();
Ben Giladd88323b2014-01-29 19:03:19 -0800198 ICallServiceSelectionResponse.Stub response = createSelectionResponse();
199 try {
Ben Giladc5b22692014-02-18 20:03:22 -0800200 selector.select(mCall.toCallInfo(), mCallServiceDescriptors, response);
Ben Giladd88323b2014-01-29 19:03:19 -0800201 } catch (RemoteException e) {
202 attemptNextSelector();
203 }
Ben Gilad0bf5b912014-01-28 17:55:57 -0800204
205 } else {
Santos Cordon681663d2014-01-30 04:32:15 -0800206 mOutgoingCallsManager.handleFailedOutgoingCall(mCall);
Ben Gilad0bf5b912014-01-28 17:55:57 -0800207 }
208 }
209
210 /**
Ben Giladd88323b2014-01-29 19:03:19 -0800211 * @return A new selection-response object that's wired to run on the main (UI) thread.
212 */
213 private ICallServiceSelectionResponse.Stub createSelectionResponse() {
214 return new ICallServiceSelectionResponse.Stub() {
Ben Giladc5b22692014-02-18 20:03:22 -0800215 @Override public void setSelectedCallServiceDescriptors(
216 final List<CallServiceDescriptor> selectedCallServiceDescriptors) {
Ben Giladd88323b2014-01-29 19:03:19 -0800217
218 Runnable runnable = new Runnable() {
219 @Override public void run() {
Ben Giladc5b22692014-02-18 20:03:22 -0800220 processSelectedCallServiceDescriptors(selectedCallServiceDescriptors);
Ben Giladd88323b2014-01-29 19:03:19 -0800221 }
222 };
223
224 mHandler.post(runnable);
225 }
226 };
227 }
228
229 /**
Ben Giladc5b22692014-02-18 20:03:22 -0800230 * Persists the ordered-list of call-service descriptor as selected by the current selector and
231 * starts iterating through the corresponding call services continuing the attempt to place the
232 * call.
Ben Gilad0bf5b912014-01-28 17:55:57 -0800233 *
Ben Giladc5b22692014-02-18 20:03:22 -0800234 * @selectedCallServiceDescriptors The (ordered) list of call-service descriptor.
Ben Gilad0bf5b912014-01-28 17:55:57 -0800235 */
Ben Giladc5b22692014-02-18 20:03:22 -0800236 private void processSelectedCallServiceDescriptors(
237 List<CallServiceDescriptor> selectedCallServiceDescriptors) {
238
239 if (selectedCallServiceDescriptors == null || selectedCallServiceDescriptors.isEmpty()) {
Ben Gilad0bf5b912014-01-28 17:55:57 -0800240 attemptNextSelector();
Ben Giladc5b22692014-02-18 20:03:22 -0800241 } else if (mCallServiceDescriptorIterator == null) {
242 mCallServiceDescriptorIterator = selectedCallServiceDescriptors.iterator();
Ben Gilad0bf5b912014-01-28 17:55:57 -0800243 attemptNextCallService();
244 }
245 }
246
247 /**
Ben Giladc5b22692014-02-18 20:03:22 -0800248 * Attempts to place the call using the call service specified by the next call-service
249 * descriptor of mCallServiceDescriptorIterator. If there are no more call services to
250 * attempt, the process continues to the next call-service selector via
251 * {@link #attemptNextSelector}.
Ben Gilad0bf5b912014-01-28 17:55:57 -0800252 */
253 private void attemptNextCallService() {
254 if (mIsAborted) {
255 return;
256 }
257
Ben Giladc5b22692014-02-18 20:03:22 -0800258 if (mCallServiceDescriptorIterator.hasNext()) {
259 CallServiceDescriptor descriptor = mCallServiceDescriptorIterator.next();
260 mCallService = mCallServicesById.get(descriptor.getCallServiceId());
Santos Cordon681663d2014-01-30 04:32:15 -0800261 if (mCallService == null) {
262 attemptNextCallService();
263 } else {
Sailesh Nepalb6141ae2014-02-18 08:45:26 -0800264 BindCallback callback = new BindCallback() {
265 @Override public void onSuccess() {
266 mCallService.call(mCall.toCallInfo());
267 }
268 @Override public void onFailure() {
269 attemptNextSelector();
270 }
271 };
272 mCallService.bind(callback);
Ben Gilad0bf5b912014-01-28 17:55:57 -0800273 }
274 } else {
Ben Giladc5b22692014-02-18 20:03:22 -0800275 mCallServiceDescriptorIterator = null;
Santos Cordon681663d2014-01-30 04:32:15 -0800276 resetCallService();
Ben Gilad0bf5b912014-01-28 17:55:57 -0800277 attemptNextSelector();
278 }
279 }
280
281 /**
Santos Cordon681663d2014-01-30 04:32:15 -0800282 * Nulls out the reference to the current call service. Invoked when the call service is no longer
283 * expected to place the outgoing call.
Ben Gilad0bf5b912014-01-28 17:55:57 -0800284 */
Santos Cordon681663d2014-01-30 04:32:15 -0800285 private void resetCallService() {
286 mCallService = null;
Ben Gilad0bf5b912014-01-28 17:55:57 -0800287 }
288}