blob: e855549ac697e675bbac88fa24aff46380edc009 [file] [log] [blame]
Sailesh Nepalae925952016-01-24 18:56:58 -08001/*
2 * Copyright (C) 2016 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.server.telecom;
18
19import android.net.Uri;
20import android.telecom.Connection;
21import android.telecom.ParcelableCall;
Hall Liudd68bc32017-01-25 17:14:23 -080022import android.telecom.ParcelableRttCall;
Sailesh Nepalae925952016-01-24 18:56:58 -080023import android.telecom.TelecomManager;
24
25import java.util.ArrayList;
26import java.util.List;
27
28/**
29 * Utilities dealing with {@link ParcelableCall}.
30 */
31public class ParcelableCallUtils {
Tyler Gunn1e37be52016-07-11 08:54:23 -070032 private static final int CALL_STATE_OVERRIDE_NONE = -1;
33
Hall Liu6d4b66d2016-04-01 16:31:13 -070034 public static class Converter {
35 public ParcelableCall toParcelableCall(Call call, boolean includeVideoProvider,
36 PhoneAccountRegistrar phoneAccountRegistrar) {
37 return ParcelableCallUtils.toParcelableCall(
Hall Liudd68bc32017-01-25 17:14:23 -080038 call, includeVideoProvider, phoneAccountRegistrar, false, false);
Hall Liu6d4b66d2016-04-01 16:31:13 -070039 }
40 }
41
Sailesh Nepalae925952016-01-24 18:56:58 -080042 /**
43 * Parcels all information for a {@link Call} into a new {@link ParcelableCall} instance.
44 *
45 * @param call The {@link Call} to parcel.
46 * @param includeVideoProvider {@code true} if the video provider should be parcelled with the
47 * {@link Call}, {@code false} otherwise. Since the {@link ParcelableCall#getVideoCall()}
48 * method creates a {@link VideoCallImpl} instance on access it is important for the
49 * recipient of the {@link ParcelableCall} to know if the video provider changed.
50 * @param phoneAccountRegistrar The {@link PhoneAccountRegistrar}.
Tyler Gunn1e37be52016-07-11 08:54:23 -070051 * @param supportsExternalCalls Indicates whether the call should be parcelled for an
52 * {@link InCallService} which supports external calls or not.
53 */
54 public static ParcelableCall toParcelableCall(
55 Call call,
56 boolean includeVideoProvider,
57 PhoneAccountRegistrar phoneAccountRegistrar,
Hall Liudd68bc32017-01-25 17:14:23 -080058 boolean supportsExternalCalls,
59 boolean includeRttCall) {
Tyler Gunn1e37be52016-07-11 08:54:23 -070060 return toParcelableCall(call, includeVideoProvider, phoneAccountRegistrar,
Hall Liudd68bc32017-01-25 17:14:23 -080061 supportsExternalCalls, CALL_STATE_OVERRIDE_NONE /* overrideState */,
62 includeRttCall);
Tyler Gunn1e37be52016-07-11 08:54:23 -070063 }
64
65 /**
66 * Parcels all information for a {@link Call} into a new {@link ParcelableCall} instance.
67 *
68 * @param call The {@link Call} to parcel.
69 * @param includeVideoProvider {@code true} if the video provider should be parcelled with the
70 * {@link Call}, {@code false} otherwise. Since the {@link ParcelableCall#getVideoCall()}
71 * method creates a {@link VideoCallImpl} instance on access it is important for the
72 * recipient of the {@link ParcelableCall} to know if the video provider changed.
73 * @param phoneAccountRegistrar The {@link PhoneAccountRegistrar}.
74 * @param supportsExternalCalls Indicates whether the call should be parcelled for an
75 * {@link InCallService} which supports external calls or not.
76 * @param overrideState When not {@link #CALL_STATE_OVERRIDE_NONE}, use the provided state as an
77 * override to whatever is defined in the call.
Sailesh Nepalae925952016-01-24 18:56:58 -080078 * @return The {@link ParcelableCall} containing all call information from the {@link Call}.
79 */
80 public static ParcelableCall toParcelableCall(
81 Call call,
82 boolean includeVideoProvider,
Tyler Gunn1e37be52016-07-11 08:54:23 -070083 PhoneAccountRegistrar phoneAccountRegistrar,
84 boolean supportsExternalCalls,
Hall Liudd68bc32017-01-25 17:14:23 -080085 int overrideState,
86 boolean includeRttCall) {
Tyler Gunn1e37be52016-07-11 08:54:23 -070087 int state;
88 if (overrideState == CALL_STATE_OVERRIDE_NONE) {
89 state = getParcelableState(call, supportsExternalCalls);
90 } else {
91 state = overrideState;
92 }
Sailesh Nepalae925952016-01-24 18:56:58 -080093 int capabilities = convertConnectionToCallCapabilities(call.getConnectionCapabilities());
Tyler Gunn571d5e62016-03-15 15:55:18 -070094 int properties = convertConnectionToCallProperties(call.getConnectionProperties());
Christine Hallstromffe558c2016-11-30 16:05:13 -080095 int supportedAudioRoutes = call.getSupportedAudioRoutes();
96
Sailesh Nepalae925952016-01-24 18:56:58 -080097 if (call.isConference()) {
98 properties |= android.telecom.Call.Details.PROPERTY_CONFERENCE;
99 }
100
Tony Makd29d9372016-02-08 18:23:41 +0000101 if (call.isWorkCall()) {
Tony Makd9ec0ea2016-05-20 21:17:06 +0100102 properties |= android.telecom.Call.Details.PROPERTY_ENTERPRISE_CALL;
Sailesh Nepalae925952016-01-24 18:56:58 -0800103 }
104
105 // If this is a single-SIM device, the "default SIM" will always be the only SIM.
Hall Liu28b82f02016-07-26 17:38:56 -0700106 boolean isDefaultSmsAccount = phoneAccountRegistrar != null &&
Sailesh Nepalae925952016-01-24 18:56:58 -0800107 phoneAccountRegistrar.isUserSelectedSmsPhoneAccount(call.getTargetPhoneAccount());
108 if (call.isRespondViaSmsCapable() && isDefaultSmsAccount) {
109 capabilities |= android.telecom.Call.Details.CAPABILITY_RESPOND_VIA_TEXT;
110 }
111
112 if (call.isEmergencyCall()) {
113 capabilities = removeCapability(
114 capabilities, android.telecom.Call.Details.CAPABILITY_MUTE);
115 }
116
117 if (state == android.telecom.Call.STATE_DIALING) {
118 capabilities = removeCapability(capabilities,
119 android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL);
120 capabilities = removeCapability(capabilities,
121 android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL);
122 }
123
124 String parentCallId = null;
125 Call parentCall = call.getParentCall();
126 if (parentCall != null) {
127 parentCallId = parentCall.getId();
128 }
129
130 long connectTimeMillis = call.getConnectTimeMillis();
131 List<Call> childCalls = call.getChildCalls();
132 List<String> childCallIds = new ArrayList<>();
133 if (!childCalls.isEmpty()) {
134 long childConnectTimeMillis = Long.MAX_VALUE;
135 for (Call child : childCalls) {
136 if (child.getConnectTimeMillis() > 0) {
137 childConnectTimeMillis = Math.min(child.getConnectTimeMillis(),
138 childConnectTimeMillis);
139 }
140 childCallIds.add(child.getId());
141 }
142
143 if (childConnectTimeMillis != Long.MAX_VALUE) {
144 connectTimeMillis = childConnectTimeMillis;
145 }
146 }
147
148 Uri handle = call.getHandlePresentation() == TelecomManager.PRESENTATION_ALLOWED ?
149 call.getHandle() : null;
150 String callerDisplayName = call.getCallerDisplayNamePresentation() ==
151 TelecomManager.PRESENTATION_ALLOWED ? call.getCallerDisplayName() : null;
152
153 List<Call> conferenceableCalls = call.getConferenceableCalls();
154 List<String> conferenceableCallIds = new ArrayList<String>(conferenceableCalls.size());
155 for (Call otherCall : conferenceableCalls) {
156 conferenceableCallIds.add(otherCall.getId());
157 }
158
Hall Liudd68bc32017-01-25 17:14:23 -0800159 ParcelableRttCall rttCall = includeRttCall ? getParcelableRttCall(call) : null;
160
Sailesh Nepalae925952016-01-24 18:56:58 -0800161 return new ParcelableCall(
162 call.getId(),
163 state,
164 call.getDisconnectCause(),
165 call.getCannedSmsResponses(),
166 capabilities,
167 properties,
Christine Hallstromffe558c2016-11-30 16:05:13 -0800168 supportedAudioRoutes,
Sailesh Nepalae925952016-01-24 18:56:58 -0800169 connectTimeMillis,
170 handle,
171 call.getHandlePresentation(),
172 callerDisplayName,
173 call.getCallerDisplayNamePresentation(),
174 call.getGatewayInfo(),
175 call.getTargetPhoneAccount(),
176 includeVideoProvider,
177 includeVideoProvider ? call.getVideoProvider() : null,
Hall Liudd68bc32017-01-25 17:14:23 -0800178 includeRttCall,
179 rttCall,
Sailesh Nepalae925952016-01-24 18:56:58 -0800180 parentCallId,
181 childCallIds,
182 call.getStatusHints(),
183 call.getVideoState(),
184 conferenceableCallIds,
185 call.getIntentExtras(),
186 call.getExtras());
187 }
188
Tyler Gunn1e37be52016-07-11 08:54:23 -0700189 private static int getParcelableState(Call call, boolean supportsExternalCalls) {
Sailesh Nepalae925952016-01-24 18:56:58 -0800190 int state = CallState.NEW;
191 switch (call.getState()) {
192 case CallState.ABORTED:
193 case CallState.DISCONNECTED:
194 state = android.telecom.Call.STATE_DISCONNECTED;
195 break;
196 case CallState.ACTIVE:
197 state = android.telecom.Call.STATE_ACTIVE;
198 break;
199 case CallState.CONNECTING:
200 state = android.telecom.Call.STATE_CONNECTING;
201 break;
202 case CallState.DIALING:
203 state = android.telecom.Call.STATE_DIALING;
204 break;
Tyler Gunn1e37be52016-07-11 08:54:23 -0700205 case CallState.PULLING:
206 if (supportsExternalCalls) {
207 // The InCallService supports external calls, so it must handle
208 // STATE_PULLING_CALL.
209 state = android.telecom.Call.STATE_PULLING_CALL;
210 } else {
211 // The InCallService does NOT support external calls, so remap
212 // STATE_PULLING_CALL to STATE_DIALING. In essence, pulling a call can be seen
213 // as a form of dialing, so it is appropriate for InCallServices which do not
214 // handle external calls.
215 state = android.telecom.Call.STATE_DIALING;
216 }
217 break;
Sailesh Nepalae925952016-01-24 18:56:58 -0800218 case CallState.DISCONNECTING:
219 state = android.telecom.Call.STATE_DISCONNECTING;
220 break;
221 case CallState.NEW:
222 state = android.telecom.Call.STATE_NEW;
223 break;
224 case CallState.ON_HOLD:
225 state = android.telecom.Call.STATE_HOLDING;
226 break;
227 case CallState.RINGING:
228 state = android.telecom.Call.STATE_RINGING;
229 break;
230 case CallState.SELECT_PHONE_ACCOUNT:
231 state = android.telecom.Call.STATE_SELECT_PHONE_ACCOUNT;
232 break;
233 }
234
235 // If we are marked as 'locally disconnecting' then mark ourselves as disconnecting instead.
236 // Unless we're disconnect*ED*, in which case leave it at that.
237 if (call.isLocallyDisconnecting() &&
238 (state != android.telecom.Call.STATE_DISCONNECTED)) {
239 state = android.telecom.Call.STATE_DISCONNECTING;
240 }
241 return state;
242 }
243
244 private static final int[] CONNECTION_TO_CALL_CAPABILITY = new int[] {
245 Connection.CAPABILITY_HOLD,
246 android.telecom.Call.Details.CAPABILITY_HOLD,
247
248 Connection.CAPABILITY_SUPPORT_HOLD,
249 android.telecom.Call.Details.CAPABILITY_SUPPORT_HOLD,
250
251 Connection.CAPABILITY_MERGE_CONFERENCE,
252 android.telecom.Call.Details.CAPABILITY_MERGE_CONFERENCE,
253
254 Connection.CAPABILITY_SWAP_CONFERENCE,
255 android.telecom.Call.Details.CAPABILITY_SWAP_CONFERENCE,
256
257 Connection.CAPABILITY_RESPOND_VIA_TEXT,
258 android.telecom.Call.Details.CAPABILITY_RESPOND_VIA_TEXT,
259
260 Connection.CAPABILITY_MUTE,
261 android.telecom.Call.Details.CAPABILITY_MUTE,
262
263 Connection.CAPABILITY_MANAGE_CONFERENCE,
264 android.telecom.Call.Details.CAPABILITY_MANAGE_CONFERENCE,
265
266 Connection.CAPABILITY_SUPPORTS_VT_LOCAL_RX,
267 android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_RX,
268
269 Connection.CAPABILITY_SUPPORTS_VT_LOCAL_TX,
270 android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_TX,
271
272 Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL,
273 android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL,
274
275 Connection.CAPABILITY_SUPPORTS_VT_REMOTE_RX,
276 android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_RX,
277
278 Connection.CAPABILITY_SUPPORTS_VT_REMOTE_TX,
279 android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_TX,
280
281 Connection.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL,
282 android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL,
283
284 Connection.CAPABILITY_SEPARATE_FROM_CONFERENCE,
285 android.telecom.Call.Details.CAPABILITY_SEPARATE_FROM_CONFERENCE,
286
287 Connection.CAPABILITY_DISCONNECT_FROM_CONFERENCE,
288 android.telecom.Call.Details.CAPABILITY_DISCONNECT_FROM_CONFERENCE,
289
290 Connection.CAPABILITY_CAN_UPGRADE_TO_VIDEO,
291 android.telecom.Call.Details.CAPABILITY_CAN_UPGRADE_TO_VIDEO,
292
293 Connection.CAPABILITY_CAN_PAUSE_VIDEO,
294 android.telecom.Call.Details.CAPABILITY_CAN_PAUSE_VIDEO,
295
296 Connection.CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION,
297 android.telecom.Call.Details.CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION,
298
299 Connection.CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO,
Tyler Gunnd45e6d92016-03-10 20:15:39 -0800300 android.telecom.Call.Details.CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO,
301
302 Connection.CAPABILITY_CAN_PULL_CALL,
303 android.telecom.Call.Details.CAPABILITY_CAN_PULL_CALL
Sailesh Nepalae925952016-01-24 18:56:58 -0800304 };
305
306 private static int convertConnectionToCallCapabilities(int connectionCapabilities) {
307 int callCapabilities = 0;
308 for (int i = 0; i < CONNECTION_TO_CALL_CAPABILITY.length; i += 2) {
309 if ((CONNECTION_TO_CALL_CAPABILITY[i] & connectionCapabilities) ==
310 CONNECTION_TO_CALL_CAPABILITY[i]) {
311
312 callCapabilities |= CONNECTION_TO_CALL_CAPABILITY[i + 1];
313 }
314 }
315 return callCapabilities;
316 }
317
318 private static final int[] CONNECTION_TO_CALL_PROPERTIES = new int[] {
Tyler Gunn571d5e62016-03-15 15:55:18 -0700319 Connection.PROPERTY_HIGH_DEF_AUDIO,
Sailesh Nepalae925952016-01-24 18:56:58 -0800320 android.telecom.Call.Details.PROPERTY_HIGH_DEF_AUDIO,
321
Tyler Gunn571d5e62016-03-15 15:55:18 -0700322 Connection.PROPERTY_WIFI,
Sailesh Nepalae925952016-01-24 18:56:58 -0800323 android.telecom.Call.Details.PROPERTY_WIFI,
324
Tyler Gunn571d5e62016-03-15 15:55:18 -0700325 Connection.PROPERTY_GENERIC_CONFERENCE,
Sailesh Nepalae925952016-01-24 18:56:58 -0800326 android.telecom.Call.Details.PROPERTY_GENERIC_CONFERENCE,
327
Hall Liuddf3f9c2016-08-30 13:38:52 -0700328 Connection.PROPERTY_EMERGENCY_CALLBACK_MODE,
Tyler Gunnd45e6d92016-03-10 20:15:39 -0800329 android.telecom.Call.Details.PROPERTY_EMERGENCY_CALLBACK_MODE,
330
Tyler Gunn571d5e62016-03-15 15:55:18 -0700331 Connection.PROPERTY_IS_EXTERNAL_CALL,
Brad Ebinger84771f82016-05-18 16:57:30 -0700332 android.telecom.Call.Details.PROPERTY_IS_EXTERNAL_CALL,
333
334 Connection.PROPERTY_HAS_CDMA_VOICE_PRIVACY,
335 android.telecom.Call.Details.PROPERTY_HAS_CDMA_VOICE_PRIVACY
Sailesh Nepalae925952016-01-24 18:56:58 -0800336 };
337
Tyler Gunn571d5e62016-03-15 15:55:18 -0700338 private static int convertConnectionToCallProperties(int connectionProperties) {
Sailesh Nepalae925952016-01-24 18:56:58 -0800339 int callProperties = 0;
340 for (int i = 0; i < CONNECTION_TO_CALL_PROPERTIES.length; i += 2) {
Tyler Gunn571d5e62016-03-15 15:55:18 -0700341 if ((CONNECTION_TO_CALL_PROPERTIES[i] & connectionProperties) ==
Sailesh Nepalae925952016-01-24 18:56:58 -0800342 CONNECTION_TO_CALL_PROPERTIES[i]) {
343
344 callProperties |= CONNECTION_TO_CALL_PROPERTIES[i + 1];
345 }
346 }
347 return callProperties;
348 }
349
350 /**
351 * Removes the specified capability from the set of capabilities bits and returns the new set.
352 */
353 private static int removeCapability(int capabilities, int capability) {
354 return capabilities & ~capability;
355 }
356
Hall Liudd68bc32017-01-25 17:14:23 -0800357 private static ParcelableRttCall getParcelableRttCall(Call call) {
358 if (!call.isRttCall()) {
359 return null;
360 }
361 return new ParcelableRttCall(call.getRttMode(), call.getInCallToCsRttPipeForInCall(),
362 call.getCsToInCallRttPipeForInCall());
363 }
364
Sailesh Nepalae925952016-01-24 18:56:58 -0800365 private ParcelableCallUtils() {}
366}