• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package com.android.server.telecom;
18 
19 import android.net.Uri;
20 import android.telecom.Connection;
21 import android.telecom.ParcelableCall;
22 import android.telecom.ParcelableRttCall;
23 import android.telecom.TelecomManager;
24 
25 import java.util.ArrayList;
26 import java.util.List;
27 
28 /**
29  * Utilities dealing with {@link ParcelableCall}.
30  */
31 public class ParcelableCallUtils {
32     private static final int CALL_STATE_OVERRIDE_NONE = -1;
33 
34     public static class Converter {
toParcelableCall(Call call, boolean includeVideoProvider, PhoneAccountRegistrar phoneAccountRegistrar)35         public ParcelableCall toParcelableCall(Call call, boolean includeVideoProvider,
36                 PhoneAccountRegistrar phoneAccountRegistrar) {
37             return ParcelableCallUtils.toParcelableCall(
38                     call, includeVideoProvider, phoneAccountRegistrar, false, false);
39         }
40     }
41 
42     /**
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}.
51      * @param supportsExternalCalls Indicates whether the call should be parcelled for an
52      *      {@link InCallService} which supports external calls or not.
53      */
toParcelableCall( Call call, boolean includeVideoProvider, PhoneAccountRegistrar phoneAccountRegistrar, boolean supportsExternalCalls, boolean includeRttCall)54     public static ParcelableCall toParcelableCall(
55             Call call,
56             boolean includeVideoProvider,
57             PhoneAccountRegistrar phoneAccountRegistrar,
58             boolean supportsExternalCalls,
59             boolean includeRttCall) {
60         return toParcelableCall(call, includeVideoProvider, phoneAccountRegistrar,
61                 supportsExternalCalls, CALL_STATE_OVERRIDE_NONE /* overrideState */,
62                 includeRttCall);
63     }
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.
78      * @return The {@link ParcelableCall} containing all call information from the {@link Call}.
79      */
toParcelableCall( Call call, boolean includeVideoProvider, PhoneAccountRegistrar phoneAccountRegistrar, boolean supportsExternalCalls, int overrideState, boolean includeRttCall)80     public static ParcelableCall toParcelableCall(
81             Call call,
82             boolean includeVideoProvider,
83             PhoneAccountRegistrar phoneAccountRegistrar,
84             boolean supportsExternalCalls,
85             int overrideState,
86             boolean includeRttCall) {
87         int state;
88         if (overrideState == CALL_STATE_OVERRIDE_NONE) {
89             state = getParcelableState(call, supportsExternalCalls);
90         } else {
91             state = overrideState;
92         }
93         int capabilities = convertConnectionToCallCapabilities(call.getConnectionCapabilities());
94         int properties = convertConnectionToCallProperties(call.getConnectionProperties());
95         int supportedAudioRoutes = call.getSupportedAudioRoutes();
96 
97         if (call.isConference()) {
98             properties |= android.telecom.Call.Details.PROPERTY_CONFERENCE;
99         }
100 
101         if (call.isWorkCall()) {
102             properties |= android.telecom.Call.Details.PROPERTY_ENTERPRISE_CALL;
103         }
104 
105         // If this is a single-SIM device, the "default SIM" will always be the only SIM.
106         boolean isDefaultSmsAccount = phoneAccountRegistrar != null &&
107                 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 
159         ParcelableRttCall rttCall = includeRttCall ? getParcelableRttCall(call) : null;
160 
161         return new ParcelableCall(
162                 call.getId(),
163                 state,
164                 call.getDisconnectCause(),
165                 call.getCannedSmsResponses(),
166                 capabilities,
167                 properties,
168                 supportedAudioRoutes,
169                 connectTimeMillis,
170                 handle,
171                 call.getHandlePresentation(),
172                 callerDisplayName,
173                 call.getCallerDisplayNamePresentation(),
174                 call.getGatewayInfo(),
175                 call.getTargetPhoneAccount(),
176                 includeVideoProvider,
177                 includeVideoProvider ? call.getVideoProvider() : null,
178                 includeRttCall,
179                 rttCall,
180                 parentCallId,
181                 childCallIds,
182                 call.getStatusHints(),
183                 call.getVideoState(),
184                 conferenceableCallIds,
185                 call.getIntentExtras(),
186                 call.getExtras(),
187                 call.getCreationTimeMillis());
188     }
189 
getParcelableState(Call call, boolean supportsExternalCalls)190     private static int getParcelableState(Call call, boolean supportsExternalCalls) {
191         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;
206             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;
219             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,
301         android.telecom.Call.Details.CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO,
302 
303         Connection.CAPABILITY_CAN_PULL_CALL,
304         android.telecom.Call.Details.CAPABILITY_CAN_PULL_CALL
305     };
306 
convertConnectionToCallCapabilities(int connectionCapabilities)307     private static int convertConnectionToCallCapabilities(int connectionCapabilities) {
308         int callCapabilities = 0;
309         for (int i = 0; i < CONNECTION_TO_CALL_CAPABILITY.length; i += 2) {
310             if ((CONNECTION_TO_CALL_CAPABILITY[i] & connectionCapabilities) ==
311                     CONNECTION_TO_CALL_CAPABILITY[i]) {
312 
313                 callCapabilities |= CONNECTION_TO_CALL_CAPABILITY[i + 1];
314             }
315         }
316         return callCapabilities;
317     }
318 
319     private static final int[] CONNECTION_TO_CALL_PROPERTIES = new int[] {
320         Connection.PROPERTY_HIGH_DEF_AUDIO,
321         android.telecom.Call.Details.PROPERTY_HIGH_DEF_AUDIO,
322 
323         Connection.PROPERTY_WIFI,
324         android.telecom.Call.Details.PROPERTY_WIFI,
325 
326         Connection.PROPERTY_GENERIC_CONFERENCE,
327         android.telecom.Call.Details.PROPERTY_GENERIC_CONFERENCE,
328 
329         Connection.PROPERTY_EMERGENCY_CALLBACK_MODE,
330         android.telecom.Call.Details.PROPERTY_EMERGENCY_CALLBACK_MODE,
331 
332         Connection.PROPERTY_IS_EXTERNAL_CALL,
333         android.telecom.Call.Details.PROPERTY_IS_EXTERNAL_CALL,
334 
335         Connection.PROPERTY_HAS_CDMA_VOICE_PRIVACY,
336         android.telecom.Call.Details.PROPERTY_HAS_CDMA_VOICE_PRIVACY,
337 
338         Connection.PROPERTY_SELF_MANAGED,
339         android.telecom.Call.Details.PROPERTY_SELF_MANAGED
340     };
341 
convertConnectionToCallProperties(int connectionProperties)342     private static int convertConnectionToCallProperties(int connectionProperties) {
343         int callProperties = 0;
344         for (int i = 0; i < CONNECTION_TO_CALL_PROPERTIES.length; i += 2) {
345             if ((CONNECTION_TO_CALL_PROPERTIES[i] & connectionProperties) ==
346                     CONNECTION_TO_CALL_PROPERTIES[i]) {
347 
348                 callProperties |= CONNECTION_TO_CALL_PROPERTIES[i + 1];
349             }
350         }
351         return callProperties;
352     }
353 
354     /**
355      * Removes the specified capability from the set of capabilities bits and returns the new set.
356      */
removeCapability(int capabilities, int capability)357     private static int removeCapability(int capabilities, int capability) {
358         return capabilities & ~capability;
359     }
360 
getParcelableRttCall(Call call)361     private static ParcelableRttCall getParcelableRttCall(Call call) {
362         if (!call.isRttCall()) {
363             return null;
364         }
365         return new ParcelableRttCall(call.getRttMode(), call.getInCallToCsRttPipeForInCall(),
366                 call.getCsToInCallRttPipeForInCall());
367     }
368 
ParcelableCallUtils()369     private ParcelableCallUtils() {}
370 }
371