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