• 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 static android.telecom.Call.Details.DIRECTION_INCOMING;
20 import static android.telecom.Call.Details.DIRECTION_OUTGOING;
21 import static android.telecom.Call.Details.DIRECTION_UNKNOWN;
22 
23 import android.net.Uri;
24 import android.os.Bundle;
25 import android.telecom.Connection;
26 import android.telecom.DisconnectCause;
27 import android.telecom.ParcelableCall;
28 import android.telecom.ParcelableRttCall;
29 import android.telecom.TelecomManager;
30 import android.telephony.ims.ImsCallProfile;
31 import android.text.TextUtils;
32 
33 import java.util.ArrayList;
34 import java.util.Collections;
35 import java.util.Iterator;
36 import java.util.List;
37 
38 /**
39  * Utilities dealing with {@link ParcelableCall}.
40  */
41 public class ParcelableCallUtils {
42     private static final int CALL_STATE_OVERRIDE_NONE = -1;
43 
44     /**
45      * A list of extra keys which should be removed from a {@link ParcelableCall} when it is being
46      * generated for the purpose of sending to a incallservice other than the system incallservice.
47      * By convention we only pass keys namespaced with android.*, however there are some keys which
48      * should not be passed to non-system incallservice apps either.
49      */
50     private static List<String> EXTRA_KEYS_TO_SANITIZE;
51     static {
52         EXTRA_KEYS_TO_SANITIZE = new ArrayList<>();
53         EXTRA_KEYS_TO_SANITIZE.add(android.telecom.Connection.EXTRA_SIP_INVITE);
54     }
55 
56     /**
57      * A list of extra keys which should be added to {@link ParcelableCall} when it is being
58      * generated for the purpose of sending to a CallScreeningService which has access to these
59      * restricted keys.
60      */
61     private static List<String> RESTRICTED_CALL_SCREENING_EXTRA_KEYS;
62     static {
63         RESTRICTED_CALL_SCREENING_EXTRA_KEYS = new ArrayList<>();
64         RESTRICTED_CALL_SCREENING_EXTRA_KEYS.add(android.telecom.Connection.EXTRA_SIP_INVITE);
65         RESTRICTED_CALL_SCREENING_EXTRA_KEYS.add(ImsCallProfile.EXTRA_IS_BUSINESS_CALL);
66         RESTRICTED_CALL_SCREENING_EXTRA_KEYS.add(ImsCallProfile.EXTRA_ASSERTED_DISPLAY_NAME);
67     }
68 
69     public static class Converter {
toParcelableCall(Call call, boolean includeVideoProvider, PhoneAccountRegistrar phoneAccountRegistrar)70         public ParcelableCall toParcelableCall(Call call, boolean includeVideoProvider,
71                 PhoneAccountRegistrar phoneAccountRegistrar) {
72             return ParcelableCallUtils.toParcelableCall(
73                     call, includeVideoProvider, phoneAccountRegistrar, false, false, false);
74         }
75 
toParcelableCallForScreening(Call call, boolean areRestrictedExtrasIncluded)76         public ParcelableCall toParcelableCallForScreening(Call call,
77                 boolean areRestrictedExtrasIncluded) {
78             return ParcelableCallUtils.toParcelableCallForScreening(call,
79                     areRestrictedExtrasIncluded);
80         }
81     }
82 
83     /**
84      * Parcels all information for a {@link Call} into a new {@link ParcelableCall} instance.
85      *
86      * @param call The {@link Call} to parcel.
87      * @param includeVideoProvider {@code true} if the video provider should be parcelled with the
88      *      {@link Call}, {@code false} otherwise.  Since the {@link ParcelableCall#getVideoCall()}
89      *      method creates a {@link VideoCallImpl} instance on access it is important for the
90      *      recipient of the {@link ParcelableCall} to know if the video provider changed.
91      * @param phoneAccountRegistrar The {@link PhoneAccountRegistrar}.
92      * @param supportsExternalCalls Indicates whether the call should be parcelled for an
93      *      {@link InCallService} which supports external calls or not.
94      * @param includeRttCall {@code true} if the RTT call should be included, {@code false}
95      *      otherwise.
96      * @param isForSystemInCallService {@code true} if this call is being parcelled for the system incallservice,
97      *      {@code false} otherwise.  When parceling for the system incallservice, the entire call extras
98      *      is included.  When parceling for anything other than the system incallservice, some extra key
99      *      values will be stripped for privacy sake.
100      */
toParcelableCall( Call call, boolean includeVideoProvider, PhoneAccountRegistrar phoneAccountRegistrar, boolean supportsExternalCalls, boolean includeRttCall, boolean isForSystemInCallService)101     public static ParcelableCall toParcelableCall(
102             Call call,
103             boolean includeVideoProvider,
104             PhoneAccountRegistrar phoneAccountRegistrar,
105             boolean supportsExternalCalls,
106             boolean includeRttCall,
107             boolean isForSystemInCallService) {
108         return toParcelableCall(call, includeVideoProvider, phoneAccountRegistrar,
109                 supportsExternalCalls, CALL_STATE_OVERRIDE_NONE /* overrideState */,
110                 includeRttCall, isForSystemInCallService);
111     }
112 
113     /**
114      * Parcels all information for a {@link Call} into a new {@link ParcelableCall} instance.
115      *
116      * @param call The {@link Call} to parcel.
117      * @param includeVideoProvider {@code true} if the video provider should be parcelled with the
118      *      {@link Call}, {@code false} otherwise.  Since the {@link ParcelableCall#getVideoCall()}
119      *      method creates a {@link VideoCallImpl} instance on access it is important for the
120      *      recipient of the {@link ParcelableCall} to know if the video provider changed.
121      * @param phoneAccountRegistrar The {@link PhoneAccountRegistrar}.
122      * @param supportsExternalCalls Indicates whether the call should be parcelled for an
123      *      {@link InCallService} which supports external calls or not.
124      * @param overrideState When not {@link #CALL_STATE_OVERRIDE_NONE}, use the provided state as an
125      *      override to whatever is defined in the call.
126      * @param isForSystemInCallService {@code true} if this call is being parcelled for the system incallservice,
127      *      {@code false} otherwise.  When parceling for the system incallservice, the entire call extras
128      *      is included.  When parceling for anything other than the system incallservice, some extra key
129      *      values will be stripped for privacy sake.
130      * @return The {@link ParcelableCall} containing all call information from the {@link Call}.
131      */
toParcelableCall( Call call, boolean includeVideoProvider, PhoneAccountRegistrar phoneAccountRegistrar, boolean supportsExternalCalls, int overrideState, boolean includeRttCall, boolean isForSystemInCallService)132     public static ParcelableCall toParcelableCall(
133             Call call,
134             boolean includeVideoProvider,
135             PhoneAccountRegistrar phoneAccountRegistrar,
136             boolean supportsExternalCalls,
137             int overrideState,
138             boolean includeRttCall,
139             boolean isForSystemInCallService) {
140         int state;
141         if (overrideState == CALL_STATE_OVERRIDE_NONE) {
142             state = getParcelableState(call, supportsExternalCalls);
143         } else {
144             state = overrideState;
145         }
146         int capabilities = convertConnectionToCallCapabilities(call.getConnectionCapabilities());
147         int properties = convertConnectionToCallProperties(call.getConnectionProperties());
148         int supportedAudioRoutes = call.getSupportedAudioRoutes();
149 
150         if (call.isConference()) {
151             properties |= android.telecom.Call.Details.PROPERTY_CONFERENCE;
152         }
153 
154         if (call.isWorkCall()) {
155             properties |= android.telecom.Call.Details.PROPERTY_ENTERPRISE_CALL;
156         }
157 
158         if (call.getIsVoipAudioMode()) {
159             properties |= android.telecom.Call.Details.PROPERTY_VOIP_AUDIO_MODE;
160         }
161 
162         if (call.isTransactionalCall()) {
163             properties |= android.telecom.Call.Details.PROPERTY_IS_TRANSACTIONAL;
164         }
165 
166         // If this is a single-SIM device, the "default SIM" will always be the only SIM.
167         boolean isDefaultSmsAccount = phoneAccountRegistrar != null &&
168                 phoneAccountRegistrar.isUserSelectedSmsPhoneAccount(call.getTargetPhoneAccount());
169         if (call.isRespondViaSmsCapable() && isDefaultSmsAccount) {
170             capabilities |= android.telecom.Call.Details.CAPABILITY_RESPOND_VIA_TEXT;
171         }
172 
173         if (call.isEmergencyCall()) {
174             capabilities = removeCapability(
175                     capabilities, android.telecom.Call.Details.CAPABILITY_MUTE);
176         }
177 
178         if (state == android.telecom.Call.STATE_DIALING) {
179             capabilities = removeCapability(capabilities,
180                     android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL);
181             capabilities = removeCapability(capabilities,
182                     android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL);
183         }
184 
185         String parentCallId = null;
186         Call parentCall = call.getParentCall();
187         if (parentCall != null) {
188             parentCallId = parentCall.getId();
189         }
190 
191         List<Call> childCalls = call.getChildCalls();
192         List<String> childCallIds = new ArrayList<>();
193         if (!childCalls.isEmpty()) {
194             for (Call child : childCalls) {
195                 childCallIds.add(child.getId());
196             }
197         }
198 
199         Uri handle = call.getHandlePresentation() == TelecomManager.PRESENTATION_ALLOWED ?
200                 call.getHandle() : null;
201         String callerDisplayName = call.getCallerDisplayNamePresentation() ==
202                 TelecomManager.PRESENTATION_ALLOWED ?  call.getCallerDisplayName() : null;
203 
204         Uri contactPhotoUri = call.getContactPhotoUri();
205 
206         List<Call> conferenceableCalls = call.getConferenceableCalls();
207         List<String> conferenceableCallIds = new ArrayList<String>(conferenceableCalls.size());
208         for (Call otherCall : conferenceableCalls) {
209             conferenceableCallIds.add(otherCall.getId());
210         }
211 
212         ParcelableRttCall rttCall = includeRttCall ? getParcelableRttCall(call) : null;
213         int callDirection;
214         if (call.isIncoming()) {
215             callDirection = DIRECTION_INCOMING;
216         } else if (call.isUnknown()) {
217             callDirection = DIRECTION_UNKNOWN;
218         } else {
219             callDirection = DIRECTION_OUTGOING;
220         }
221 
222         String activeChildCallId = null;
223         if (call.getConferenceLevelActiveCall() != null) {
224             activeChildCallId = call.getConferenceLevelActiveCall().getId();
225         }
226 
227         Bundle extras;
228         if (isForSystemInCallService) {
229             extras = call.getExtras();
230         } else {
231             extras = sanitizeExtras(call.getExtras());
232         }
233 
234         return new ParcelableCall.ParcelableCallBuilder()
235                 .setId(call.getId())
236                 .setState(state)
237                 .setDisconnectCause(call.getDisconnectCause())
238                 .setCannedSmsResponses(call.getCannedSmsResponses())
239                 .setCapabilities(capabilities)
240                 .setProperties(properties)
241                 .setSupportedAudioRoutes(supportedAudioRoutes)
242                 .setConnectTimeMillis(call.getConnectTimeMillis())
243                 .setHandle(handle)
244                 .setHandlePresentation(call.getHandlePresentation())
245                 .setCallerDisplayName(callerDisplayName)
246                 .setCallerDisplayNamePresentation(call.getCallerDisplayNamePresentation())
247                 .setGatewayInfo(call.getGatewayInfo())
248                 .setAccountHandle(call.getTargetPhoneAccount())
249                 .setIsVideoCallProviderChanged(includeVideoProvider)
250                 .setVideoCallProvider(includeVideoProvider ? call.getVideoProvider() : null)
251                 .setIsRttCallChanged(includeRttCall)
252                 .setRttCall(rttCall)
253                 .setParentCallId(parentCallId)
254                 .setChildCallIds(childCallIds)
255                 .setStatusHints(call.getStatusHints())
256                 .setVideoState(call.getVideoState())
257                 .setConferenceableCallIds(conferenceableCallIds)
258                 .setIntentExtras(call.getIntentExtras())
259                 .setExtras(extras)
260                 .setCreationTimeMillis(call.getCreationTimeMillis())
261                 .setCallDirection(callDirection)
262                 .setCallerNumberVerificationStatus(call.getCallerNumberVerificationStatus())
263                 .setContactDisplayName(call.getName())
264                 .setActiveChildCallId(activeChildCallId)
265                 .setContactPhotoUri(contactPhotoUri)
266                 .createParcelableCall();
267     }
268 
269     /**
270      * Creates a ParcelableCall with the bare minimum properties required for a
271      * {@link android.telecom.CallScreeningService}.  We ONLY expose the following:
272      * <ul>
273      *     <li>Call Id (not exposed to public, but needed to associated calls)</li>
274      *     <li>Call directoin</li>
275      *     <li>Creation time</li>
276      *     <li>Connection time</li>
277      *     <li>Handle (phone number)</li>
278      *     <li>Handle (phone number) presentation</li>
279      *     <li>Caller number verification status (verstat)</li>
280      * </ul>
281      * All other fields are nulled or set to 0 values.
282      * Where the call screening service is part of the system incallservice, the
283      * {@link Connection#EXTRA_SIP_INVITE} header information is also sent to the call screening
284      * service (since the system incallservice has access to this anyways).
285      * @param call The telecom call to send to a call screening service.
286      * @param areRestrictedExtrasIncluded {@code true} if the set of restricted extras defined in
287      *                                    {@link #RESTRICTED_CALL_SCREENING_EXTRA_KEYS} are to
288      *                                    be included in the parceled call, {@code false} otherwise.
289      * @return Minimal {@link ParcelableCall} to send to the call screening service.
290      */
toParcelableCallForScreening(Call call, boolean areRestrictedExtrasIncluded)291     public static ParcelableCall toParcelableCallForScreening(Call call,
292             boolean areRestrictedExtrasIncluded) {
293         Uri handle = call.getHandlePresentation() == TelecomManager.PRESENTATION_ALLOWED ?
294                 call.getHandle() : null;
295         int callDirection;
296         if (call.isIncoming()) {
297             callDirection = DIRECTION_INCOMING;
298         } else if (call.isUnknown()) {
299             callDirection = DIRECTION_UNKNOWN;
300         } else {
301             callDirection = DIRECTION_OUTGOING;
302         }
303         Bundle callExtras;
304         if (areRestrictedExtrasIncluded) {
305             callExtras = sanitizeRestrictedCallExtras(call.getExtras());
306         } else {
307             callExtras = new Bundle();
308         }
309 
310         return new ParcelableCall.ParcelableCallBuilder()
311                 .setId(call.getId())
312                 .setState(getParcelableState(call, false /* supportsExternalCalls */))
313                 .setDisconnectCause(new DisconnectCause(DisconnectCause.UNKNOWN))
314                 .setCannedSmsResponses(null)
315                 .setCapabilities(0)
316                 .setProperties(0)
317                 .setSupportedAudioRoutes(0)
318                 .setConnectTimeMillis(call.getConnectTimeMillis())
319                 .setHandle(handle)
320                 .setHandlePresentation(call.getHandlePresentation())
321                 .setCallerDisplayName(null)
322                 .setCallerDisplayNamePresentation(0)
323                 .setGatewayInfo(null)
324                 .setAccountHandle(null)
325                 .setIsVideoCallProviderChanged(false)
326                 .setVideoCallProvider(null)
327                 .setIsRttCallChanged(false)
328                 .setRttCall(null)
329                 .setParentCallId(null)
330                 .setChildCallIds(null)
331                 .setStatusHints(null)
332                 .setVideoState(0)
333                 .setConferenceableCallIds(Collections.emptyList())
334                 .setIntentExtras(null)
335                 .setExtras(callExtras)
336                 .setCreationTimeMillis(call.getCreationTimeMillis())
337                 .setCallDirection(callDirection)
338                 .setCallerNumberVerificationStatus(call.getCallerNumberVerificationStatus())
339                 .setContactDisplayName(null)
340                 .setActiveChildCallId(null)
341                 .createParcelableCall();
342     }
343 
344     /**
345      * Sanitize the extras bundle passed in, removing keys which should not be sent to non-system
346      * incallservice apps.
347      * @param oldExtras Extras bundle to sanitize.
348      * @return The sanitized extras bundle.
349      */
sanitizeExtras(Bundle oldExtras)350     private static Bundle sanitizeExtras(Bundle oldExtras) {
351         if (oldExtras == null) {
352             return new Bundle();
353         }
354         Bundle extras = new Bundle(oldExtras);
355         for (String key : EXTRA_KEYS_TO_SANITIZE) {
356             extras.remove(key);
357         }
358 
359         // As a catch-all remove any that don't start with android namespace.
360         Iterator<String> toCheck = extras.keySet().iterator();
361         while (toCheck.hasNext()) {
362             String extraKey = toCheck.next();
363             if (TextUtils.isEmpty(extraKey) || !extraKey.startsWith("android.")) {
364                 toCheck.remove();
365             }
366         }
367         return extras;
368     }
369 
370     /**
371      * Sanitize the extras bundle passed in, removing keys which should not be sent to call
372      * screening services which have access to the restricted extras.
373      * @param oldExtras Extras bundle to sanitize.
374      * @return The sanitized extras bundle.
375      */
sanitizeRestrictedCallExtras(Bundle oldExtras)376     private static Bundle sanitizeRestrictedCallExtras(Bundle oldExtras) {
377         if (oldExtras == null) {
378             return new Bundle();
379         }
380         Bundle extras = new Bundle(oldExtras);
381         Iterator<String> toCheck = extras.keySet().iterator();
382         while (toCheck.hasNext()) {
383             String extraKey = toCheck.next();
384             if (TextUtils.isEmpty(extraKey)
385                     || !RESTRICTED_CALL_SCREENING_EXTRA_KEYS.contains(extraKey)) {
386                 toCheck.remove();
387             }
388         }
389         return extras;
390     }
391 
getParcelableState(Call call, boolean supportsExternalCalls)392     private static int getParcelableState(Call call, boolean supportsExternalCalls) {
393         int state = CallState.NEW;
394         switch (call.getParcelableCallState()) {
395             case CallState.ABORTED:
396             case CallState.DISCONNECTED:
397                 state = android.telecom.Call.STATE_DISCONNECTED;
398                 break;
399             case CallState.ACTIVE:
400                 state = android.telecom.Call.STATE_ACTIVE;
401                 break;
402             case CallState.CONNECTING:
403                 state = android.telecom.Call.STATE_CONNECTING;
404                 break;
405             case CallState.DIALING:
406                 state = android.telecom.Call.STATE_DIALING;
407                 break;
408             case CallState.PULLING:
409                 if (supportsExternalCalls) {
410                     // The InCallService supports external calls, so it must handle
411                     // STATE_PULLING_CALL.
412                     state = android.telecom.Call.STATE_PULLING_CALL;
413                 } else {
414                     // The InCallService does NOT support external calls, so remap
415                     // STATE_PULLING_CALL to STATE_DIALING.  In essence, pulling a call can be seen
416                     // as a form of dialing, so it is appropriate for InCallServices which do not
417                     // handle external calls.
418                     state = android.telecom.Call.STATE_DIALING;
419                 }
420                 break;
421             case CallState.DISCONNECTING:
422                 state = android.telecom.Call.STATE_DISCONNECTING;
423                 break;
424             case CallState.NEW:
425                 state = android.telecom.Call.STATE_NEW;
426                 break;
427             case CallState.ON_HOLD:
428                 state = android.telecom.Call.STATE_HOLDING;
429                 break;
430             case CallState.RINGING:
431             case CallState.ANSWERED:
432                 // TODO: does in-call UI need to see ANSWERED?
433                 state = android.telecom.Call.STATE_RINGING;
434                 break;
435             case CallState.SELECT_PHONE_ACCOUNT:
436                 state = android.telecom.Call.STATE_SELECT_PHONE_ACCOUNT;
437                 break;
438             case CallState.AUDIO_PROCESSING:
439                 state = android.telecom.Call.STATE_AUDIO_PROCESSING;
440                 break;
441             case CallState.SIMULATED_RINGING:
442                 state = android.telecom.Call.STATE_SIMULATED_RINGING;
443                 break;
444         }
445 
446         return state;
447     }
448 
449     private static final int[] CONNECTION_TO_CALL_CAPABILITY = new int[] {
450         Connection.CAPABILITY_HOLD,
451         android.telecom.Call.Details.CAPABILITY_HOLD,
452 
453         Connection.CAPABILITY_SUPPORT_HOLD,
454         android.telecom.Call.Details.CAPABILITY_SUPPORT_HOLD,
455 
456         Connection.CAPABILITY_MERGE_CONFERENCE,
457         android.telecom.Call.Details.CAPABILITY_MERGE_CONFERENCE,
458 
459         Connection.CAPABILITY_SWAP_CONFERENCE,
460         android.telecom.Call.Details.CAPABILITY_SWAP_CONFERENCE,
461 
462         Connection.CAPABILITY_RESPOND_VIA_TEXT,
463         android.telecom.Call.Details.CAPABILITY_RESPOND_VIA_TEXT,
464 
465         Connection.CAPABILITY_MUTE,
466         android.telecom.Call.Details.CAPABILITY_MUTE,
467 
468         Connection.CAPABILITY_MANAGE_CONFERENCE,
469         android.telecom.Call.Details.CAPABILITY_MANAGE_CONFERENCE,
470 
471         Connection.CAPABILITY_SUPPORTS_VT_LOCAL_RX,
472         android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_RX,
473 
474         Connection.CAPABILITY_SUPPORTS_VT_LOCAL_TX,
475         android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_TX,
476 
477         Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL,
478         android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL,
479 
480         Connection.CAPABILITY_SUPPORTS_VT_REMOTE_RX,
481         android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_RX,
482 
483         Connection.CAPABILITY_SUPPORTS_VT_REMOTE_TX,
484         android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_TX,
485 
486         Connection.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL,
487         android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL,
488 
489         Connection.CAPABILITY_SEPARATE_FROM_CONFERENCE,
490         android.telecom.Call.Details.CAPABILITY_SEPARATE_FROM_CONFERENCE,
491 
492         Connection.CAPABILITY_DISCONNECT_FROM_CONFERENCE,
493         android.telecom.Call.Details.CAPABILITY_DISCONNECT_FROM_CONFERENCE,
494 
495         Connection.CAPABILITY_CAN_UPGRADE_TO_VIDEO,
496         android.telecom.Call.Details.CAPABILITY_CAN_UPGRADE_TO_VIDEO,
497 
498         Connection.CAPABILITY_CAN_PAUSE_VIDEO,
499         android.telecom.Call.Details.CAPABILITY_CAN_PAUSE_VIDEO,
500 
501         Connection.CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION,
502         android.telecom.Call.Details.CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION,
503 
504         Connection.CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO,
505         android.telecom.Call.Details.CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO,
506 
507         Connection.CAPABILITY_CAN_PULL_CALL,
508         android.telecom.Call.Details.CAPABILITY_CAN_PULL_CALL,
509 
510         Connection.CAPABILITY_SUPPORT_DEFLECT,
511         android.telecom.Call.Details.CAPABILITY_SUPPORT_DEFLECT,
512 
513         Connection.CAPABILITY_ADD_PARTICIPANT,
514         android.telecom.Call.Details.CAPABILITY_ADD_PARTICIPANT,
515 
516         Connection.CAPABILITY_TRANSFER,
517         android.telecom.Call.Details.CAPABILITY_TRANSFER,
518 
519         Connection.CAPABILITY_TRANSFER_CONSULTATIVE,
520         android.telecom.Call.Details.CAPABILITY_TRANSFER_CONSULTATIVE,
521 
522         Connection.CAPABILITY_REMOTE_PARTY_SUPPORTS_RTT,
523         android.telecom.Call.Details.CAPABILITY_REMOTE_PARTY_SUPPORTS_RTT
524 
525     };
526 
convertConnectionToCallCapabilities(int connectionCapabilities)527     private static int convertConnectionToCallCapabilities(int connectionCapabilities) {
528         int callCapabilities = 0;
529         for (int i = 0; i < CONNECTION_TO_CALL_CAPABILITY.length; i += 2) {
530             if ((CONNECTION_TO_CALL_CAPABILITY[i] & connectionCapabilities) ==
531                     CONNECTION_TO_CALL_CAPABILITY[i]) {
532 
533                 callCapabilities |= CONNECTION_TO_CALL_CAPABILITY[i + 1];
534             }
535         }
536         return callCapabilities;
537     }
538 
539     private static final int[] CONNECTION_TO_CALL_PROPERTIES = new int[] {
540         Connection.PROPERTY_HIGH_DEF_AUDIO,
541         android.telecom.Call.Details.PROPERTY_HIGH_DEF_AUDIO,
542 
543         Connection.PROPERTY_WIFI,
544         android.telecom.Call.Details.PROPERTY_WIFI,
545 
546         Connection.PROPERTY_GENERIC_CONFERENCE,
547         android.telecom.Call.Details.PROPERTY_GENERIC_CONFERENCE,
548 
549         Connection.PROPERTY_EMERGENCY_CALLBACK_MODE,
550         android.telecom.Call.Details.PROPERTY_EMERGENCY_CALLBACK_MODE,
551 
552         Connection.PROPERTY_IS_EXTERNAL_CALL,
553         android.telecom.Call.Details.PROPERTY_IS_EXTERNAL_CALL,
554 
555         Connection.PROPERTY_HAS_CDMA_VOICE_PRIVACY,
556         android.telecom.Call.Details.PROPERTY_HAS_CDMA_VOICE_PRIVACY,
557 
558         Connection.PROPERTY_SELF_MANAGED,
559         android.telecom.Call.Details.PROPERTY_SELF_MANAGED,
560 
561         Connection.PROPERTY_ASSISTED_DIALING,
562         android.telecom.Call.Details.PROPERTY_ASSISTED_DIALING,
563 
564         Connection.PROPERTY_IS_RTT,
565         android.telecom.Call.Details.PROPERTY_RTT,
566 
567         Connection.PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL,
568         android.telecom.Call.Details.PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL,
569 
570         Connection.PROPERTY_IS_ADHOC_CONFERENCE,
571         android.telecom.Call.Details.PROPERTY_IS_ADHOC_CONFERENCE,
572 
573         Connection.PROPERTY_CROSS_SIM,
574         android.telecom.Call.Details.PROPERTY_CROSS_SIM
575     };
576 
convertConnectionToCallProperties(int connectionProperties)577     private static int convertConnectionToCallProperties(int connectionProperties) {
578         int callProperties = 0;
579         for (int i = 0; i < CONNECTION_TO_CALL_PROPERTIES.length; i += 2) {
580             if ((CONNECTION_TO_CALL_PROPERTIES[i] & connectionProperties) ==
581                     CONNECTION_TO_CALL_PROPERTIES[i]) {
582 
583                 callProperties |= CONNECTION_TO_CALL_PROPERTIES[i + 1];
584             }
585         }
586         return callProperties;
587     }
588 
589     /**
590      * Removes the specified capability from the set of capabilities bits and returns the new set.
591      */
removeCapability(int capabilities, int capability)592     private static int removeCapability(int capabilities, int capability) {
593         return capabilities & ~capability;
594     }
595 
getParcelableRttCall(Call call)596     private static ParcelableRttCall getParcelableRttCall(Call call) {
597         if (!call.isRttCall()) {
598             return null;
599         }
600         return new ParcelableRttCall(call.getRttMode(), call.getInCallToCsRttPipeForInCall(),
601                 call.getCsToInCallRttPipeForInCall());
602     }
603 
ParcelableCallUtils()604     private ParcelableCallUtils() {}
605 }
606