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