• 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.TelecomManager;
23 
24 import java.util.ArrayList;
25 import java.util.List;
26 
27 /**
28  * Utilities dealing with {@link ParcelableCall}.
29  */
30 public class ParcelableCallUtils {
31     private static final int CALL_STATE_OVERRIDE_NONE = -1;
32 
33     public static class Converter {
toParcelableCall(Call call, boolean includeVideoProvider, PhoneAccountRegistrar phoneAccountRegistrar)34         public ParcelableCall toParcelableCall(Call call, boolean includeVideoProvider,
35                 PhoneAccountRegistrar phoneAccountRegistrar) {
36             return ParcelableCallUtils.toParcelableCall(
37                     call, includeVideoProvider, phoneAccountRegistrar, false);
38         }
39     }
40 
41     /**
42      * Parcels all information for a {@link Call} into a new {@link ParcelableCall} instance.
43      *
44      * @param call The {@link Call} to parcel.
45      * @param includeVideoProvider {@code true} if the video provider should be parcelled with the
46      *      {@link Call}, {@code false} otherwise.  Since the {@link ParcelableCall#getVideoCall()}
47      *      method creates a {@link VideoCallImpl} instance on access it is important for the
48      *      recipient of the {@link ParcelableCall} to know if the video provider changed.
49      * @param phoneAccountRegistrar The {@link PhoneAccountRegistrar}.
50      * @param supportsExternalCalls Indicates whether the call should be parcelled for an
51      *      {@link InCallService} which supports external calls or not.
52      */
toParcelableCall( Call call, boolean includeVideoProvider, PhoneAccountRegistrar phoneAccountRegistrar, boolean supportsExternalCalls)53     public static ParcelableCall toParcelableCall(
54             Call call,
55             boolean includeVideoProvider,
56             PhoneAccountRegistrar phoneAccountRegistrar,
57             boolean supportsExternalCalls) {
58         return toParcelableCall(call, includeVideoProvider, phoneAccountRegistrar,
59                 supportsExternalCalls, CALL_STATE_OVERRIDE_NONE /* overrideState */);
60     }
61 
62     /**
63      * Parcels all information for a {@link Call} into a new {@link ParcelableCall} instance.
64      *
65      * @param call The {@link Call} to parcel.
66      * @param includeVideoProvider {@code true} if the video provider should be parcelled with the
67      *      {@link Call}, {@code false} otherwise.  Since the {@link ParcelableCall#getVideoCall()}
68      *      method creates a {@link VideoCallImpl} instance on access it is important for the
69      *      recipient of the {@link ParcelableCall} to know if the video provider changed.
70      * @param phoneAccountRegistrar The {@link PhoneAccountRegistrar}.
71      * @param supportsExternalCalls Indicates whether the call should be parcelled for an
72      *      {@link InCallService} which supports external calls or not.
73      * @param overrideState When not {@link #CALL_STATE_OVERRIDE_NONE}, use the provided state as an
74      *      override to whatever is defined in the call.
75      * @return The {@link ParcelableCall} containing all call information from the {@link Call}.
76      */
toParcelableCall( Call call, boolean includeVideoProvider, PhoneAccountRegistrar phoneAccountRegistrar, boolean supportsExternalCalls, int overrideState)77     public static ParcelableCall toParcelableCall(
78             Call call,
79             boolean includeVideoProvider,
80             PhoneAccountRegistrar phoneAccountRegistrar,
81             boolean supportsExternalCalls,
82             int overrideState) {
83         int state;
84         if (overrideState == CALL_STATE_OVERRIDE_NONE) {
85             state = getParcelableState(call, supportsExternalCalls);
86         } else {
87             state = overrideState;
88         }
89         int capabilities = convertConnectionToCallCapabilities(call.getConnectionCapabilities());
90         int properties = convertConnectionToCallProperties(call.getConnectionProperties());
91         if (call.isConference()) {
92             properties |= android.telecom.Call.Details.PROPERTY_CONFERENCE;
93         }
94 
95         if (call.isWorkCall()) {
96             properties |= android.telecom.Call.Details.PROPERTY_ENTERPRISE_CALL;
97         }
98 
99         // If this is a single-SIM device, the "default SIM" will always be the only SIM.
100         boolean isDefaultSmsAccount =
101                 phoneAccountRegistrar.isUserSelectedSmsPhoneAccount(call.getTargetPhoneAccount());
102         if (call.isRespondViaSmsCapable() && isDefaultSmsAccount) {
103             capabilities |= android.telecom.Call.Details.CAPABILITY_RESPOND_VIA_TEXT;
104         }
105 
106         if (call.isEmergencyCall()) {
107             capabilities = removeCapability(
108                     capabilities, android.telecom.Call.Details.CAPABILITY_MUTE);
109         }
110 
111         if (state == android.telecom.Call.STATE_DIALING) {
112             capabilities = removeCapability(capabilities,
113                     android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL);
114             capabilities = removeCapability(capabilities,
115                     android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL);
116         }
117 
118         String parentCallId = null;
119         Call parentCall = call.getParentCall();
120         if (parentCall != null) {
121             parentCallId = parentCall.getId();
122         }
123 
124         long connectTimeMillis = call.getConnectTimeMillis();
125         List<Call> childCalls = call.getChildCalls();
126         List<String> childCallIds = new ArrayList<>();
127         if (!childCalls.isEmpty()) {
128             long childConnectTimeMillis = Long.MAX_VALUE;
129             for (Call child : childCalls) {
130                 if (child.getConnectTimeMillis() > 0) {
131                     childConnectTimeMillis = Math.min(child.getConnectTimeMillis(),
132                             childConnectTimeMillis);
133                 }
134                 childCallIds.add(child.getId());
135             }
136 
137             if (childConnectTimeMillis != Long.MAX_VALUE) {
138                 connectTimeMillis = childConnectTimeMillis;
139             }
140         }
141 
142         Uri handle = call.getHandlePresentation() == TelecomManager.PRESENTATION_ALLOWED ?
143                 call.getHandle() : null;
144         String callerDisplayName = call.getCallerDisplayNamePresentation() ==
145                 TelecomManager.PRESENTATION_ALLOWED ?  call.getCallerDisplayName() : null;
146 
147         List<Call> conferenceableCalls = call.getConferenceableCalls();
148         List<String> conferenceableCallIds = new ArrayList<String>(conferenceableCalls.size());
149         for (Call otherCall : conferenceableCalls) {
150             conferenceableCallIds.add(otherCall.getId());
151         }
152 
153         return new ParcelableCall(
154                 call.getId(),
155                 state,
156                 call.getDisconnectCause(),
157                 call.getCannedSmsResponses(),
158                 capabilities,
159                 properties,
160                 connectTimeMillis,
161                 handle,
162                 call.getHandlePresentation(),
163                 callerDisplayName,
164                 call.getCallerDisplayNamePresentation(),
165                 call.getGatewayInfo(),
166                 call.getTargetPhoneAccount(),
167                 includeVideoProvider,
168                 includeVideoProvider ? call.getVideoProvider() : null,
169                 parentCallId,
170                 childCallIds,
171                 call.getStatusHints(),
172                 call.getVideoState(),
173                 conferenceableCallIds,
174                 call.getIntentExtras(),
175                 call.getExtras());
176     }
177 
getParcelableState(Call call, boolean supportsExternalCalls)178     private static int getParcelableState(Call call, boolean supportsExternalCalls) {
179         int state = CallState.NEW;
180         switch (call.getState()) {
181             case CallState.ABORTED:
182             case CallState.DISCONNECTED:
183                 state = android.telecom.Call.STATE_DISCONNECTED;
184                 break;
185             case CallState.ACTIVE:
186                 state = android.telecom.Call.STATE_ACTIVE;
187                 break;
188             case CallState.CONNECTING:
189                 state = android.telecom.Call.STATE_CONNECTING;
190                 break;
191             case CallState.DIALING:
192                 state = android.telecom.Call.STATE_DIALING;
193                 break;
194             case CallState.PULLING:
195                 if (supportsExternalCalls) {
196                     // The InCallService supports external calls, so it must handle
197                     // STATE_PULLING_CALL.
198                     state = android.telecom.Call.STATE_PULLING_CALL;
199                 } else {
200                     // The InCallService does NOT support external calls, so remap
201                     // STATE_PULLING_CALL to STATE_DIALING.  In essence, pulling a call can be seen
202                     // as a form of dialing, so it is appropriate for InCallServices which do not
203                     // handle external calls.
204                     state = android.telecom.Call.STATE_DIALING;
205                 }
206                 break;
207             case CallState.DISCONNECTING:
208                 state = android.telecom.Call.STATE_DISCONNECTING;
209                 break;
210             case CallState.NEW:
211                 state = android.telecom.Call.STATE_NEW;
212                 break;
213             case CallState.ON_HOLD:
214                 state = android.telecom.Call.STATE_HOLDING;
215                 break;
216             case CallState.RINGING:
217                 state = android.telecom.Call.STATE_RINGING;
218                 break;
219             case CallState.SELECT_PHONE_ACCOUNT:
220                 state = android.telecom.Call.STATE_SELECT_PHONE_ACCOUNT;
221                 break;
222         }
223 
224         // If we are marked as 'locally disconnecting' then mark ourselves as disconnecting instead.
225         // Unless we're disconnect*ED*, in which case leave it at that.
226         if (call.isLocallyDisconnecting() &&
227                 (state != android.telecom.Call.STATE_DISCONNECTED)) {
228             state = android.telecom.Call.STATE_DISCONNECTING;
229         }
230         return state;
231     }
232 
233     private static final int[] CONNECTION_TO_CALL_CAPABILITY = new int[] {
234         Connection.CAPABILITY_HOLD,
235         android.telecom.Call.Details.CAPABILITY_HOLD,
236 
237         Connection.CAPABILITY_SUPPORT_HOLD,
238         android.telecom.Call.Details.CAPABILITY_SUPPORT_HOLD,
239 
240         Connection.CAPABILITY_MERGE_CONFERENCE,
241         android.telecom.Call.Details.CAPABILITY_MERGE_CONFERENCE,
242 
243         Connection.CAPABILITY_SWAP_CONFERENCE,
244         android.telecom.Call.Details.CAPABILITY_SWAP_CONFERENCE,
245 
246         Connection.CAPABILITY_RESPOND_VIA_TEXT,
247         android.telecom.Call.Details.CAPABILITY_RESPOND_VIA_TEXT,
248 
249         Connection.CAPABILITY_MUTE,
250         android.telecom.Call.Details.CAPABILITY_MUTE,
251 
252         Connection.CAPABILITY_MANAGE_CONFERENCE,
253         android.telecom.Call.Details.CAPABILITY_MANAGE_CONFERENCE,
254 
255         Connection.CAPABILITY_SUPPORTS_VT_LOCAL_RX,
256         android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_RX,
257 
258         Connection.CAPABILITY_SUPPORTS_VT_LOCAL_TX,
259         android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_TX,
260 
261         Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL,
262         android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL,
263 
264         Connection.CAPABILITY_SUPPORTS_VT_REMOTE_RX,
265         android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_RX,
266 
267         Connection.CAPABILITY_SUPPORTS_VT_REMOTE_TX,
268         android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_TX,
269 
270         Connection.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL,
271         android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL,
272 
273         Connection.CAPABILITY_SEPARATE_FROM_CONFERENCE,
274         android.telecom.Call.Details.CAPABILITY_SEPARATE_FROM_CONFERENCE,
275 
276         Connection.CAPABILITY_DISCONNECT_FROM_CONFERENCE,
277         android.telecom.Call.Details.CAPABILITY_DISCONNECT_FROM_CONFERENCE,
278 
279         Connection.CAPABILITY_CAN_UPGRADE_TO_VIDEO,
280         android.telecom.Call.Details.CAPABILITY_CAN_UPGRADE_TO_VIDEO,
281 
282         Connection.CAPABILITY_CAN_PAUSE_VIDEO,
283         android.telecom.Call.Details.CAPABILITY_CAN_PAUSE_VIDEO,
284 
285         Connection.CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION,
286         android.telecom.Call.Details.CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION,
287 
288         Connection.CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO,
289         android.telecom.Call.Details.CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO,
290 
291         Connection.CAPABILITY_CAN_PULL_CALL,
292         android.telecom.Call.Details.CAPABILITY_CAN_PULL_CALL
293     };
294 
convertConnectionToCallCapabilities(int connectionCapabilities)295     private static int convertConnectionToCallCapabilities(int connectionCapabilities) {
296         int callCapabilities = 0;
297         for (int i = 0; i < CONNECTION_TO_CALL_CAPABILITY.length; i += 2) {
298             if ((CONNECTION_TO_CALL_CAPABILITY[i] & connectionCapabilities) ==
299                     CONNECTION_TO_CALL_CAPABILITY[i]) {
300 
301                 callCapabilities |= CONNECTION_TO_CALL_CAPABILITY[i + 1];
302             }
303         }
304         return callCapabilities;
305     }
306 
307     private static final int[] CONNECTION_TO_CALL_PROPERTIES = new int[] {
308         Connection.PROPERTY_HIGH_DEF_AUDIO,
309         android.telecom.Call.Details.PROPERTY_HIGH_DEF_AUDIO,
310 
311         Connection.PROPERTY_WIFI,
312         android.telecom.Call.Details.PROPERTY_WIFI,
313 
314         Connection.PROPERTY_GENERIC_CONFERENCE,
315         android.telecom.Call.Details.PROPERTY_GENERIC_CONFERENCE,
316 
317         Connection.PROPERTY_SHOW_CALLBACK_NUMBER,
318         android.telecom.Call.Details.PROPERTY_EMERGENCY_CALLBACK_MODE,
319 
320         Connection.PROPERTY_IS_EXTERNAL_CALL,
321         android.telecom.Call.Details.PROPERTY_IS_EXTERNAL_CALL,
322 
323         Connection.PROPERTY_HAS_CDMA_VOICE_PRIVACY,
324         android.telecom.Call.Details.PROPERTY_HAS_CDMA_VOICE_PRIVACY
325     };
326 
convertConnectionToCallProperties(int connectionProperties)327     private static int convertConnectionToCallProperties(int connectionProperties) {
328         int callProperties = 0;
329         for (int i = 0; i < CONNECTION_TO_CALL_PROPERTIES.length; i += 2) {
330             if ((CONNECTION_TO_CALL_PROPERTIES[i] & connectionProperties) ==
331                     CONNECTION_TO_CALL_PROPERTIES[i]) {
332 
333                 callProperties |= CONNECTION_TO_CALL_PROPERTIES[i + 1];
334             }
335         }
336         return callProperties;
337     }
338 
339     /**
340      * Removes the specified capability from the set of capabilities bits and returns the new set.
341      */
removeCapability(int capabilities, int capability)342     private static int removeCapability(int capabilities, int capability) {
343         return capabilities & ~capability;
344     }
345 
ParcelableCallUtils()346     private ParcelableCallUtils() {}
347 }
348