1 /* 2 * Copyright (C) 2022 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 android.telecom; 18 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.net.Uri; 23 import android.os.Parcel; 24 import android.os.Parcelable; 25 import android.text.TextUtils; 26 27 import java.util.Objects; 28 29 /** 30 * CallAttributes represents a set of properties that define a new Call. Apps should build an 31 * instance of this class and use {@link TelecomManager#addCall} to start a new call with Telecom. 32 * 33 * <p> 34 * Apps should first register a {@link PhoneAccount} via {@link TelecomManager#registerPhoneAccount} 35 * and use the same {@link PhoneAccountHandle} registered with Telecom when creating an 36 * instance of CallAttributes. 37 */ 38 public final class CallAttributes implements Parcelable { 39 40 /** PhoneAccountHandle associated with the App managing calls **/ 41 private final PhoneAccountHandle mPhoneAccountHandle; 42 43 /** Display name of the person on the other end of the call **/ 44 private final CharSequence mDisplayName; 45 46 /** Address of the call. Note, this can be extended to a meeting link **/ 47 private final Uri mAddress; 48 49 /** The direction (Outgoing/Incoming) of the new Call **/ 50 @Direction private final int mDirection; 51 52 /** Information related to data being transmitted (voice, video, etc. ) **/ 53 @CallType private final int mCallType; 54 55 /** Allows a package to opt into capabilities on the telecom side, on a per-call basis **/ 56 @CallCapability private final int mCallCapabilities; 57 58 /** @hide **/ 59 public static final String CALL_CAPABILITIES_KEY = "TelecomCapabilities"; 60 61 /** @hide **/ 62 public static final String DISPLAY_NAME_KEY = "DisplayName"; 63 64 /** @hide **/ 65 public static final String CALLER_PID_KEY = "CallerPid"; 66 67 /** @hide **/ 68 public static final String CALLER_UID_KEY = "CallerUid"; 69 CallAttributes(@onNull PhoneAccountHandle phoneAccountHandle, @NonNull CharSequence displayName, @NonNull Uri address, int direction, int callType, int callCapabilities)70 private CallAttributes(@NonNull PhoneAccountHandle phoneAccountHandle, 71 @NonNull CharSequence displayName, 72 @NonNull Uri address, 73 int direction, 74 int callType, 75 int callCapabilities) { 76 mPhoneAccountHandle = phoneAccountHandle; 77 mDisplayName = displayName; 78 mAddress = address; 79 mDirection = direction; 80 mCallType = callType; 81 mCallCapabilities = callCapabilities; 82 } 83 84 /** @hide */ 85 @IntDef(value = {DIRECTION_INCOMING, DIRECTION_OUTGOING}) 86 public @interface Direction { 87 } 88 /** 89 * Indicates that the call is an incoming call. 90 */ 91 public static final int DIRECTION_INCOMING = 1; 92 /** 93 * Indicates that the call is an outgoing call. 94 */ 95 public static final int DIRECTION_OUTGOING = 2; 96 97 /** @hide */ 98 @IntDef(value = {AUDIO_CALL, VIDEO_CALL}) 99 public @interface CallType { 100 } 101 /** 102 * Used when answering or dialing a call to indicate that the call does not have a video 103 * component 104 */ 105 public static final int AUDIO_CALL = 1; 106 /** 107 * Indicates video transmission is supported 108 */ 109 public static final int VIDEO_CALL = 2; 110 111 /** @hide */ 112 @IntDef(value = {SUPPORTS_SET_INACTIVE, SUPPORTS_STREAM, SUPPORTS_TRANSFER}, flag = true) 113 public @interface CallCapability { 114 } 115 /** 116 * The call being created can be set to inactive (traditionally referred to as hold). This 117 * means that once a new call goes active, if the active call needs to be held in order to 118 * place or receive an incoming call, the active call will be placed on hold. otherwise, the 119 * active call may be disconnected. 120 */ 121 public static final int SUPPORTS_SET_INACTIVE = 1 << 1; 122 /** 123 * The call can be streamed from a root device to another device to continue the call without 124 * completely transferring it. 125 */ 126 public static final int SUPPORTS_STREAM = 1 << 2; 127 /** 128 * The call can be completely transferred from one endpoint to another. 129 */ 130 public static final int SUPPORTS_TRANSFER = 1 << 3; 131 132 /** 133 * Build an instance of {@link CallAttributes}. In order to build a valid instance, a 134 * {@link PhoneAccountHandle}, call direction, display name, and {@link Uri} address 135 * are required. 136 * 137 * <p> 138 * Note: Pass in the same {@link PhoneAccountHandle} that was used to register a 139 * {@link PhoneAccount} with Telecom. see {@link TelecomManager#registerPhoneAccount} 140 */ 141 public static final class Builder { 142 // required and final fields 143 private final PhoneAccountHandle mPhoneAccountHandle; 144 @Direction private final int mDirection; 145 private final CharSequence mDisplayName; 146 private final Uri mAddress; 147 // optional fields 148 @CallType private int mCallType = CallAttributes.AUDIO_CALL; 149 @CallCapability private int mCallCapabilities = SUPPORTS_SET_INACTIVE; 150 151 /** 152 * Constructor for the CallAttributes.Builder class 153 * 154 * @param phoneAccountHandle that belongs to package registered with Telecom 155 * @param callDirection of the new call that will be added to Telecom 156 * @param displayName of the caller for incoming calls or initiating user for outgoing calls 157 * @param address of the caller for incoming calls or destination for outgoing calls 158 */ Builder(@onNull PhoneAccountHandle phoneAccountHandle, @Direction int callDirection, @NonNull CharSequence displayName, @NonNull Uri address)159 public Builder(@NonNull PhoneAccountHandle phoneAccountHandle, 160 @Direction int callDirection, @NonNull CharSequence displayName, 161 @NonNull Uri address) { 162 if (!isInRange(DIRECTION_INCOMING, DIRECTION_OUTGOING, callDirection)) { 163 throw new IllegalArgumentException(TextUtils.formatSimple("CallDirection=[%d] is" 164 + " invalid. CallDirections value should be within [%d, %d]", 165 callDirection, DIRECTION_INCOMING, DIRECTION_OUTGOING)); 166 } 167 Objects.requireNonNull(phoneAccountHandle); 168 Objects.requireNonNull(displayName); 169 Objects.requireNonNull(address); 170 mPhoneAccountHandle = phoneAccountHandle; 171 mDirection = callDirection; 172 mDisplayName = displayName; 173 mAddress = address; 174 } 175 176 /** 177 * Sets the type of call; uses to indicate if a call is a video call or audio call. 178 * @param callType The call type. 179 * @return Builder 180 */ 181 @NonNull setCallType(@allType int callType)182 public Builder setCallType(@CallType int callType) { 183 if (!isInRange(AUDIO_CALL, VIDEO_CALL, callType)) { 184 throw new IllegalArgumentException(TextUtils.formatSimple("CallType=[%d] is" 185 + " invalid. CallTypes value should be within [%d, %d]", 186 callType, AUDIO_CALL, VIDEO_CALL)); 187 } 188 mCallType = callType; 189 return this; 190 } 191 192 /** 193 * Sets the capabilities of this call. Use this to indicate whether your app supports 194 * holding, streaming and call transfers. 195 * @param callCapabilities Bitmask of call capabilities. 196 * @return Builder 197 */ 198 @NonNull setCallCapabilities(@allCapability int callCapabilities)199 public Builder setCallCapabilities(@CallCapability int callCapabilities) { 200 mCallCapabilities = callCapabilities; 201 return this; 202 } 203 204 /** 205 * Build an instance of {@link CallAttributes} based on the last values passed to the 206 * setters or default values. 207 * 208 * @return an instance of {@link CallAttributes} 209 */ 210 @NonNull build()211 public CallAttributes build() { 212 return new CallAttributes(mPhoneAccountHandle, mDisplayName, mAddress, mDirection, 213 mCallType, mCallCapabilities); 214 } 215 216 /** @hide */ isInRange(int floor, int ceiling, int value)217 private boolean isInRange(int floor, int ceiling, int value) { 218 return value >= floor && value <= ceiling; 219 } 220 } 221 222 /** 223 * The {@link PhoneAccountHandle} that should be registered to Telecom to allow calls. The 224 * {@link PhoneAccountHandle} should be registered before creating a CallAttributes instance. 225 * 226 * @return the {@link PhoneAccountHandle} for this package that allows this call to be created 227 */ getPhoneAccountHandle()228 @NonNull public PhoneAccountHandle getPhoneAccountHandle() { 229 return mPhoneAccountHandle; 230 } 231 232 /** 233 * @return display name of the incoming caller or the person being called for an outgoing call 234 */ getDisplayName()235 @NonNull public CharSequence getDisplayName() { 236 return mDisplayName; 237 } 238 239 /** 240 * @return address of the incoming caller 241 * or the address of the person being called for an outgoing call 242 */ getAddress()243 @NonNull public Uri getAddress() { 244 return mAddress; 245 } 246 247 /** 248 * @return the direction of the new call. 249 */ getDirection()250 public @Direction int getDirection() { 251 return mDirection; 252 } 253 254 /** 255 * @return Information related to data being transmitted (voice, video, etc. ) 256 */ getCallType()257 public @CallType int getCallType() { 258 return mCallType; 259 } 260 261 /** 262 * @return The allowed capabilities of the new call 263 */ getCallCapabilities()264 public @CallCapability int getCallCapabilities() { 265 return mCallCapabilities; 266 } 267 268 @Override describeContents()269 public int describeContents() { 270 return 0; 271 } 272 273 @Override writeToParcel(@ullable Parcel dest, int flags)274 public void writeToParcel(@Nullable Parcel dest, int flags) { 275 dest.writeParcelable(mPhoneAccountHandle, flags); 276 dest.writeCharSequence(mDisplayName); 277 dest.writeParcelable(mAddress, flags); 278 dest.writeInt(mDirection); 279 dest.writeInt(mCallType); 280 dest.writeInt(mCallCapabilities); 281 } 282 283 /** 284 * Responsible for creating CallAttribute objects for deserialized Parcels. 285 */ 286 public static final @android.annotation.NonNull 287 Parcelable.Creator<CallAttributes> CREATOR = 288 new Parcelable.Creator<>() { 289 @Override 290 public CallAttributes createFromParcel(Parcel source) { 291 return new CallAttributes(source.readParcelable(getClass().getClassLoader(), 292 android.telecom.PhoneAccountHandle.class), 293 source.readCharSequence(), 294 source.readParcelable(getClass().getClassLoader(), 295 android.net.Uri.class), 296 source.readInt(), 297 source.readInt(), 298 source.readInt()); 299 } 300 301 @Override 302 public CallAttributes[] newArray(int size) { 303 return new CallAttributes[size]; 304 } 305 }; 306 307 /** 308 * {@inheritDoc} 309 */ 310 @Override toString()311 public String toString() { 312 StringBuilder sb = new StringBuilder(); 313 314 sb.append("{ CallAttributes: [phoneAccountHandle: ") 315 .append(mPhoneAccountHandle) /* PhoneAccountHandle#toString handles PII */ 316 .append("], [contactName: ") 317 .append(Log.pii(mDisplayName)) 318 .append("], [address=") 319 .append(Log.pii(mAddress)) 320 .append("], [direction=") 321 .append(mDirection) 322 .append("], [callType=") 323 .append(mCallType) 324 .append("], [mCallCapabilities=") 325 .append(mCallCapabilities) 326 .append("] }"); 327 328 return sb.toString(); 329 } 330 331 /** 332 * {@inheritDoc} 333 */ 334 @Override equals(Object obj)335 public boolean equals(Object obj) { 336 if (obj == null || obj.getClass() != this.getClass()) { 337 return false; 338 } 339 CallAttributes that = (CallAttributes) obj; 340 return this.mDirection == that.mDirection 341 && this.mCallType == that.mCallType 342 && this.mCallCapabilities == that.mCallCapabilities 343 && Objects.equals(this.mPhoneAccountHandle, that.mPhoneAccountHandle) 344 && Objects.equals(this.mAddress, that.mAddress) 345 && Objects.equals(this.mDisplayName, that.mDisplayName); 346 } 347 348 /** 349 * {@inheritDoc} 350 */ 351 @Override hashCode()352 public int hashCode() { 353 return Objects.hash(mPhoneAccountHandle, mAddress, mDisplayName, 354 mDirection, mCallType, mCallCapabilities); 355 } 356 } 357