| /* |
| * Copyright (C) 2022 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.telecom; |
| |
| import android.annotation.IntDef; |
| import android.annotation.NonNull; |
| import android.annotation.Nullable; |
| import android.net.Uri; |
| import android.os.Parcel; |
| import android.os.Parcelable; |
| import android.text.TextUtils; |
| |
| import java.util.Objects; |
| |
| /** |
| * CallAttributes represents a set of properties that define a new Call. Apps should build an |
| * instance of this class and use {@link TelecomManager#addCall} to start a new call with Telecom. |
| * |
| * <p> |
| * Apps should first register a {@link PhoneAccount} via {@link TelecomManager#registerPhoneAccount} |
| * and use the same {@link PhoneAccountHandle} registered with Telecom when creating an |
| * instance of CallAttributes. |
| */ |
| public final class CallAttributes implements Parcelable { |
| |
| /** PhoneAccountHandle associated with the App managing calls **/ |
| private final PhoneAccountHandle mPhoneAccountHandle; |
| |
| /** Display name of the person on the other end of the call **/ |
| private final CharSequence mDisplayName; |
| |
| /** Address of the call. Note, this can be extended to a meeting link **/ |
| private final Uri mAddress; |
| |
| /** The direction (Outgoing/Incoming) of the new Call **/ |
| @Direction private final int mDirection; |
| |
| /** Information related to data being transmitted (voice, video, etc. ) **/ |
| @CallType private final int mCallType; |
| |
| /** Allows a package to opt into capabilities on the telecom side, on a per-call basis **/ |
| @CallCapability private final int mCallCapabilities; |
| |
| /** @hide **/ |
| public static final String CALL_CAPABILITIES_KEY = "TelecomCapabilities"; |
| |
| private CallAttributes(@NonNull PhoneAccountHandle phoneAccountHandle, |
| @NonNull CharSequence displayName, |
| @NonNull Uri address, |
| int direction, |
| int callType, |
| int callCapabilities) { |
| mPhoneAccountHandle = phoneAccountHandle; |
| mDisplayName = displayName; |
| mAddress = address; |
| mDirection = direction; |
| mCallType = callType; |
| mCallCapabilities = callCapabilities; |
| } |
| |
| /** @hide */ |
| @IntDef(value = {DIRECTION_INCOMING, DIRECTION_OUTGOING}) |
| public @interface Direction { |
| } |
| /** |
| * Indicates that the call is an incoming call. |
| */ |
| public static final int DIRECTION_INCOMING = 1; |
| /** |
| * Indicates that the call is an outgoing call. |
| */ |
| public static final int DIRECTION_OUTGOING = 2; |
| |
| /** @hide */ |
| @IntDef(value = {AUDIO_CALL, VIDEO_CALL}) |
| public @interface CallType { |
| } |
| /** |
| * Used when answering or dialing a call to indicate that the call does not have a video |
| * component |
| */ |
| public static final int AUDIO_CALL = 1; |
| /** |
| * Indicates video transmission is supported |
| */ |
| public static final int VIDEO_CALL = 2; |
| |
| /** @hide */ |
| @IntDef(value = {SUPPORTS_SET_INACTIVE, SUPPORTS_STREAM, SUPPORTS_TRANSFER}, flag = true) |
| public @interface CallCapability { |
| } |
| /** |
| * The call being created can be set to inactive (traditionally referred to as hold). This |
| * means that once a new call goes active, if the active call needs to be held in order to |
| * place or receive an incoming call, the active call will be placed on hold. otherwise, the |
| * active call may be disconnected. |
| */ |
| public static final int SUPPORTS_SET_INACTIVE = 1 << 1; |
| /** |
| * The call can be streamed from a root device to another device to continue the call without |
| * completely transferring it. |
| */ |
| public static final int SUPPORTS_STREAM = 1 << 2; |
| /** |
| * The call can be completely transferred from one endpoint to another. |
| */ |
| public static final int SUPPORTS_TRANSFER = 1 << 3; |
| |
| /** |
| * Build an instance of {@link CallAttributes}. In order to build a valid instance, a |
| * {@link PhoneAccountHandle}, call direction, display name, and {@link Uri} address |
| * are required. |
| * |
| * <p> |
| * Note: Pass in the same {@link PhoneAccountHandle} that was used to register a |
| * {@link PhoneAccount} with Telecom. see {@link TelecomManager#registerPhoneAccount} |
| */ |
| public static final class Builder { |
| // required and final fields |
| private final PhoneAccountHandle mPhoneAccountHandle; |
| @Direction private final int mDirection; |
| private final CharSequence mDisplayName; |
| private final Uri mAddress; |
| // optional fields |
| @CallType private int mCallType = CallAttributes.AUDIO_CALL; |
| @CallCapability private int mCallCapabilities = SUPPORTS_SET_INACTIVE; |
| |
| /** |
| * Constructor for the CallAttributes.Builder class |
| * |
| * @param phoneAccountHandle that belongs to package registered with Telecom |
| * @param callDirection of the new call that will be added to Telecom |
| * @param displayName of the caller for incoming calls or initiating user for outgoing calls |
| * @param address of the caller for incoming calls or destination for outgoing calls |
| */ |
| public Builder(@NonNull PhoneAccountHandle phoneAccountHandle, |
| @Direction int callDirection, @NonNull CharSequence displayName, |
| @NonNull Uri address) { |
| if (!isInRange(DIRECTION_INCOMING, DIRECTION_OUTGOING, callDirection)) { |
| throw new IllegalArgumentException(TextUtils.formatSimple("CallDirection=[%d] is" |
| + " invalid. CallDirections value should be within [%d, %d]", |
| callDirection, DIRECTION_INCOMING, DIRECTION_OUTGOING)); |
| } |
| Objects.requireNonNull(phoneAccountHandle); |
| Objects.requireNonNull(displayName); |
| Objects.requireNonNull(address); |
| mPhoneAccountHandle = phoneAccountHandle; |
| mDirection = callDirection; |
| mDisplayName = displayName; |
| mAddress = address; |
| } |
| |
| /** |
| * Sets the type of call; uses to indicate if a call is a video call or audio call. |
| * @param callType The call type. |
| * @return Builder |
| */ |
| @NonNull |
| public Builder setCallType(@CallType int callType) { |
| if (!isInRange(AUDIO_CALL, VIDEO_CALL, callType)) { |
| throw new IllegalArgumentException(TextUtils.formatSimple("CallType=[%d] is" |
| + " invalid. CallTypes value should be within [%d, %d]", |
| callType, AUDIO_CALL, VIDEO_CALL)); |
| } |
| mCallType = callType; |
| return this; |
| } |
| |
| /** |
| * Sets the capabilities of this call. Use this to indicate whether your app supports |
| * holding, streaming and call transfers. |
| * @param callCapabilities Bitmask of call capabilities. |
| * @return Builder |
| */ |
| @NonNull |
| public Builder setCallCapabilities(@CallCapability int callCapabilities) { |
| mCallCapabilities = callCapabilities; |
| return this; |
| } |
| |
| /** |
| * Build an instance of {@link CallAttributes} based on the last values passed to the |
| * setters or default values. |
| * |
| * @return an instance of {@link CallAttributes} |
| */ |
| @NonNull |
| public CallAttributes build() { |
| return new CallAttributes(mPhoneAccountHandle, mDisplayName, mAddress, mDirection, |
| mCallType, mCallCapabilities); |
| } |
| |
| /** @hide */ |
| private boolean isInRange(int floor, int ceiling, int value) { |
| return value >= floor && value <= ceiling; |
| } |
| } |
| |
| /** |
| * The {@link PhoneAccountHandle} that should be registered to Telecom to allow calls. The |
| * {@link PhoneAccountHandle} should be registered before creating a CallAttributes instance. |
| * |
| * @return the {@link PhoneAccountHandle} for this package that allows this call to be created |
| */ |
| @NonNull public PhoneAccountHandle getPhoneAccountHandle() { |
| return mPhoneAccountHandle; |
| } |
| |
| /** |
| * @return display name of the incoming caller or the person being called for an outgoing call |
| */ |
| @NonNull public CharSequence getDisplayName() { |
| return mDisplayName; |
| } |
| |
| /** |
| * @return address of the incoming caller |
| * or the address of the person being called for an outgoing call |
| */ |
| @NonNull public Uri getAddress() { |
| return mAddress; |
| } |
| |
| /** |
| * @return the direction of the new call. |
| */ |
| public @Direction int getDirection() { |
| return mDirection; |
| } |
| |
| /** |
| * @return Information related to data being transmitted (voice, video, etc. ) |
| */ |
| public @CallType int getCallType() { |
| return mCallType; |
| } |
| |
| /** |
| * @return The allowed capabilities of the new call |
| */ |
| public @CallCapability int getCallCapabilities() { |
| return mCallCapabilities; |
| } |
| |
| @Override |
| public int describeContents() { |
| return 0; |
| } |
| |
| @Override |
| public void writeToParcel(@Nullable Parcel dest, int flags) { |
| dest.writeParcelable(mPhoneAccountHandle, flags); |
| dest.writeCharSequence(mDisplayName); |
| dest.writeParcelable(mAddress, flags); |
| dest.writeInt(mDirection); |
| dest.writeInt(mCallType); |
| dest.writeInt(mCallCapabilities); |
| } |
| |
| /** |
| * Responsible for creating CallAttribute objects for deserialized Parcels. |
| */ |
| public static final @android.annotation.NonNull |
| Parcelable.Creator<CallAttributes> CREATOR = |
| new Parcelable.Creator<>() { |
| @Override |
| public CallAttributes createFromParcel(Parcel source) { |
| return new CallAttributes(source.readParcelable(getClass().getClassLoader(), |
| android.telecom.PhoneAccountHandle.class), |
| source.readCharSequence(), |
| source.readParcelable(getClass().getClassLoader(), |
| android.net.Uri.class), |
| source.readInt(), |
| source.readInt(), |
| source.readInt()); |
| } |
| |
| @Override |
| public CallAttributes[] newArray(int size) { |
| return new CallAttributes[size]; |
| } |
| }; |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public String toString() { |
| StringBuilder sb = new StringBuilder(); |
| |
| sb.append("{ CallAttributes: [phoneAccountHandle: ") |
| .append(mPhoneAccountHandle) /* PhoneAccountHandle#toString handles PII */ |
| .append("], [contactName: ") |
| .append(Log.pii(mDisplayName)) |
| .append("], [address=") |
| .append(Log.pii(mAddress)) |
| .append("], [direction=") |
| .append(mDirection) |
| .append("], [callType=") |
| .append(mCallType) |
| .append("], [mCallCapabilities=") |
| .append(mCallCapabilities) |
| .append("] }"); |
| |
| return sb.toString(); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public boolean equals(Object obj) { |
| if (obj == null || obj.getClass() != this.getClass()) { |
| return false; |
| } |
| CallAttributes that = (CallAttributes) obj; |
| return this.mDirection == that.mDirection |
| && this.mCallType == that.mCallType |
| && this.mCallCapabilities == that.mCallCapabilities |
| && Objects.equals(this.mPhoneAccountHandle, that.mPhoneAccountHandle) |
| && Objects.equals(this.mAddress, that.mAddress) |
| && Objects.equals(this.mDisplayName, that.mDisplayName); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public int hashCode() { |
| return Objects.hash(mPhoneAccountHandle, mAddress, mDisplayName, |
| mDirection, mCallType, mCallCapabilities); |
| } |
| } |