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