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