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