blob: 77598c87f4487819a9fa8102ab958b1adb1d502f [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(),
Tyler Gunn00af1c82017-03-17 11:28:26 -0700186 call.getExtras(),
187 call.getCreationTimeMillis());
Sailesh Nepalae925952016-01-24 18:56:58 -0800188 }
189
Tyler Gunn1e37be52016-07-11 08:54:23 -0700190 private static int getParcelableState(Call call, boolean supportsExternalCalls) {
Sailesh Nepalae925952016-01-24 18:56:58 -0800191 int state = CallState.NEW;
192 switch (call.getState()) {
193 case CallState.ABORTED:
194 case CallState.DISCONNECTED:
195 state = android.telecom.Call.STATE_DISCONNECTED;
196 break;
197 case CallState.ACTIVE:
198 state = android.telecom.Call.STATE_ACTIVE;
199 break;
200 case CallState.CONNECTING:
201 state = android.telecom.Call.STATE_CONNECTING;
202 break;
203 case CallState.DIALING:
204 state = android.telecom.Call.STATE_DIALING;
205 break;
Tyler Gunn1e37be52016-07-11 08:54:23 -0700206 case CallState.PULLING:
207 if (supportsExternalCalls) {
208 // The InCallService supports external calls, so it must handle
209 // STATE_PULLING_CALL.
210 state = android.telecom.Call.STATE_PULLING_CALL;
211 } else {
212 // The InCallService does NOT support external calls, so remap
213 // STATE_PULLING_CALL to STATE_DIALING. In essence, pulling a call can be seen
214 // as a form of dialing, so it is appropriate for InCallServices which do not
215 // handle external calls.
216 state = android.telecom.Call.STATE_DIALING;
217 }
218 break;
Sailesh Nepalae925952016-01-24 18:56:58 -0800219 case CallState.DISCONNECTING:
220 state = android.telecom.Call.STATE_DISCONNECTING;
221 break;
222 case CallState.NEW:
223 state = android.telecom.Call.STATE_NEW;
224 break;
225 case CallState.ON_HOLD:
226 state = android.telecom.Call.STATE_HOLDING;
227 break;
228 case CallState.RINGING:
229 state = android.telecom.Call.STATE_RINGING;
230 break;
231 case CallState.SELECT_PHONE_ACCOUNT:
232 state = android.telecom.Call.STATE_SELECT_PHONE_ACCOUNT;
233 break;
234 }
235
236 // If we are marked as 'locally disconnecting' then mark ourselves as disconnecting instead.
237 // Unless we're disconnect*ED*, in which case leave it at that.
238 if (call.isLocallyDisconnecting() &&
239 (state != android.telecom.Call.STATE_DISCONNECTED)) {
240 state = android.telecom.Call.STATE_DISCONNECTING;
241 }
242 return state;
243 }
244
245 private static final int[] CONNECTION_TO_CALL_CAPABILITY = new int[] {
246 Connection.CAPABILITY_HOLD,
247 android.telecom.Call.Details.CAPABILITY_HOLD,
248
249 Connection.CAPABILITY_SUPPORT_HOLD,
250 android.telecom.Call.Details.CAPABILITY_SUPPORT_HOLD,
251
252 Connection.CAPABILITY_MERGE_CONFERENCE,
253 android.telecom.Call.Details.CAPABILITY_MERGE_CONFERENCE,
254
255 Connection.CAPABILITY_SWAP_CONFERENCE,
256 android.telecom.Call.Details.CAPABILITY_SWAP_CONFERENCE,
257
258 Connection.CAPABILITY_RESPOND_VIA_TEXT,
259 android.telecom.Call.Details.CAPABILITY_RESPOND_VIA_TEXT,
260
261 Connection.CAPABILITY_MUTE,
262 android.telecom.Call.Details.CAPABILITY_MUTE,
263
264 Connection.CAPABILITY_MANAGE_CONFERENCE,
265 android.telecom.Call.Details.CAPABILITY_MANAGE_CONFERENCE,
266
267 Connection.CAPABILITY_SUPPORTS_VT_LOCAL_RX,
268 android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_RX,
269
270 Connection.CAPABILITY_SUPPORTS_VT_LOCAL_TX,
271 android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_TX,
272
273 Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL,
274 android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL,
275
276 Connection.CAPABILITY_SUPPORTS_VT_REMOTE_RX,
277 android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_RX,
278
279 Connection.CAPABILITY_SUPPORTS_VT_REMOTE_TX,
280 android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_TX,
281
282 Connection.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL,
283 android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL,
284
285 Connection.CAPABILITY_SEPARATE_FROM_CONFERENCE,
286 android.telecom.Call.Details.CAPABILITY_SEPARATE_FROM_CONFERENCE,
287
288 Connection.CAPABILITY_DISCONNECT_FROM_CONFERENCE,
289 android.telecom.Call.Details.CAPABILITY_DISCONNECT_FROM_CONFERENCE,
290
291 Connection.CAPABILITY_CAN_UPGRADE_TO_VIDEO,
292 android.telecom.Call.Details.CAPABILITY_CAN_UPGRADE_TO_VIDEO,
293
294 Connection.CAPABILITY_CAN_PAUSE_VIDEO,
295 android.telecom.Call.Details.CAPABILITY_CAN_PAUSE_VIDEO,
296
297 Connection.CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION,
298 android.telecom.Call.Details.CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION,
299
300 Connection.CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO,
Tyler Gunnd45e6d92016-03-10 20:15:39 -0800301 android.telecom.Call.Details.CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO,
302
303 Connection.CAPABILITY_CAN_PULL_CALL,
Pooja Jainad4ebc02017-12-28 14:23:13 +0530304 android.telecom.Call.Details.CAPABILITY_CAN_PULL_CALL,
305
306 Connection.CAPABILITY_SUPPORT_DEFLECT,
307 android.telecom.Call.Details.CAPABILITY_SUPPORT_DEFLECT
Sailesh Nepalae925952016-01-24 18:56:58 -0800308 };
309
310 private static int convertConnectionToCallCapabilities(int connectionCapabilities) {
311 int callCapabilities = 0;
312 for (int i = 0; i < CONNECTION_TO_CALL_CAPABILITY.length; i += 2) {
313 if ((CONNECTION_TO_CALL_CAPABILITY[i] & connectionCapabilities) ==
314 CONNECTION_TO_CALL_CAPABILITY[i]) {
315
316 callCapabilities |= CONNECTION_TO_CALL_CAPABILITY[i + 1];
317 }
318 }
319 return callCapabilities;
320 }
321
322 private static final int[] CONNECTION_TO_CALL_PROPERTIES = new int[] {
Tyler Gunn571d5e62016-03-15 15:55:18 -0700323 Connection.PROPERTY_HIGH_DEF_AUDIO,
Sailesh Nepalae925952016-01-24 18:56:58 -0800324 android.telecom.Call.Details.PROPERTY_HIGH_DEF_AUDIO,
325
Tyler Gunn571d5e62016-03-15 15:55:18 -0700326 Connection.PROPERTY_WIFI,
Sailesh Nepalae925952016-01-24 18:56:58 -0800327 android.telecom.Call.Details.PROPERTY_WIFI,
328
Tyler Gunn571d5e62016-03-15 15:55:18 -0700329 Connection.PROPERTY_GENERIC_CONFERENCE,
Sailesh Nepalae925952016-01-24 18:56:58 -0800330 android.telecom.Call.Details.PROPERTY_GENERIC_CONFERENCE,
331
Hall Liuddf3f9c2016-08-30 13:38:52 -0700332 Connection.PROPERTY_EMERGENCY_CALLBACK_MODE,
Tyler Gunnd45e6d92016-03-10 20:15:39 -0800333 android.telecom.Call.Details.PROPERTY_EMERGENCY_CALLBACK_MODE,
334
Tyler Gunn571d5e62016-03-15 15:55:18 -0700335 Connection.PROPERTY_IS_EXTERNAL_CALL,
Brad Ebinger84771f82016-05-18 16:57:30 -0700336 android.telecom.Call.Details.PROPERTY_IS_EXTERNAL_CALL,
337
338 Connection.PROPERTY_HAS_CDMA_VOICE_PRIVACY,
Tyler Gunn37e782b2017-02-10 09:42:03 -0800339 android.telecom.Call.Details.PROPERTY_HAS_CDMA_VOICE_PRIVACY,
340
341 Connection.PROPERTY_SELF_MANAGED,
Eric Erfanian07294862017-12-06 16:20:20 -0800342 android.telecom.Call.Details.PROPERTY_SELF_MANAGED,
343
344 Connection.PROPERTY_ASSISTED_DIALING_USED,
Hall Liuea67a762018-02-09 16:48:57 -0800345 android.telecom.Call.Details.PROPERTY_ASSISTED_DIALING_USED,
346
347 Connection.PROPERTY_IS_RTT,
348 android.telecom.Call.Details.PROPERTY_RTT
Sailesh Nepalae925952016-01-24 18:56:58 -0800349 };
350
Tyler Gunn571d5e62016-03-15 15:55:18 -0700351 private static int convertConnectionToCallProperties(int connectionProperties) {
Sailesh Nepalae925952016-01-24 18:56:58 -0800352 int callProperties = 0;
353 for (int i = 0; i < CONNECTION_TO_CALL_PROPERTIES.length; i += 2) {
Tyler Gunn571d5e62016-03-15 15:55:18 -0700354 if ((CONNECTION_TO_CALL_PROPERTIES[i] & connectionProperties) ==
Sailesh Nepalae925952016-01-24 18:56:58 -0800355 CONNECTION_TO_CALL_PROPERTIES[i]) {
356
357 callProperties |= CONNECTION_TO_CALL_PROPERTIES[i + 1];
358 }
359 }
360 return callProperties;
361 }
362
363 /**
364 * Removes the specified capability from the set of capabilities bits and returns the new set.
365 */
366 private static int removeCapability(int capabilities, int capability) {
367 return capabilities & ~capability;
368 }
369
Hall Liudd68bc32017-01-25 17:14:23 -0800370 private static ParcelableRttCall getParcelableRttCall(Call call) {
371 if (!call.isRttCall()) {
372 return null;
373 }
374 return new ParcelableRttCall(call.getRttMode(), call.getInCallToCsRttPipeForInCall(),
375 call.getCsToInCallRttPipeForInCall());
376 }
377
Sailesh Nepalae925952016-01-24 18:56:58 -0800378 private ParcelableCallUtils() {}
379}