• 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                 .setAssociatedUser(call.getAssociatedUser())
267                 .createParcelableCall();
268     }
269 
270     /**
271      * Creates a ParcelableCall with the bare minimum properties required for a
272      * {@link android.telecom.CallScreeningService}.  We ONLY expose the following:
273      * <ul>
274      *     <li>Call Id (not exposed to public, but needed to associated calls)</li>
275      *     <li>Call directoin</li>
276      *     <li>Creation time</li>
277      *     <li>Connection time</li>
278      *     <li>Handle (phone number)</li>
279      *     <li>Handle (phone number) presentation</li>
280      *     <li>Caller number verification status (verstat)</li>
281      * </ul>
282      * All other fields are nulled or set to 0 values.
283      * Where the call screening service is part of the system incallservice, the
284      * {@link Connection#EXTRA_SIP_INVITE} header information is also sent to the call screening
285      * service (since the system incallservice has access to this anyways).
286      * @param call The telecom call to send to a call screening service.
287      * @param areRestrictedExtrasIncluded {@code true} if the set of restricted extras defined in
288      *                                    {@link #RESTRICTED_CALL_SCREENING_EXTRA_KEYS} are to
289      *                                    be included in the parceled call, {@code false} otherwise.
290      * @return Minimal {@link ParcelableCall} to send to the call screening service.
291      */
toParcelableCallForScreening(Call call, boolean areRestrictedExtrasIncluded)292     public static ParcelableCall toParcelableCallForScreening(Call call,
293             boolean areRestrictedExtrasIncluded) {
294         Uri handle = call.getHandlePresentation() == TelecomManager.PRESENTATION_ALLOWED ?
295                 call.getHandle() : null;
296         int callDirection;
297         if (call.isIncoming()) {
298             callDirection = DIRECTION_INCOMING;
299         } else if (call.isUnknown()) {
300             callDirection = DIRECTION_UNKNOWN;
301         } else {
302             callDirection = DIRECTION_OUTGOING;
303         }
304         Bundle callExtras;
305         if (areRestrictedExtrasIncluded) {
306             callExtras = sanitizeRestrictedCallExtras(call.getExtras());
307         } else {
308             callExtras = new Bundle();
309         }
310 
311         return new ParcelableCall.ParcelableCallBuilder()
312                 .setId(call.getId())
313                 .setState(getParcelableState(call, false /* supportsExternalCalls */))
314                 .setDisconnectCause(new DisconnectCause(DisconnectCause.UNKNOWN))
315                 .setCannedSmsResponses(null)
316                 .setCapabilities(0)
317                 .setProperties(0)
318                 .setSupportedAudioRoutes(0)
319                 .setConnectTimeMillis(call.getConnectTimeMillis())
320                 .setHandle(handle)
321                 .setHandlePresentation(call.getHandlePresentation())
322                 .setCallerDisplayName(null)
323                 .setCallerDisplayNamePresentation(0)
324                 .setGatewayInfo(null)
325                 .setAccountHandle(null)
326                 .setIsVideoCallProviderChanged(false)
327                 .setVideoCallProvider(null)
328                 .setIsRttCallChanged(false)
329                 .setRttCall(null)
330                 .setParentCallId(null)
331                 .setChildCallIds(null)
332                 .setStatusHints(null)
333                 .setVideoState(0)
334                 .setConferenceableCallIds(Collections.emptyList())
335                 .setIntentExtras(null)
336                 .setExtras(callExtras)
337                 .setCreationTimeMillis(call.getCreationTimeMillis())
338                 .setCallDirection(callDirection)
339                 .setCallerNumberVerificationStatus(call.getCallerNumberVerificationStatus())
340                 .setContactDisplayName(null)
341                 .setActiveChildCallId(null)
342                 .createParcelableCall();
343     }
344 
345     /**
346      * Sanitize the extras bundle passed in, removing keys which should not be sent to non-system
347      * incallservice apps.
348      * @param oldExtras Extras bundle to sanitize.
349      * @return The sanitized extras bundle.
350      */
sanitizeExtras(Bundle oldExtras)351     private static Bundle sanitizeExtras(Bundle oldExtras) {
352         if (oldExtras == null) {
353             return new Bundle();
354         }
355         Bundle extras = new Bundle(oldExtras);
356         for (String key : EXTRA_KEYS_TO_SANITIZE) {
357             extras.remove(key);
358         }
359 
360         // As a catch-all remove any that don't start with android namespace.
361         Iterator<String> toCheck = extras.keySet().iterator();
362         while (toCheck.hasNext()) {
363             String extraKey = toCheck.next();
364             if (TextUtils.isEmpty(extraKey) || !extraKey.startsWith("android.")) {
365                 toCheck.remove();
366             }
367         }
368         return extras;
369     }
370 
371     /**
372      * Sanitize the extras bundle passed in, removing keys which should not be sent to call
373      * screening services which have access to the restricted extras.
374      * @param oldExtras Extras bundle to sanitize.
375      * @return The sanitized extras bundle.
376      */
sanitizeRestrictedCallExtras(Bundle oldExtras)377     private static Bundle sanitizeRestrictedCallExtras(Bundle oldExtras) {
378         if (oldExtras == null) {
379             return new Bundle();
380         }
381         Bundle extras = new Bundle(oldExtras);
382         Iterator<String> toCheck = extras.keySet().iterator();
383         while (toCheck.hasNext()) {
384             String extraKey = toCheck.next();
385             if (TextUtils.isEmpty(extraKey)
386                     || !RESTRICTED_CALL_SCREENING_EXTRA_KEYS.contains(extraKey)) {
387                 toCheck.remove();
388             }
389         }
390         return extras;
391     }
392 
getParcelableState(Call call, boolean supportsExternalCalls)393     private static int getParcelableState(Call call, boolean supportsExternalCalls) {
394         int state = CallState.NEW;
395         switch (call.getParcelableCallState()) {
396             case CallState.ABORTED:
397             case CallState.DISCONNECTED:
398                 state = android.telecom.Call.STATE_DISCONNECTED;
399                 break;
400             case CallState.ACTIVE:
401                 state = android.telecom.Call.STATE_ACTIVE;
402                 break;
403             case CallState.CONNECTING:
404                 state = android.telecom.Call.STATE_CONNECTING;
405                 break;
406             case CallState.DIALING:
407                 state = android.telecom.Call.STATE_DIALING;
408                 break;
409             case CallState.PULLING:
410                 if (supportsExternalCalls) {
411                     // The InCallService supports external calls, so it must handle
412                     // STATE_PULLING_CALL.
413                     state = android.telecom.Call.STATE_PULLING_CALL;
414                 } else {
415                     // The InCallService does NOT support external calls, so remap
416                     // STATE_PULLING_CALL to STATE_DIALING.  In essence, pulling a call can be seen
417                     // as a form of dialing, so it is appropriate for InCallServices which do not
418                     // handle external calls.
419                     state = android.telecom.Call.STATE_DIALING;
420                 }
421                 break;
422             case CallState.DISCONNECTING:
423                 state = android.telecom.Call.STATE_DISCONNECTING;
424                 break;
425             case CallState.NEW:
426                 state = android.telecom.Call.STATE_NEW;
427                 break;
428             case CallState.ON_HOLD:
429                 state = android.telecom.Call.STATE_HOLDING;
430                 break;
431             case CallState.RINGING:
432             case CallState.ANSWERED:
433                 // TODO: does in-call UI need to see ANSWERED?
434                 state = android.telecom.Call.STATE_RINGING;
435                 break;
436             case CallState.SELECT_PHONE_ACCOUNT:
437                 state = android.telecom.Call.STATE_SELECT_PHONE_ACCOUNT;
438                 break;
439             case CallState.AUDIO_PROCESSING:
440                 state = android.telecom.Call.STATE_AUDIO_PROCESSING;
441                 break;
442             case CallState.SIMULATED_RINGING:
443                 state = android.telecom.Call.STATE_SIMULATED_RINGING;
444                 break;
445         }
446 
447         return state;
448     }
449 
450     private static final int[] CONNECTION_TO_CALL_CAPABILITY = new int[] {
451         Connection.CAPABILITY_HOLD,
452         android.telecom.Call.Details.CAPABILITY_HOLD,
453 
454         Connection.CAPABILITY_SUPPORT_HOLD,
455         android.telecom.Call.Details.CAPABILITY_SUPPORT_HOLD,
456 
457         Connection.CAPABILITY_MERGE_CONFERENCE,
458         android.telecom.Call.Details.CAPABILITY_MERGE_CONFERENCE,
459 
460         Connection.CAPABILITY_SWAP_CONFERENCE,
461         android.telecom.Call.Details.CAPABILITY_SWAP_CONFERENCE,
462 
463         Connection.CAPABILITY_RESPOND_VIA_TEXT,
464         android.telecom.Call.Details.CAPABILITY_RESPOND_VIA_TEXT,
465 
466         Connection.CAPABILITY_MUTE,
467         android.telecom.Call.Details.CAPABILITY_MUTE,
468 
469         Connection.CAPABILITY_MANAGE_CONFERENCE,
470         android.telecom.Call.Details.CAPABILITY_MANAGE_CONFERENCE,
471 
472         Connection.CAPABILITY_SUPPORTS_VT_LOCAL_RX,
473         android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_RX,
474 
475         Connection.CAPABILITY_SUPPORTS_VT_LOCAL_TX,
476         android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_TX,
477 
478         Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL,
479         android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL,
480 
481         Connection.CAPABILITY_SUPPORTS_VT_REMOTE_RX,
482         android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_RX,
483 
484         Connection.CAPABILITY_SUPPORTS_VT_REMOTE_TX,
485         android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_TX,
486 
487         Connection.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL,
488         android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL,
489 
490         Connection.CAPABILITY_SEPARATE_FROM_CONFERENCE,
491         android.telecom.Call.Details.CAPABILITY_SEPARATE_FROM_CONFERENCE,
492 
493         Connection.CAPABILITY_DISCONNECT_FROM_CONFERENCE,
494         android.telecom.Call.Details.CAPABILITY_DISCONNECT_FROM_CONFERENCE,
495 
496         Connection.CAPABILITY_CAN_UPGRADE_TO_VIDEO,
497         android.telecom.Call.Details.CAPABILITY_CAN_UPGRADE_TO_VIDEO,
498 
499         Connection.CAPABILITY_CAN_PAUSE_VIDEO,
500         android.telecom.Call.Details.CAPABILITY_CAN_PAUSE_VIDEO,
501 
502         Connection.CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION,
503         android.telecom.Call.Details.CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION,
504 
505         Connection.CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO,
506         android.telecom.Call.Details.CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO,
507 
508         Connection.CAPABILITY_CAN_PULL_CALL,
509         android.telecom.Call.Details.CAPABILITY_CAN_PULL_CALL,
510 
511         Connection.CAPABILITY_SUPPORT_DEFLECT,
512         android.telecom.Call.Details.CAPABILITY_SUPPORT_DEFLECT,
513 
514         Connection.CAPABILITY_ADD_PARTICIPANT,
515         android.telecom.Call.Details.CAPABILITY_ADD_PARTICIPANT,
516 
517         Connection.CAPABILITY_TRANSFER,
518         android.telecom.Call.Details.CAPABILITY_TRANSFER,
519 
520         Connection.CAPABILITY_TRANSFER_CONSULTATIVE,
521         android.telecom.Call.Details.CAPABILITY_TRANSFER_CONSULTATIVE,
522 
523         Connection.CAPABILITY_REMOTE_PARTY_SUPPORTS_RTT,
524         android.telecom.Call.Details.CAPABILITY_REMOTE_PARTY_SUPPORTS_RTT
525 
526     };
527 
convertConnectionToCallCapabilities(int connectionCapabilities)528     private static int convertConnectionToCallCapabilities(int connectionCapabilities) {
529         int callCapabilities = 0;
530         for (int i = 0; i < CONNECTION_TO_CALL_CAPABILITY.length; i += 2) {
531             if ((CONNECTION_TO_CALL_CAPABILITY[i] & connectionCapabilities) ==
532                     CONNECTION_TO_CALL_CAPABILITY[i]) {
533 
534                 callCapabilities |= CONNECTION_TO_CALL_CAPABILITY[i + 1];
535             }
536         }
537         return callCapabilities;
538     }
539 
540     private static final int[] CONNECTION_TO_CALL_PROPERTIES = new int[] {
541         Connection.PROPERTY_HIGH_DEF_AUDIO,
542         android.telecom.Call.Details.PROPERTY_HIGH_DEF_AUDIO,
543 
544         Connection.PROPERTY_WIFI,
545         android.telecom.Call.Details.PROPERTY_WIFI,
546 
547         Connection.PROPERTY_GENERIC_CONFERENCE,
548         android.telecom.Call.Details.PROPERTY_GENERIC_CONFERENCE,
549 
550         Connection.PROPERTY_EMERGENCY_CALLBACK_MODE,
551         android.telecom.Call.Details.PROPERTY_EMERGENCY_CALLBACK_MODE,
552 
553         Connection.PROPERTY_IS_EXTERNAL_CALL,
554         android.telecom.Call.Details.PROPERTY_IS_EXTERNAL_CALL,
555 
556         Connection.PROPERTY_HAS_CDMA_VOICE_PRIVACY,
557         android.telecom.Call.Details.PROPERTY_HAS_CDMA_VOICE_PRIVACY,
558 
559         Connection.PROPERTY_SELF_MANAGED,
560         android.telecom.Call.Details.PROPERTY_SELF_MANAGED,
561 
562         Connection.PROPERTY_ASSISTED_DIALING,
563         android.telecom.Call.Details.PROPERTY_ASSISTED_DIALING,
564 
565         Connection.PROPERTY_IS_RTT,
566         android.telecom.Call.Details.PROPERTY_RTT,
567 
568         Connection.PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL,
569         android.telecom.Call.Details.PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL,
570 
571         Connection.PROPERTY_IS_ADHOC_CONFERENCE,
572         android.telecom.Call.Details.PROPERTY_IS_ADHOC_CONFERENCE,
573 
574         Connection.PROPERTY_CROSS_SIM,
575         android.telecom.Call.Details.PROPERTY_CROSS_SIM
576     };
577 
convertConnectionToCallProperties(int connectionProperties)578     private static int convertConnectionToCallProperties(int connectionProperties) {
579         int callProperties = 0;
580         for (int i = 0; i < CONNECTION_TO_CALL_PROPERTIES.length; i += 2) {
581             if ((CONNECTION_TO_CALL_PROPERTIES[i] & connectionProperties) ==
582                     CONNECTION_TO_CALL_PROPERTIES[i]) {
583 
584                 callProperties |= CONNECTION_TO_CALL_PROPERTIES[i + 1];
585             }
586         }
587         return callProperties;
588     }
589 
590     /**
591      * Removes the specified capability from the set of capabilities bits and returns the new set.
592      */
removeCapability(int capabilities, int capability)593     private static int removeCapability(int capabilities, int capability) {
594         return capabilities & ~capability;
595     }
596 
getParcelableRttCall(Call call)597     private static ParcelableRttCall getParcelableRttCall(Call call) {
598         if (!call.isRttCall()) {
599             return null;
600         }
601         return new ParcelableRttCall(call.getRttMode(), call.getInCallToCsRttPipeForInCall(),
602                 call.getCsToInCallRttPipeForInCall());
603     }
604 
ParcelableCallUtils()605     private ParcelableCallUtils() {}
606 }
607