• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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