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 17package com.android.server.telecom; 18 19import android.net.Uri; 20import android.telecom.Connection; 21import android.telecom.ParcelableCall; 22import android.telecom.TelecomManager; 23 24import java.util.ArrayList; 25import java.util.List; 26 27/** 28 * Utilities dealing with {@link ParcelableCall}. 29 */ 30public class ParcelableCallUtils { 31 public static class Converter { 32 public ParcelableCall toParcelableCall(Call call, boolean includeVideoProvider, 33 PhoneAccountRegistrar phoneAccountRegistrar) { 34 return ParcelableCallUtils.toParcelableCall( 35 call, includeVideoProvider, phoneAccountRegistrar); 36 } 37 } 38 39 /** 40 * Parcels all information for a {@link Call} into a new {@link ParcelableCall} instance. 41 * 42 * @param call The {@link Call} to parcel. 43 * @param includeVideoProvider {@code true} if the video provider should be parcelled with the 44 * {@link Call}, {@code false} otherwise. Since the {@link ParcelableCall#getVideoCall()} 45 * method creates a {@link VideoCallImpl} instance on access it is important for the 46 * recipient of the {@link ParcelableCall} to know if the video provider changed. 47 * @param phoneAccountRegistrar The {@link PhoneAccountRegistrar}. 48 * @return The {@link ParcelableCall} containing all call information from the {@link Call}. 49 */ 50 public static ParcelableCall toParcelableCall( 51 Call call, 52 boolean includeVideoProvider, 53 PhoneAccountRegistrar phoneAccountRegistrar) { 54 int state = getParcelableState(call); 55 int capabilities = convertConnectionToCallCapabilities(call.getConnectionCapabilities()); 56 int properties = convertConnectionToCallProperties(call.getConnectionProperties()); 57 if (call.isConference()) { 58 properties |= android.telecom.Call.Details.PROPERTY_CONFERENCE; 59 } 60 61 if (call.isWorkCall()) { 62 properties |= android.telecom.Call.Details.PROPERTY_ENTERPRISE_CALL; 63 } 64 65 // If this is a single-SIM device, the "default SIM" will always be the only SIM. 66 boolean isDefaultSmsAccount = 67 phoneAccountRegistrar.isUserSelectedSmsPhoneAccount(call.getTargetPhoneAccount()); 68 if (call.isRespondViaSmsCapable() && isDefaultSmsAccount) { 69 capabilities |= android.telecom.Call.Details.CAPABILITY_RESPOND_VIA_TEXT; 70 } 71 72 if (call.isEmergencyCall()) { 73 capabilities = removeCapability( 74 capabilities, android.telecom.Call.Details.CAPABILITY_MUTE); 75 } 76 77 if (state == android.telecom.Call.STATE_DIALING) { 78 capabilities = removeCapability(capabilities, 79 android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL); 80 capabilities = removeCapability(capabilities, 81 android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL); 82 } 83 84 String parentCallId = null; 85 Call parentCall = call.getParentCall(); 86 if (parentCall != null) { 87 parentCallId = parentCall.getId(); 88 } 89 90 long connectTimeMillis = call.getConnectTimeMillis(); 91 List<Call> childCalls = call.getChildCalls(); 92 List<String> childCallIds = new ArrayList<>(); 93 if (!childCalls.isEmpty()) { 94 long childConnectTimeMillis = Long.MAX_VALUE; 95 for (Call child : childCalls) { 96 if (child.getConnectTimeMillis() > 0) { 97 childConnectTimeMillis = Math.min(child.getConnectTimeMillis(), 98 childConnectTimeMillis); 99 } 100 childCallIds.add(child.getId()); 101 } 102 103 if (childConnectTimeMillis != Long.MAX_VALUE) { 104 connectTimeMillis = childConnectTimeMillis; 105 } 106 } 107 108 Uri handle = call.getHandlePresentation() == TelecomManager.PRESENTATION_ALLOWED ? 109 call.getHandle() : null; 110 String callerDisplayName = call.getCallerDisplayNamePresentation() == 111 TelecomManager.PRESENTATION_ALLOWED ? call.getCallerDisplayName() : null; 112 113 List<Call> conferenceableCalls = call.getConferenceableCalls(); 114 List<String> conferenceableCallIds = new ArrayList<String>(conferenceableCalls.size()); 115 for (Call otherCall : conferenceableCalls) { 116 conferenceableCallIds.add(otherCall.getId()); 117 } 118 119 return new ParcelableCall( 120 call.getId(), 121 state, 122 call.getDisconnectCause(), 123 call.getCannedSmsResponses(), 124 capabilities, 125 properties, 126 connectTimeMillis, 127 handle, 128 call.getHandlePresentation(), 129 callerDisplayName, 130 call.getCallerDisplayNamePresentation(), 131 call.getGatewayInfo(), 132 call.getTargetPhoneAccount(), 133 includeVideoProvider, 134 includeVideoProvider ? call.getVideoProvider() : null, 135 parentCallId, 136 childCallIds, 137 call.getStatusHints(), 138 call.getVideoState(), 139 conferenceableCallIds, 140 call.getIntentExtras(), 141 call.getExtras()); 142 } 143 144 private static int getParcelableState(Call call) { 145 int state = CallState.NEW; 146 switch (call.getState()) { 147 case CallState.ABORTED: 148 case CallState.DISCONNECTED: 149 state = android.telecom.Call.STATE_DISCONNECTED; 150 break; 151 case CallState.ACTIVE: 152 state = android.telecom.Call.STATE_ACTIVE; 153 break; 154 case CallState.CONNECTING: 155 state = android.telecom.Call.STATE_CONNECTING; 156 break; 157 case CallState.DIALING: 158 state = android.telecom.Call.STATE_DIALING; 159 break; 160 case CallState.DISCONNECTING: 161 state = android.telecom.Call.STATE_DISCONNECTING; 162 break; 163 case CallState.NEW: 164 state = android.telecom.Call.STATE_NEW; 165 break; 166 case CallState.ON_HOLD: 167 state = android.telecom.Call.STATE_HOLDING; 168 break; 169 case CallState.RINGING: 170 state = android.telecom.Call.STATE_RINGING; 171 break; 172 case CallState.SELECT_PHONE_ACCOUNT: 173 state = android.telecom.Call.STATE_SELECT_PHONE_ACCOUNT; 174 break; 175 } 176 177 // If we are marked as 'locally disconnecting' then mark ourselves as disconnecting instead. 178 // Unless we're disconnect*ED*, in which case leave it at that. 179 if (call.isLocallyDisconnecting() && 180 (state != android.telecom.Call.STATE_DISCONNECTED)) { 181 state = android.telecom.Call.STATE_DISCONNECTING; 182 } 183 return state; 184 } 185 186 private static final int[] CONNECTION_TO_CALL_CAPABILITY = new int[] { 187 Connection.CAPABILITY_HOLD, 188 android.telecom.Call.Details.CAPABILITY_HOLD, 189 190 Connection.CAPABILITY_SUPPORT_HOLD, 191 android.telecom.Call.Details.CAPABILITY_SUPPORT_HOLD, 192 193 Connection.CAPABILITY_MERGE_CONFERENCE, 194 android.telecom.Call.Details.CAPABILITY_MERGE_CONFERENCE, 195 196 Connection.CAPABILITY_SWAP_CONFERENCE, 197 android.telecom.Call.Details.CAPABILITY_SWAP_CONFERENCE, 198 199 Connection.CAPABILITY_RESPOND_VIA_TEXT, 200 android.telecom.Call.Details.CAPABILITY_RESPOND_VIA_TEXT, 201 202 Connection.CAPABILITY_MUTE, 203 android.telecom.Call.Details.CAPABILITY_MUTE, 204 205 Connection.CAPABILITY_MANAGE_CONFERENCE, 206 android.telecom.Call.Details.CAPABILITY_MANAGE_CONFERENCE, 207 208 Connection.CAPABILITY_SUPPORTS_VT_LOCAL_RX, 209 android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_RX, 210 211 Connection.CAPABILITY_SUPPORTS_VT_LOCAL_TX, 212 android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_TX, 213 214 Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL, 215 android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL, 216 217 Connection.CAPABILITY_SUPPORTS_VT_REMOTE_RX, 218 android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_RX, 219 220 Connection.CAPABILITY_SUPPORTS_VT_REMOTE_TX, 221 android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_TX, 222 223 Connection.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL, 224 android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL, 225 226 Connection.CAPABILITY_SEPARATE_FROM_CONFERENCE, 227 android.telecom.Call.Details.CAPABILITY_SEPARATE_FROM_CONFERENCE, 228 229 Connection.CAPABILITY_DISCONNECT_FROM_CONFERENCE, 230 android.telecom.Call.Details.CAPABILITY_DISCONNECT_FROM_CONFERENCE, 231 232 Connection.CAPABILITY_CAN_UPGRADE_TO_VIDEO, 233 android.telecom.Call.Details.CAPABILITY_CAN_UPGRADE_TO_VIDEO, 234 235 Connection.CAPABILITY_CAN_PAUSE_VIDEO, 236 android.telecom.Call.Details.CAPABILITY_CAN_PAUSE_VIDEO, 237 238 Connection.CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION, 239 android.telecom.Call.Details.CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION, 240 241 Connection.CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO, 242 android.telecom.Call.Details.CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO, 243 244 Connection.CAPABILITY_CAN_PULL_CALL, 245 android.telecom.Call.Details.CAPABILITY_CAN_PULL_CALL 246 }; 247 248 private static int convertConnectionToCallCapabilities(int connectionCapabilities) { 249 int callCapabilities = 0; 250 for (int i = 0; i < CONNECTION_TO_CALL_CAPABILITY.length; i += 2) { 251 if ((CONNECTION_TO_CALL_CAPABILITY[i] & connectionCapabilities) == 252 CONNECTION_TO_CALL_CAPABILITY[i]) { 253 254 callCapabilities |= CONNECTION_TO_CALL_CAPABILITY[i + 1]; 255 } 256 } 257 return callCapabilities; 258 } 259 260 private static final int[] CONNECTION_TO_CALL_PROPERTIES = new int[] { 261 Connection.PROPERTY_HIGH_DEF_AUDIO, 262 android.telecom.Call.Details.PROPERTY_HIGH_DEF_AUDIO, 263 264 Connection.PROPERTY_WIFI, 265 android.telecom.Call.Details.PROPERTY_WIFI, 266 267 Connection.PROPERTY_GENERIC_CONFERENCE, 268 android.telecom.Call.Details.PROPERTY_GENERIC_CONFERENCE, 269 270 Connection.PROPERTY_SHOW_CALLBACK_NUMBER, 271 android.telecom.Call.Details.PROPERTY_EMERGENCY_CALLBACK_MODE, 272 273 Connection.PROPERTY_IS_EXTERNAL_CALL, 274 android.telecom.Call.Details.PROPERTY_IS_EXTERNAL_CALL 275 }; 276 277 private static int convertConnectionToCallProperties(int connectionProperties) { 278 int callProperties = 0; 279 for (int i = 0; i < CONNECTION_TO_CALL_PROPERTIES.length; i += 2) { 280 if ((CONNECTION_TO_CALL_PROPERTIES[i] & connectionProperties) == 281 CONNECTION_TO_CALL_PROPERTIES[i]) { 282 283 callProperties |= CONNECTION_TO_CALL_PROPERTIES[i + 1]; 284 } 285 } 286 return callProperties; 287 } 288 289 /** 290 * Removes the specified capability from the set of capabilities bits and returns the new set. 291 */ 292 private static int removeCapability(int capabilities, int capability) { 293 return capabilities & ~capability; 294 } 295 296 private ParcelableCallUtils() {} 297} 298