• 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         int supportedAudioRoutes = call.getSupportedAudioRoutes();
92 
93         if (call.isConference()) {
94             properties |= android.telecom.Call.Details.PROPERTY_CONFERENCE;
95         }
96 
97         if (call.isWorkCall()) {
98             properties |= android.telecom.Call.Details.PROPERTY_ENTERPRISE_CALL;
99         }
100 
101         // If this is a single-SIM device, the "default SIM" will always be the only SIM.
102         boolean isDefaultSmsAccount = phoneAccountRegistrar != null &&
103                 phoneAccountRegistrar.isUserSelectedSmsPhoneAccount(call.getTargetPhoneAccount());
104         if (call.isRespondViaSmsCapable() && isDefaultSmsAccount) {
105             capabilities |= android.telecom.Call.Details.CAPABILITY_RESPOND_VIA_TEXT;
106         }
107 
108         if (call.isEmergencyCall()) {
109             capabilities = removeCapability(
110                     capabilities, android.telecom.Call.Details.CAPABILITY_MUTE);
111         }
112 
113         if (state == android.telecom.Call.STATE_DIALING) {
114             capabilities = removeCapability(capabilities,
115                     android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL);
116             capabilities = removeCapability(capabilities,
117                     android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL);
118         }
119 
120         String parentCallId = null;
121         Call parentCall = call.getParentCall();
122         if (parentCall != null) {
123             parentCallId = parentCall.getId();
124         }
125 
126         long connectTimeMillis = call.getConnectTimeMillis();
127         List<Call> childCalls = call.getChildCalls();
128         List<String> childCallIds = new ArrayList<>();
129         if (!childCalls.isEmpty()) {
130             long childConnectTimeMillis = Long.MAX_VALUE;
131             for (Call child : childCalls) {
132                 if (child.getConnectTimeMillis() > 0) {
133                     childConnectTimeMillis = Math.min(child.getConnectTimeMillis(),
134                             childConnectTimeMillis);
135                 }
136                 childCallIds.add(child.getId());
137             }
138 
139             if (childConnectTimeMillis != Long.MAX_VALUE) {
140                 connectTimeMillis = childConnectTimeMillis;
141             }
142         }
143 
144         Uri handle = call.getHandlePresentation() == TelecomManager.PRESENTATION_ALLOWED ?
145                 call.getHandle() : null;
146         String callerDisplayName = call.getCallerDisplayNamePresentation() ==
147                 TelecomManager.PRESENTATION_ALLOWED ?  call.getCallerDisplayName() : null;
148 
149         List<Call> conferenceableCalls = call.getConferenceableCalls();
150         List<String> conferenceableCallIds = new ArrayList<String>(conferenceableCalls.size());
151         for (Call otherCall : conferenceableCalls) {
152             conferenceableCallIds.add(otherCall.getId());
153         }
154 
155         return new ParcelableCall(
156                 call.getId(),
157                 state,
158                 call.getDisconnectCause(),
159                 call.getCannedSmsResponses(),
160                 capabilities,
161                 properties,
162                 supportedAudioRoutes,
163                 connectTimeMillis,
164                 handle,
165                 call.getHandlePresentation(),
166                 callerDisplayName,
167                 call.getCallerDisplayNamePresentation(),
168                 call.getGatewayInfo(),
169                 call.getTargetPhoneAccount(),
170                 includeVideoProvider,
171                 includeVideoProvider ? call.getVideoProvider() : null,
172                 parentCallId,
173                 childCallIds,
174                 call.getStatusHints(),
175                 call.getVideoState(),
176                 conferenceableCallIds,
177                 call.getIntentExtras(),
178                 call.getExtras());
179     }
180 
getParcelableState(Call call, boolean supportsExternalCalls)181     private static int getParcelableState(Call call, boolean supportsExternalCalls) {
182         int state = CallState.NEW;
183         switch (call.getState()) {
184             case CallState.ABORTED:
185             case CallState.DISCONNECTED:
186                 state = android.telecom.Call.STATE_DISCONNECTED;
187                 break;
188             case CallState.ACTIVE:
189                 state = android.telecom.Call.STATE_ACTIVE;
190                 break;
191             case CallState.CONNECTING:
192                 state = android.telecom.Call.STATE_CONNECTING;
193                 break;
194             case CallState.DIALING:
195                 state = android.telecom.Call.STATE_DIALING;
196                 break;
197             case CallState.PULLING:
198                 if (supportsExternalCalls) {
199                     // The InCallService supports external calls, so it must handle
200                     // STATE_PULLING_CALL.
201                     state = android.telecom.Call.STATE_PULLING_CALL;
202                 } else {
203                     // The InCallService does NOT support external calls, so remap
204                     // STATE_PULLING_CALL to STATE_DIALING.  In essence, pulling a call can be seen
205                     // as a form of dialing, so it is appropriate for InCallServices which do not
206                     // handle external calls.
207                     state = android.telecom.Call.STATE_DIALING;
208                 }
209                 break;
210             case CallState.DISCONNECTING:
211                 state = android.telecom.Call.STATE_DISCONNECTING;
212                 break;
213             case CallState.NEW:
214                 state = android.telecom.Call.STATE_NEW;
215                 break;
216             case CallState.ON_HOLD:
217                 state = android.telecom.Call.STATE_HOLDING;
218                 break;
219             case CallState.RINGING:
220                 state = android.telecom.Call.STATE_RINGING;
221                 break;
222             case CallState.SELECT_PHONE_ACCOUNT:
223                 state = android.telecom.Call.STATE_SELECT_PHONE_ACCOUNT;
224                 break;
225         }
226 
227         // If we are marked as 'locally disconnecting' then mark ourselves as disconnecting instead.
228         // Unless we're disconnect*ED*, in which case leave it at that.
229         if (call.isLocallyDisconnecting() &&
230                 (state != android.telecom.Call.STATE_DISCONNECTED)) {
231             state = android.telecom.Call.STATE_DISCONNECTING;
232         }
233         return state;
234     }
235 
236     private static final int[] CONNECTION_TO_CALL_CAPABILITY = new int[] {
237         Connection.CAPABILITY_HOLD,
238         android.telecom.Call.Details.CAPABILITY_HOLD,
239 
240         Connection.CAPABILITY_SUPPORT_HOLD,
241         android.telecom.Call.Details.CAPABILITY_SUPPORT_HOLD,
242 
243         Connection.CAPABILITY_MERGE_CONFERENCE,
244         android.telecom.Call.Details.CAPABILITY_MERGE_CONFERENCE,
245 
246         Connection.CAPABILITY_SWAP_CONFERENCE,
247         android.telecom.Call.Details.CAPABILITY_SWAP_CONFERENCE,
248 
249         Connection.CAPABILITY_RESPOND_VIA_TEXT,
250         android.telecom.Call.Details.CAPABILITY_RESPOND_VIA_TEXT,
251 
252         Connection.CAPABILITY_MUTE,
253         android.telecom.Call.Details.CAPABILITY_MUTE,
254 
255         Connection.CAPABILITY_MANAGE_CONFERENCE,
256         android.telecom.Call.Details.CAPABILITY_MANAGE_CONFERENCE,
257 
258         Connection.CAPABILITY_SUPPORTS_VT_LOCAL_RX,
259         android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_RX,
260 
261         Connection.CAPABILITY_SUPPORTS_VT_LOCAL_TX,
262         android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_TX,
263 
264         Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL,
265         android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL,
266 
267         Connection.CAPABILITY_SUPPORTS_VT_REMOTE_RX,
268         android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_RX,
269 
270         Connection.CAPABILITY_SUPPORTS_VT_REMOTE_TX,
271         android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_TX,
272 
273         Connection.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL,
274         android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL,
275 
276         Connection.CAPABILITY_SEPARATE_FROM_CONFERENCE,
277         android.telecom.Call.Details.CAPABILITY_SEPARATE_FROM_CONFERENCE,
278 
279         Connection.CAPABILITY_DISCONNECT_FROM_CONFERENCE,
280         android.telecom.Call.Details.CAPABILITY_DISCONNECT_FROM_CONFERENCE,
281 
282         Connection.CAPABILITY_CAN_UPGRADE_TO_VIDEO,
283         android.telecom.Call.Details.CAPABILITY_CAN_UPGRADE_TO_VIDEO,
284 
285         Connection.CAPABILITY_CAN_PAUSE_VIDEO,
286         android.telecom.Call.Details.CAPABILITY_CAN_PAUSE_VIDEO,
287 
288         Connection.CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION,
289         android.telecom.Call.Details.CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION,
290 
291         Connection.CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO,
292         android.telecom.Call.Details.CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO,
293 
294         Connection.CAPABILITY_CAN_PULL_CALL,
295         android.telecom.Call.Details.CAPABILITY_CAN_PULL_CALL
296     };
297 
convertConnectionToCallCapabilities(int connectionCapabilities)298     private static int convertConnectionToCallCapabilities(int connectionCapabilities) {
299         int callCapabilities = 0;
300         for (int i = 0; i < CONNECTION_TO_CALL_CAPABILITY.length; i += 2) {
301             if ((CONNECTION_TO_CALL_CAPABILITY[i] & connectionCapabilities) ==
302                     CONNECTION_TO_CALL_CAPABILITY[i]) {
303 
304                 callCapabilities |= CONNECTION_TO_CALL_CAPABILITY[i + 1];
305             }
306         }
307         return callCapabilities;
308     }
309 
310     private static final int[] CONNECTION_TO_CALL_PROPERTIES = new int[] {
311         Connection.PROPERTY_HIGH_DEF_AUDIO,
312         android.telecom.Call.Details.PROPERTY_HIGH_DEF_AUDIO,
313 
314         Connection.PROPERTY_WIFI,
315         android.telecom.Call.Details.PROPERTY_WIFI,
316 
317         Connection.PROPERTY_GENERIC_CONFERENCE,
318         android.telecom.Call.Details.PROPERTY_GENERIC_CONFERENCE,
319 
320         Connection.PROPERTY_EMERGENCY_CALLBACK_MODE,
321         android.telecom.Call.Details.PROPERTY_EMERGENCY_CALLBACK_MODE,
322 
323         Connection.PROPERTY_IS_EXTERNAL_CALL,
324         android.telecom.Call.Details.PROPERTY_IS_EXTERNAL_CALL,
325 
326         Connection.PROPERTY_HAS_CDMA_VOICE_PRIVACY,
327         android.telecom.Call.Details.PROPERTY_HAS_CDMA_VOICE_PRIVACY
328     };
329 
convertConnectionToCallProperties(int connectionProperties)330     private static int convertConnectionToCallProperties(int connectionProperties) {
331         int callProperties = 0;
332         for (int i = 0; i < CONNECTION_TO_CALL_PROPERTIES.length; i += 2) {
333             if ((CONNECTION_TO_CALL_PROPERTIES[i] & connectionProperties) ==
334                     CONNECTION_TO_CALL_PROPERTIES[i]) {
335 
336                 callProperties |= CONNECTION_TO_CALL_PROPERTIES[i + 1];
337             }
338         }
339         return callProperties;
340     }
341 
342     /**
343      * Removes the specified capability from the set of capabilities bits and returns the new set.
344      */
removeCapability(int capabilities, int capability)345     private static int removeCapability(int capabilities, int capability) {
346         return capabilities & ~capability;
347     }
348 
ParcelableCallUtils()349     private ParcelableCallUtils() {}
350 }
351