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 incallservice other than the system incallservice. 46 * By convention we only pass keys namespaced with android.*, however there are some keys which 47 * should not be passed to non-system incallservice 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 isForSystemInCallService {@code true} if this call is being parcelled for the system incallservice, 94 * {@code false} otherwise. When parceling for the system incallservice, the entire call extras 95 * is included. When parceling for anything other than the system incallservice, some extra key 96 * values will be stripped for privacy sake. 97 */ toParcelableCall( Call call, boolean includeVideoProvider, PhoneAccountRegistrar phoneAccountRegistrar, boolean supportsExternalCalls, boolean includeRttCall, boolean isForSystemInCallService)98 public static ParcelableCall toParcelableCall( 99 Call call, 100 boolean includeVideoProvider, 101 PhoneAccountRegistrar phoneAccountRegistrar, 102 boolean supportsExternalCalls, 103 boolean includeRttCall, 104 boolean isForSystemInCallService) { 105 return toParcelableCall(call, includeVideoProvider, phoneAccountRegistrar, 106 supportsExternalCalls, CALL_STATE_OVERRIDE_NONE /* overrideState */, 107 includeRttCall, isForSystemInCallService); 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 isForSystemInCallService {@code true} if this call is being parcelled for the system incallservice, 124 * {@code false} otherwise. When parceling for the system incallservice, the entire call extras 125 * is included. When parceling for anything other than the system incallservice, 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 isForSystemInCallService)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 isForSystemInCallService) { 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 List<Call> childCalls = call.getChildCalls(); 185 List<String> childCallIds = new ArrayList<>(); 186 if (!childCalls.isEmpty()) { 187 for (Call child : childCalls) { 188 childCallIds.add(child.getId()); 189 } 190 } 191 192 Uri handle = call.getHandlePresentation() == TelecomManager.PRESENTATION_ALLOWED ? 193 call.getHandle() : null; 194 String callerDisplayName = call.getCallerDisplayNamePresentation() == 195 TelecomManager.PRESENTATION_ALLOWED ? call.getCallerDisplayName() : null; 196 197 List<Call> conferenceableCalls = call.getConferenceableCalls(); 198 List<String> conferenceableCallIds = new ArrayList<String>(conferenceableCalls.size()); 199 for (Call otherCall : conferenceableCalls) { 200 conferenceableCallIds.add(otherCall.getId()); 201 } 202 203 ParcelableRttCall rttCall = includeRttCall ? getParcelableRttCall(call) : null; 204 int callDirection; 205 if (call.isIncoming()) { 206 callDirection = DIRECTION_INCOMING; 207 } else if (call.isUnknown()) { 208 callDirection = DIRECTION_UNKNOWN; 209 } else { 210 callDirection = DIRECTION_OUTGOING; 211 } 212 213 String activeChildCallId = null; 214 if (call.getConferenceLevelActiveCall() != null) { 215 activeChildCallId = call.getConferenceLevelActiveCall().getId(); 216 } 217 218 Bundle extras; 219 if (isForSystemInCallService) { 220 extras = call.getExtras(); 221 } else { 222 extras = sanitizeExtras(call.getExtras()); 223 } 224 225 return new ParcelableCall.ParcelableCallBuilder() 226 .setId(call.getId()) 227 .setState(state) 228 .setDisconnectCause(call.getDisconnectCause()) 229 .setCannedSmsResponses(call.getCannedSmsResponses()) 230 .setCapabilities(capabilities) 231 .setProperties(properties) 232 .setSupportedAudioRoutes(supportedAudioRoutes) 233 .setConnectTimeMillis(call.getConnectTimeMillis()) 234 .setHandle(handle) 235 .setHandlePresentation(call.getHandlePresentation()) 236 .setCallerDisplayName(callerDisplayName) 237 .setCallerDisplayNamePresentation(call.getCallerDisplayNamePresentation()) 238 .setGatewayInfo(call.getGatewayInfo()) 239 .setAccountHandle(call.getTargetPhoneAccount()) 240 .setIsVideoCallProviderChanged(includeVideoProvider) 241 .setVideoCallProvider(includeVideoProvider ? call.getVideoProvider() : null) 242 .setIsRttCallChanged(includeRttCall) 243 .setRttCall(rttCall) 244 .setParentCallId(parentCallId) 245 .setChildCallIds(childCallIds) 246 .setStatusHints(call.getStatusHints()) 247 .setVideoState(call.getVideoState()) 248 .setConferenceableCallIds(conferenceableCallIds) 249 .setIntentExtras(call.getIntentExtras()) 250 .setExtras(extras) 251 .setCreationTimeMillis(call.getCreationTimeMillis()) 252 .setCallDirection(callDirection) 253 .setCallerNumberVerificationStatus(call.getCallerNumberVerificationStatus()) 254 .setContactDisplayName(call.getName()) 255 .setActiveChildCallId(activeChildCallId) 256 .createParcelableCall(); 257 } 258 259 /** 260 * Creates a ParcelableCall with the bare minimum properties required for a 261 * {@link android.telecom.CallScreeningService}. We ONLY expose the following: 262 * <ul> 263 * <li>Call Id (not exposed to public, but needed to associated calls)</li> 264 * <li>Call directoin</li> 265 * <li>Creation time</li> 266 * <li>Connection time</li> 267 * <li>Handle (phone number)</li> 268 * <li>Handle (phone number) presentation</li> 269 * <li>Caller number verification status (verstat)</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 incallservice, the 273 * {@link Connection#EXTRA_SIP_INVITE} header information is also sent to the call screening 274 * service (since the system incallservice 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.ParcelableCallBuilder() 301 .setId(call.getId()) 302 .setState(getParcelableState(call, false /* supportsExternalCalls */)) 303 .setDisconnectCause(new DisconnectCause(DisconnectCause.UNKNOWN)) 304 .setCannedSmsResponses(null) 305 .setCapabilities(0) 306 .setProperties(0) 307 .setSupportedAudioRoutes(0) 308 .setConnectTimeMillis(call.getConnectTimeMillis()) 309 .setHandle(handle) 310 .setHandlePresentation(call.getHandlePresentation()) 311 .setCallerDisplayName(null) 312 .setCallerDisplayNamePresentation(0) 313 .setGatewayInfo(null) 314 .setAccountHandle(null) 315 .setIsVideoCallProviderChanged(false) 316 .setVideoCallProvider(null) 317 .setIsRttCallChanged(false) 318 .setRttCall(null) 319 .setParentCallId(null) 320 .setChildCallIds(null) 321 .setStatusHints(null) 322 .setVideoState(0) 323 .setConferenceableCallIds(Collections.emptyList()) 324 .setIntentExtras(null) 325 .setExtras(callExtras) 326 .setCreationTimeMillis(call.getCreationTimeMillis()) 327 .setCallDirection(callDirection) 328 .setCallerNumberVerificationStatus(call.getCallerNumberVerificationStatus()) 329 .setContactDisplayName(null) 330 .setActiveChildCallId(null) 331 .createParcelableCall(); 332 } 333 334 /** 335 * Sanitize the extras bundle passed in, removing keys which should not be sent to non-system 336 * incallservice apps. 337 * @param oldExtras Extras bundle to sanitize. 338 * @return The sanitized extras bundle. 339 */ sanitizeExtras(Bundle oldExtras)340 private static Bundle sanitizeExtras(Bundle oldExtras) { 341 if (oldExtras == null) { 342 return new Bundle(); 343 } 344 Bundle extras = new Bundle(oldExtras); 345 for (String key : EXTRA_KEYS_TO_SANITIZE) { 346 extras.remove(key); 347 } 348 349 // As a catch-all remove any that don't start with android namespace. 350 Iterator<String> toCheck = extras.keySet().iterator(); 351 while (toCheck.hasNext()) { 352 String extraKey = toCheck.next(); 353 if (TextUtils.isEmpty(extraKey) || !extraKey.startsWith("android.")) { 354 toCheck.remove(); 355 } 356 } 357 return extras; 358 } 359 360 /** 361 * Sanitize the extras bundle passed in, removing keys which should not be sent to call 362 * screening services which have access to the restricted extras. 363 * @param oldExtras Extras bundle to sanitize. 364 * @return The sanitized extras bundle. 365 */ sanitizeRestrictedCallExtras(Bundle oldExtras)366 private static Bundle sanitizeRestrictedCallExtras(Bundle oldExtras) { 367 if (oldExtras == null) { 368 return new Bundle(); 369 } 370 Bundle extras = new Bundle(oldExtras); 371 Iterator<String> toCheck = extras.keySet().iterator(); 372 while (toCheck.hasNext()) { 373 String extraKey = toCheck.next(); 374 if (TextUtils.isEmpty(extraKey) 375 || !RESTRICTED_CALL_SCREENING_EXTRA_KEYS.contains(extraKey)) { 376 toCheck.remove(); 377 } 378 } 379 return extras; 380 } 381 getParcelableState(Call call, boolean supportsExternalCalls)382 private static int getParcelableState(Call call, boolean supportsExternalCalls) { 383 int state = CallState.NEW; 384 switch (call.getState()) { 385 case CallState.ABORTED: 386 case CallState.DISCONNECTED: 387 state = android.telecom.Call.STATE_DISCONNECTED; 388 break; 389 case CallState.ACTIVE: 390 state = android.telecom.Call.STATE_ACTIVE; 391 break; 392 case CallState.CONNECTING: 393 state = android.telecom.Call.STATE_CONNECTING; 394 break; 395 case CallState.DIALING: 396 state = android.telecom.Call.STATE_DIALING; 397 break; 398 case CallState.PULLING: 399 if (supportsExternalCalls) { 400 // The InCallService supports external calls, so it must handle 401 // STATE_PULLING_CALL. 402 state = android.telecom.Call.STATE_PULLING_CALL; 403 } else { 404 // The InCallService does NOT support external calls, so remap 405 // STATE_PULLING_CALL to STATE_DIALING. In essence, pulling a call can be seen 406 // as a form of dialing, so it is appropriate for InCallServices which do not 407 // handle external calls. 408 state = android.telecom.Call.STATE_DIALING; 409 } 410 break; 411 case CallState.DISCONNECTING: 412 state = android.telecom.Call.STATE_DISCONNECTING; 413 break; 414 case CallState.NEW: 415 state = android.telecom.Call.STATE_NEW; 416 break; 417 case CallState.ON_HOLD: 418 state = android.telecom.Call.STATE_HOLDING; 419 break; 420 case CallState.RINGING: 421 case CallState.ANSWERED: 422 // TODO: does in-call UI need to see ANSWERED? 423 state = android.telecom.Call.STATE_RINGING; 424 break; 425 case CallState.SELECT_PHONE_ACCOUNT: 426 state = android.telecom.Call.STATE_SELECT_PHONE_ACCOUNT; 427 break; 428 case CallState.AUDIO_PROCESSING: 429 state = android.telecom.Call.STATE_AUDIO_PROCESSING; 430 break; 431 case CallState.SIMULATED_RINGING: 432 state = android.telecom.Call.STATE_SIMULATED_RINGING; 433 break; 434 } 435 436 // If we are marked as 'locally disconnecting' then mark ourselves as disconnecting instead. 437 // Unless we're disconnect*ED*, in which case leave it at that. 438 if (call.isLocallyDisconnecting() && 439 (state != android.telecom.Call.STATE_DISCONNECTED)) { 440 state = android.telecom.Call.STATE_DISCONNECTING; 441 } 442 return state; 443 } 444 445 private static final int[] CONNECTION_TO_CALL_CAPABILITY = new int[] { 446 Connection.CAPABILITY_HOLD, 447 android.telecom.Call.Details.CAPABILITY_HOLD, 448 449 Connection.CAPABILITY_SUPPORT_HOLD, 450 android.telecom.Call.Details.CAPABILITY_SUPPORT_HOLD, 451 452 Connection.CAPABILITY_MERGE_CONFERENCE, 453 android.telecom.Call.Details.CAPABILITY_MERGE_CONFERENCE, 454 455 Connection.CAPABILITY_SWAP_CONFERENCE, 456 android.telecom.Call.Details.CAPABILITY_SWAP_CONFERENCE, 457 458 Connection.CAPABILITY_RESPOND_VIA_TEXT, 459 android.telecom.Call.Details.CAPABILITY_RESPOND_VIA_TEXT, 460 461 Connection.CAPABILITY_MUTE, 462 android.telecom.Call.Details.CAPABILITY_MUTE, 463 464 Connection.CAPABILITY_MANAGE_CONFERENCE, 465 android.telecom.Call.Details.CAPABILITY_MANAGE_CONFERENCE, 466 467 Connection.CAPABILITY_SUPPORTS_VT_LOCAL_RX, 468 android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_RX, 469 470 Connection.CAPABILITY_SUPPORTS_VT_LOCAL_TX, 471 android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_TX, 472 473 Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL, 474 android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL, 475 476 Connection.CAPABILITY_SUPPORTS_VT_REMOTE_RX, 477 android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_RX, 478 479 Connection.CAPABILITY_SUPPORTS_VT_REMOTE_TX, 480 android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_TX, 481 482 Connection.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL, 483 android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL, 484 485 Connection.CAPABILITY_SEPARATE_FROM_CONFERENCE, 486 android.telecom.Call.Details.CAPABILITY_SEPARATE_FROM_CONFERENCE, 487 488 Connection.CAPABILITY_DISCONNECT_FROM_CONFERENCE, 489 android.telecom.Call.Details.CAPABILITY_DISCONNECT_FROM_CONFERENCE, 490 491 Connection.CAPABILITY_CAN_UPGRADE_TO_VIDEO, 492 android.telecom.Call.Details.CAPABILITY_CAN_UPGRADE_TO_VIDEO, 493 494 Connection.CAPABILITY_CAN_PAUSE_VIDEO, 495 android.telecom.Call.Details.CAPABILITY_CAN_PAUSE_VIDEO, 496 497 Connection.CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION, 498 android.telecom.Call.Details.CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION, 499 500 Connection.CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO, 501 android.telecom.Call.Details.CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO, 502 503 Connection.CAPABILITY_CAN_PULL_CALL, 504 android.telecom.Call.Details.CAPABILITY_CAN_PULL_CALL, 505 506 Connection.CAPABILITY_SUPPORT_DEFLECT, 507 android.telecom.Call.Details.CAPABILITY_SUPPORT_DEFLECT, 508 509 Connection.CAPABILITY_ADD_PARTICIPANT, 510 android.telecom.Call.Details.CAPABILITY_ADD_PARTICIPANT, 511 512 Connection.CAPABILITY_TRANSFER, 513 android.telecom.Call.Details.CAPABILITY_TRANSFER, 514 515 Connection.CAPABILITY_TRANSFER_CONSULTATIVE, 516 android.telecom.Call.Details.CAPABILITY_TRANSFER_CONSULTATIVE 517 }; 518 convertConnectionToCallCapabilities(int connectionCapabilities)519 private static int convertConnectionToCallCapabilities(int connectionCapabilities) { 520 int callCapabilities = 0; 521 for (int i = 0; i < CONNECTION_TO_CALL_CAPABILITY.length; i += 2) { 522 if ((CONNECTION_TO_CALL_CAPABILITY[i] & connectionCapabilities) == 523 CONNECTION_TO_CALL_CAPABILITY[i]) { 524 525 callCapabilities |= CONNECTION_TO_CALL_CAPABILITY[i + 1]; 526 } 527 } 528 return callCapabilities; 529 } 530 531 private static final int[] CONNECTION_TO_CALL_PROPERTIES = new int[] { 532 Connection.PROPERTY_HIGH_DEF_AUDIO, 533 android.telecom.Call.Details.PROPERTY_HIGH_DEF_AUDIO, 534 535 Connection.PROPERTY_WIFI, 536 android.telecom.Call.Details.PROPERTY_WIFI, 537 538 Connection.PROPERTY_GENERIC_CONFERENCE, 539 android.telecom.Call.Details.PROPERTY_GENERIC_CONFERENCE, 540 541 Connection.PROPERTY_EMERGENCY_CALLBACK_MODE, 542 android.telecom.Call.Details.PROPERTY_EMERGENCY_CALLBACK_MODE, 543 544 Connection.PROPERTY_IS_EXTERNAL_CALL, 545 android.telecom.Call.Details.PROPERTY_IS_EXTERNAL_CALL, 546 547 Connection.PROPERTY_HAS_CDMA_VOICE_PRIVACY, 548 android.telecom.Call.Details.PROPERTY_HAS_CDMA_VOICE_PRIVACY, 549 550 Connection.PROPERTY_SELF_MANAGED, 551 android.telecom.Call.Details.PROPERTY_SELF_MANAGED, 552 553 Connection.PROPERTY_ASSISTED_DIALING, 554 android.telecom.Call.Details.PROPERTY_ASSISTED_DIALING, 555 556 Connection.PROPERTY_IS_RTT, 557 android.telecom.Call.Details.PROPERTY_RTT, 558 559 Connection.PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL, 560 android.telecom.Call.Details.PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL, 561 562 Connection.PROPERTY_IS_ADHOC_CONFERENCE, 563 android.telecom.Call.Details.PROPERTY_IS_ADHOC_CONFERENCE 564 }; 565 convertConnectionToCallProperties(int connectionProperties)566 private static int convertConnectionToCallProperties(int connectionProperties) { 567 int callProperties = 0; 568 for (int i = 0; i < CONNECTION_TO_CALL_PROPERTIES.length; i += 2) { 569 if ((CONNECTION_TO_CALL_PROPERTIES[i] & connectionProperties) == 570 CONNECTION_TO_CALL_PROPERTIES[i]) { 571 572 callProperties |= CONNECTION_TO_CALL_PROPERTIES[i + 1]; 573 } 574 } 575 return callProperties; 576 } 577 578 /** 579 * Removes the specified capability from the set of capabilities bits and returns the new set. 580 */ removeCapability(int capabilities, int capability)581 private static int removeCapability(int capabilities, int capability) { 582 return capabilities & ~capability; 583 } 584 getParcelableRttCall(Call call)585 private static ParcelableRttCall getParcelableRttCall(Call call) { 586 if (!call.isRttCall()) { 587 return null; 588 } 589 return new ParcelableRttCall(call.getRttMode(), call.getInCallToCsRttPipeForInCall(), 590 call.getCsToInCallRttPipeForInCall()); 591 } 592 ParcelableCallUtils()593 private ParcelableCallUtils() {} 594 } 595