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