1 /*
2  * Copyright (C) 2014 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 static android.Manifest.permission.MODIFY_PHONE_STATE;
20 
21 import android.annotation.NonNull;
22 import android.annotation.RequiresPermission;
23 import android.annotation.SystemApi;
24 import android.annotation.TestApi;
25 import android.content.Intent;
26 import android.graphics.drawable.Icon;
27 import android.net.Uri;
28 import android.os.Bundle;
29 import android.os.Parcel;
30 import android.os.Parcelable;
31 import android.text.TextUtils;
32 
33 import java.util.ArrayList;
34 import java.util.Collections;
35 import java.util.List;
36 import java.util.Objects;
37 
38 /**
39  * Represents a distinct method to place or receive a phone call. Apps which can place calls and
40  * want those calls to be integrated into the dialer and in-call UI should build an instance of
41  * this class and register it with the system using {@link TelecomManager}.
42  * <p>
43  * {@link TelecomManager} uses registered {@link PhoneAccount}s to present the user with
44  * alternative options when placing a phone call. When building a {@link PhoneAccount}, the app
45  * should supply a valid {@link PhoneAccountHandle} that references the connection service
46  * implementation Telecom will use to interact with the app.
47  */
48 public final class PhoneAccount implements Parcelable {
49 
50     /**
51      * {@link PhoneAccount} extras key (see {@link PhoneAccount#getExtras()}) which determines the
52      * sort order for {@link PhoneAccount}s from the same
53      * {@link android.telecom.ConnectionService}.
54      * @hide
55      */
56     public static final String EXTRA_SORT_ORDER =
57             "android.telecom.extra.SORT_ORDER";
58 
59     /**
60      * {@link PhoneAccount} extras key (see {@link PhoneAccount#getExtras()}) which determines the
61      * maximum permitted length of a call subject specified via the
62      * {@link TelecomManager#EXTRA_CALL_SUBJECT} extra on an
63      * {@link android.content.Intent#ACTION_CALL} intent.  Ultimately a {@link ConnectionService} is
64      * responsible for enforcing the maximum call subject length when sending the message, however
65      * this extra is provided so that the user interface can proactively limit the length of the
66      * call subject as the user types it.
67      */
68     public static final String EXTRA_CALL_SUBJECT_MAX_LENGTH =
69             "android.telecom.extra.CALL_SUBJECT_MAX_LENGTH";
70 
71     /**
72      * {@link PhoneAccount} extras key (see {@link PhoneAccount#getExtras()}) which determines the
73      * character encoding to be used when determining the length of messages.
74      * The user interface can use this when determining the number of characters the user may type
75      * in a call subject.  If empty-string, the call subject message size limit will be enforced on
76      * a 1:1 basis.  That is, each character will count towards the messages size limit as a single
77      * character.  If a character encoding is specified, the message size limit will be based on the
78      * number of bytes in the message per the specified encoding.  See
79      * {@link #EXTRA_CALL_SUBJECT_MAX_LENGTH} for more information on the call subject maximum
80      * length.
81      */
82     public static final String EXTRA_CALL_SUBJECT_CHARACTER_ENCODING =
83             "android.telecom.extra.CALL_SUBJECT_CHARACTER_ENCODING";
84 
85     /**
86      * Boolean {@link PhoneAccount} extras key (see {@link PhoneAccount#getExtras()}) which
87      * indicates that all calls from this {@link PhoneAccount} should be treated as VoIP calls
88      * rather than cellular calls.
89      * @hide
90      */
91     public static final String EXTRA_ALWAYS_USE_VOIP_AUDIO_MODE =
92             "android.telecom.extra.ALWAYS_USE_VOIP_AUDIO_MODE";
93 
94     /**
95      * Boolean {@link PhoneAccount} extras key (see {@link PhoneAccount#getExtras()}) which
96      * indicates whether this {@link PhoneAccount} is capable of supporting a request to handover a
97      * connection (see {@code android.telecom.Call#handoverTo()}) to this {@link PhoneAccount} from
98      * a {@link PhoneAccount} specifying {@link #EXTRA_SUPPORTS_HANDOVER_FROM}.
99      * <p>
100      * A handover request is initiated by the user from the default dialer app to indicate a desire
101      * to handover a call from one {@link PhoneAccount}/{@link ConnectionService} to another.
102      */
103     public static final String EXTRA_SUPPORTS_HANDOVER_TO =
104             "android.telecom.extra.SUPPORTS_HANDOVER_TO";
105 
106     /**
107      * Boolean {@link PhoneAccount} extras key (see {@link PhoneAccount#getExtras()}) which
108      * indicates whether this {@link PhoneAccount} supports using a fallback if video calling is
109      * not available. This extra is for device level support, {@link
110      * android.telephony.CarrierConfigManager#KEY_ALLOW_VIDEO_CALLING_FALLBACK_BOOL} should also
111      * be checked to ensure it is not disabled by individual carrier.
112      *
113      * @hide
114      */
115     public static final String EXTRA_SUPPORTS_VIDEO_CALLING_FALLBACK =
116             "android.telecom.extra.SUPPORTS_VIDEO_CALLING_FALLBACK";
117 
118     /**
119      * Boolean {@link PhoneAccount} extras key (see {@link PhoneAccount#getExtras()}) which
120      * indicates whether this {@link PhoneAccount} is capable of supporting a request to handover a
121      * connection from this {@link PhoneAccount} to another {@link PhoneAccount}.
122      * (see {@code android.telecom.Call#handoverTo()}) which specifies
123      * {@link #EXTRA_SUPPORTS_HANDOVER_TO}.
124      * <p>
125      * A handover request is initiated by the user from the default dialer app to indicate a desire
126      * to handover a call from one {@link PhoneAccount}/{@link ConnectionService} to another.
127      */
128     public static final String EXTRA_SUPPORTS_HANDOVER_FROM =
129             "android.telecom.extra.SUPPORTS_HANDOVER_FROM";
130 
131 
132     /**
133      * Boolean {@link PhoneAccount} extras key (see {@link PhoneAccount#getExtras()}) which
134      * indicates whether a Self-Managed {@link PhoneAccount} should log its calls to the call log.
135      * Self-Managed {@link PhoneAccount}s are responsible for their own notifications, so the system
136      * will not create a notification when a missed call is logged.
137      * <p>
138      * By default, Self-Managed {@link PhoneAccount}s do not log their calls to the call log.
139      * Setting this extra to {@code true} provides a means for them to log their calls.
140      * <p>
141      * Note: Only calls where the {@link Call.Details#getHandle()} {@link Uri#getScheme()} is
142      * {@link #SCHEME_SIP} or {@link #SCHEME_TEL} will be logged at the current time.
143      */
144     public static final String EXTRA_LOG_SELF_MANAGED_CALLS =
145             "android.telecom.extra.LOG_SELF_MANAGED_CALLS";
146 
147     /**
148      * Boolean {@link PhoneAccount} extras key (see {@link PhoneAccount#getExtras()}) which
149      * indicates whether calls for a {@link PhoneAccount} should generate a "call recording tone"
150      * when the user is recording audio on the device.
151      * <p>
152      * The call recording tone is played over the telephony audio stream so that the remote party
153      * has an audible indication that it is possible their call is being recorded using a call
154      * recording app on the device.
155      * <p>
156      * This extra only has an effect for calls placed via Telephony (e.g.
157      * {@link #CAPABILITY_SIM_SUBSCRIPTION}).
158      * <p>
159      * The call recording tone is a 1400 hz tone which repeats every 15 seconds while recording is
160      * in progress.
161      * @hide
162      */
163     public static final String EXTRA_PLAY_CALL_RECORDING_TONE =
164             "android.telecom.extra.PLAY_CALL_RECORDING_TONE";
165 
166     /**
167      * Boolean {@link PhoneAccount} extras key (see {@link PhoneAccount#getExtras()} which
168      * indicates whether calls for a {@link PhoneAccount} should skip call filtering.
169      * <p>
170      * If not specified, this will default to false; all calls will undergo call filtering unless
171      * specifically exempted (e.g. {@link Connection#PROPERTY_EMERGENCY_CALLBACK_MODE}.) However,
172      * this may be used to skip call filtering when it has already been performed on another device.
173      * @hide
174      */
175     public static final String EXTRA_SKIP_CALL_FILTERING =
176         "android.telecom.extra.SKIP_CALL_FILTERING";
177 
178     /**
179      * Flag indicating that this {@code PhoneAccount} can act as a connection manager for
180      * other connections. The {@link ConnectionService} associated with this {@code PhoneAccount}
181      * will be allowed to manage phone calls including using its own proprietary phone-call
182      * implementation (like VoIP calling) to make calls instead of the telephony stack.
183      * <p>
184      * When a user opts to place a call using the SIM-based telephony stack, the
185      * {@link ConnectionService} associated with this {@code PhoneAccount} will be attempted first
186      * if the user has explicitly selected it to be used as the default connection manager.
187      * <p>
188      * See {@link #getCapabilities}
189      */
190     public static final int CAPABILITY_CONNECTION_MANAGER = 0x1;
191 
192     /**
193      * Flag indicating that this {@code PhoneAccount} can make phone calls in place of
194      * traditional SIM-based telephony calls. This account will be treated as a distinct method
195      * for placing calls alongside the traditional SIM-based telephony stack. This flag is
196      * distinct from {@link #CAPABILITY_CONNECTION_MANAGER} in that it is not allowed to manage
197      * or place calls from the built-in telephony stack.
198      * <p>
199      * See {@link #getCapabilities}
200      * <p>
201      */
202     public static final int CAPABILITY_CALL_PROVIDER = 0x2;
203 
204     /**
205      * Flag indicating that this {@code PhoneAccount} represents a built-in PSTN SIM
206      * subscription.
207      * <p>
208      * Only the Android framework can register a {@code PhoneAccount} having this capability.
209      * <p>
210      * See {@link #getCapabilities}
211      */
212     public static final int CAPABILITY_SIM_SUBSCRIPTION = 0x4;
213 
214     /**
215      * Flag indicating that this {@code PhoneAccount} is currently able to place video calls.
216      * <p>
217      * See also {@link #CAPABILITY_SUPPORTS_VIDEO_CALLING} which indicates whether the
218      * {@code PhoneAccount} supports placing video calls.
219      * <p>
220      * See {@link #getCapabilities}
221      */
222     public static final int CAPABILITY_VIDEO_CALLING = 0x8;
223 
224     /**
225      * Flag indicating that this {@code PhoneAccount} is capable of placing emergency calls.
226      * By default all PSTN {@code PhoneAccount}s are capable of placing emergency calls.
227      * <p>
228      * See {@link #getCapabilities}
229      */
230     public static final int CAPABILITY_PLACE_EMERGENCY_CALLS = 0x10;
231 
232     /**
233      * Flag indicating that this {@code PhoneAccount} is capable of being used by all users. This
234      * should only be used by system apps (and will be ignored for all other apps trying to use it).
235      * <p>
236      * See {@link #getCapabilities}
237      * @hide
238      */
239     @SystemApi
240     public static final int CAPABILITY_MULTI_USER = 0x20;
241 
242     /**
243      * Flag indicating that this {@code PhoneAccount} supports a subject for Calls.  This means a
244      * caller is able to specify a short subject line for an outgoing call.  A capable receiving
245      * device displays the call subject on the incoming call screen.
246      * <p>
247      * See {@link #getCapabilities}
248      */
249     public static final int CAPABILITY_CALL_SUBJECT = 0x40;
250 
251     /**
252      * Flag indicating that this {@code PhoneAccount} should only be used for emergency calls.
253      * <p>
254      * See {@link #getCapabilities}
255      * @hide
256      */
257     public static final int CAPABILITY_EMERGENCY_CALLS_ONLY = 0x80;
258 
259     /**
260      * Flag indicating that for this {@code PhoneAccount}, the ability to make a video call to a
261      * number relies on presence.  Should only be set if the {@code PhoneAccount} also has
262      * {@link #CAPABILITY_VIDEO_CALLING}.
263      * <p>
264      * When set, the {@link ConnectionService} is responsible for toggling the
265      * {@link android.provider.ContactsContract.Data#CARRIER_PRESENCE_VT_CAPABLE} bit on the
266      * {@link android.provider.ContactsContract.Data#CARRIER_PRESENCE} column to indicate whether
267      * a contact's phone number supports video calling.
268      * <p>
269      * See {@link #getCapabilities}
270      */
271     public static final int CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE = 0x100;
272 
273     /**
274      * Flag indicating that for this {@link PhoneAccount}, emergency video calling is allowed.
275      * <p>
276      * When set, Telecom will allow emergency video calls to be placed.  When not set, Telecom will
277      * convert all outgoing video calls to emergency numbers to audio-only.
278      * @hide
279      */
280     public static final int CAPABILITY_EMERGENCY_VIDEO_CALLING = 0x200;
281 
282     /**
283      * Flag indicating that this {@link PhoneAccount} supports video calling.
284      * This is not an indication that the {@link PhoneAccount} is currently able to make a video
285      * call, but rather that it has the ability to make video calls (but not necessarily at this
286      * time).
287      * <p>
288      * Whether a {@link PhoneAccount} can make a video call is ultimately controlled by
289      * {@link #CAPABILITY_VIDEO_CALLING}, which indicates whether the {@link PhoneAccount} is
290      * currently capable of making a video call.  Consider a case where, for example, a
291      * {@link PhoneAccount} supports making video calls (e.g.
292      * {@link #CAPABILITY_SUPPORTS_VIDEO_CALLING}), but a current lack of network connectivity
293      * prevents video calls from being made (e.g. {@link #CAPABILITY_VIDEO_CALLING}).
294      * <p>
295      * See {@link #getCapabilities}
296      */
297     public static final int CAPABILITY_SUPPORTS_VIDEO_CALLING = 0x400;
298 
299     /**
300      * Flag indicating that this {@link PhoneAccount} is responsible for managing its own
301      * {@link Connection}s.  This type of {@link PhoneAccount} is ideal for use with standalone
302      * calling apps which do not wish to use the default phone app for {@link Connection} UX,
303      * but which want to leverage the call and audio routing capabilities of the Telecom framework.
304      * <p>
305      * When set, {@link Connection}s created by the self-managed {@link ConnectionService} will not
306      * be surfaced to implementations of the {@link InCallService} API.  Thus it is the
307      * responsibility of a self-managed {@link ConnectionService} to provide a user interface for
308      * its {@link Connection}s.
309      * <p>
310      * Self-managed {@link Connection}s will, however, be displayed on connected Bluetooth devices.
311      */
312     public static final int CAPABILITY_SELF_MANAGED = 0x800;
313 
314     /**
315      * Flag indicating that this {@link PhoneAccount} is capable of making a call with an
316      * RTT (Real-time text) session.
317      * When set, Telecom will attempt to open an RTT session on outgoing calls that specify
318      * that they should be placed with an RTT session , and the in-call app will be displayed
319      * with text entry fields for RTT. Likewise, the in-call app can request that an RTT
320      * session be opened during a call if this bit is set.
321      */
322     public static final int CAPABILITY_RTT = 0x1000;
323 
324     /**
325      * Flag indicating that this {@link PhoneAccount} is the preferred SIM subscription for
326      * emergency calls. A {@link PhoneAccount} that sets this capabilitiy must also
327      * set the {@link #CAPABILITY_SIM_SUBSCRIPTION} and {@link #CAPABILITY_PLACE_EMERGENCY_CALLS}
328      * capabilities. There should only be one emergency preferred {@link PhoneAccount}.
329      * <p>
330      * When set, Telecom will prefer this {@link PhoneAccount} over others for emergency calling,
331      * even if the emergency call was placed with a specific {@link PhoneAccount} set using the
332      * extra{@link TelecomManager#EXTRA_PHONE_ACCOUNT_HANDLE} in
333      * {@link Intent#ACTION_CALL_EMERGENCY} or {@link TelecomManager#placeCall(Uri, Bundle)}.
334      *
335      * @hide
336      */
337     public static final int CAPABILITY_EMERGENCY_PREFERRED = 0x2000;
338 
339     /**
340      * An adhoc conference call is established by providing a list of addresses to
341      * {@code TelecomManager#startConference(List<Uri>, int videoState)} where the
342      * {@link ConnectionService} is responsible for connecting all indicated participants
343      * to a conference simultaneously.
344      * This is in contrast to conferences formed by merging calls together (e.g. using
345      * {@link android.telecom.Call#mergeConference()}).
346      */
347     public static final int CAPABILITY_ADHOC_CONFERENCE_CALLING = 0x4000;
348 
349     /* NEXT CAPABILITY: 0x8000 */
350 
351     /**
352      * URI scheme for telephone number URIs.
353      */
354     public static final String SCHEME_TEL = "tel";
355 
356     /**
357      * URI scheme for voicemail URIs.
358      */
359     public static final String SCHEME_VOICEMAIL = "voicemail";
360 
361     /**
362      * URI scheme for SIP URIs.
363      */
364     public static final String SCHEME_SIP = "sip";
365 
366     /**
367      * Indicating no icon tint is set.
368      * @hide
369      */
370     public static final int NO_ICON_TINT = 0;
371 
372     /**
373      * Indicating no hightlight color is set.
374      */
375     public static final int NO_HIGHLIGHT_COLOR = 0;
376 
377     /**
378      * Indicating no resource ID is set.
379      */
380     public static final int NO_RESOURCE_ID = -1;
381 
382     private final PhoneAccountHandle mAccountHandle;
383     private final Uri mAddress;
384     private final Uri mSubscriptionAddress;
385     private final int mCapabilities;
386     private final int mHighlightColor;
387     private final CharSequence mLabel;
388     private final CharSequence mShortDescription;
389     private final List<String> mSupportedUriSchemes;
390     private final int mSupportedAudioRoutes;
391     private final Icon mIcon;
392     private final Bundle mExtras;
393     private boolean mIsEnabled;
394     private String mGroupId;
395 
396     @Override
equals(Object o)397     public boolean equals(Object o) {
398         if (this == o) return true;
399         if (o == null || getClass() != o.getClass()) return false;
400         PhoneAccount that = (PhoneAccount) o;
401         return mCapabilities == that.mCapabilities &&
402                 mHighlightColor == that.mHighlightColor &&
403                 mSupportedAudioRoutes == that.mSupportedAudioRoutes &&
404                 mIsEnabled == that.mIsEnabled &&
405                 Objects.equals(mAccountHandle, that.mAccountHandle) &&
406                 Objects.equals(mAddress, that.mAddress) &&
407                 Objects.equals(mSubscriptionAddress, that.mSubscriptionAddress) &&
408                 Objects.equals(mLabel, that.mLabel) &&
409                 Objects.equals(mShortDescription, that.mShortDescription) &&
410                 Objects.equals(mSupportedUriSchemes, that.mSupportedUriSchemes) &&
411                 areBundlesEqual(mExtras, that.mExtras) &&
412                 Objects.equals(mGroupId, that.mGroupId);
413     }
414 
415     @Override
hashCode()416     public int hashCode() {
417         return Objects.hash(mAccountHandle, mAddress, mSubscriptionAddress, mCapabilities,
418                 mHighlightColor, mLabel, mShortDescription, mSupportedUriSchemes,
419                 mSupportedAudioRoutes,
420                 mExtras, mIsEnabled, mGroupId);
421     }
422 
423     /**
424      * Helper class for creating a {@link PhoneAccount}.
425      */
426     public static class Builder {
427 
428         private PhoneAccountHandle mAccountHandle;
429         private Uri mAddress;
430         private Uri mSubscriptionAddress;
431         private int mCapabilities;
432         private int mSupportedAudioRoutes = CallAudioState.ROUTE_ALL;
433         private int mHighlightColor = NO_HIGHLIGHT_COLOR;
434         private CharSequence mLabel;
435         private CharSequence mShortDescription;
436         private List<String> mSupportedUriSchemes = new ArrayList<String>();
437         private Icon mIcon;
438         private Bundle mExtras;
439         private boolean mIsEnabled = false;
440         private String mGroupId = "";
441 
442         /**
443          * Creates a builder with the specified {@link PhoneAccountHandle} and label.
444          */
Builder(PhoneAccountHandle accountHandle, CharSequence label)445         public Builder(PhoneAccountHandle accountHandle, CharSequence label) {
446             this.mAccountHandle = accountHandle;
447             this.mLabel = label;
448         }
449 
450         /**
451          * Creates an instance of the {@link PhoneAccount.Builder} from an existing
452          * {@link PhoneAccount}.
453          *
454          * @param phoneAccount The {@link PhoneAccount} used to initialize the builder.
455          */
Builder(PhoneAccount phoneAccount)456         public Builder(PhoneAccount phoneAccount) {
457             mAccountHandle = phoneAccount.getAccountHandle();
458             mAddress = phoneAccount.getAddress();
459             mSubscriptionAddress = phoneAccount.getSubscriptionAddress();
460             mCapabilities = phoneAccount.getCapabilities();
461             mHighlightColor = phoneAccount.getHighlightColor();
462             mLabel = phoneAccount.getLabel();
463             mShortDescription = phoneAccount.getShortDescription();
464             mSupportedUriSchemes.addAll(phoneAccount.getSupportedUriSchemes());
465             mIcon = phoneAccount.getIcon();
466             mIsEnabled = phoneAccount.isEnabled();
467             mExtras = phoneAccount.getExtras();
468             mGroupId = phoneAccount.getGroupId();
469             mSupportedAudioRoutes = phoneAccount.getSupportedAudioRoutes();
470         }
471 
472         /**
473          * Sets the label. See {@link PhoneAccount#getLabel()}.
474          *
475          * @param label The label of the phone account.
476          * @return The builder.
477          * @hide
478          */
setLabel(CharSequence label)479         public Builder setLabel(CharSequence label) {
480             this.mLabel = label;
481             return this;
482         }
483 
484         /**
485          * Sets the address. See {@link PhoneAccount#getAddress}.
486          *
487          * @param value The address of the phone account.
488          * @return The builder.
489          */
setAddress(Uri value)490         public Builder setAddress(Uri value) {
491             this.mAddress = value;
492             return this;
493         }
494 
495         /**
496          * Sets the subscription address. See {@link PhoneAccount#getSubscriptionAddress}.
497          *
498          * @param value The subscription address.
499          * @return The builder.
500          */
setSubscriptionAddress(Uri value)501         public Builder setSubscriptionAddress(Uri value) {
502             this.mSubscriptionAddress = value;
503             return this;
504         }
505 
506         /**
507          * Sets the capabilities. See {@link PhoneAccount#getCapabilities}.
508          *
509          * @param value The capabilities to set.
510          * @return The builder.
511          */
setCapabilities(int value)512         public Builder setCapabilities(int value) {
513             this.mCapabilities = value;
514             return this;
515         }
516 
517         /**
518          * Sets the icon. See {@link PhoneAccount#getIcon}.
519          *
520          * @param icon The icon to set.
521          */
setIcon(Icon icon)522         public Builder setIcon(Icon icon) {
523             mIcon = icon;
524             return this;
525         }
526 
527         /**
528          * Sets the highlight color. See {@link PhoneAccount#getHighlightColor}.
529          *
530          * @param value The highlight color.
531          * @return The builder.
532          */
setHighlightColor(int value)533         public Builder setHighlightColor(int value) {
534             this.mHighlightColor = value;
535             return this;
536         }
537 
538         /**
539          * Sets the short description. See {@link PhoneAccount#getShortDescription}.
540          *
541          * @param value The short description.
542          * @return The builder.
543          */
setShortDescription(CharSequence value)544         public Builder setShortDescription(CharSequence value) {
545             this.mShortDescription = value;
546             return this;
547         }
548 
549         /**
550          * Specifies an additional URI scheme supported by the {@link PhoneAccount}.
551          *
552          * @param uriScheme The URI scheme.
553          * @return The builder.
554          */
addSupportedUriScheme(String uriScheme)555         public Builder addSupportedUriScheme(String uriScheme) {
556             if (!TextUtils.isEmpty(uriScheme) && !mSupportedUriSchemes.contains(uriScheme)) {
557                 this.mSupportedUriSchemes.add(uriScheme);
558             }
559             return this;
560         }
561 
562         /**
563          * Specifies the URI schemes supported by the {@link PhoneAccount}.
564          *
565          * @param uriSchemes The URI schemes.
566          * @return The builder.
567          */
setSupportedUriSchemes(List<String> uriSchemes)568         public Builder setSupportedUriSchemes(List<String> uriSchemes) {
569             mSupportedUriSchemes.clear();
570 
571             if (uriSchemes != null && !uriSchemes.isEmpty()) {
572                 for (String uriScheme : uriSchemes) {
573                     addSupportedUriScheme(uriScheme);
574                 }
575             }
576             return this;
577         }
578 
579         /**
580          * Specifies the extras associated with the {@link PhoneAccount}.
581          * <p>
582          * {@code PhoneAccount}s only support extra values of type: {@link String}, {@link Integer},
583          * and {@link Boolean}.  Extras which are not of these types are ignored.
584          *
585          * @param extras
586          * @return
587          */
setExtras(Bundle extras)588         public Builder setExtras(Bundle extras) {
589             mExtras = extras;
590             return this;
591         }
592 
593         /**
594          * Sets the enabled state of the phone account.
595          *
596          * @param isEnabled The enabled state.
597          * @return The builder.
598          * @hide
599          */
setIsEnabled(boolean isEnabled)600         public Builder setIsEnabled(boolean isEnabled) {
601             mIsEnabled = isEnabled;
602             return this;
603         }
604 
605         /**
606          * Sets the group Id of the {@link PhoneAccount}. When a new {@link PhoneAccount} is
607          * registered to Telecom, it will replace another {@link PhoneAccount} that is already
608          * registered in Telecom and take on the current user defaults and enabled status. There can
609          * only be one {@link PhoneAccount} with a non-empty group number registered to Telecom at a
610          * time. By default, there is no group Id for a {@link PhoneAccount} (an empty String). Only
611          * grouped {@link PhoneAccount}s with the same {@link ConnectionService} can be replaced.
612          * <p>
613          * Note: This is an API specific to the Telephony stack; the group Id will be ignored for
614          * callers not holding the correct permission.
615          *
616          * @param groupId The group Id of the {@link PhoneAccount} that will replace any other
617          * registered {@link PhoneAccount} in Telecom with the same Group Id.
618          * @return The builder
619          * @hide
620          */
621         @SystemApi
622         @TestApi
623         @RequiresPermission(MODIFY_PHONE_STATE)
setGroupId(@onNull String groupId)624         public @NonNull Builder setGroupId(@NonNull String groupId) {
625             if (groupId != null) {
626                 mGroupId = groupId;
627             } else {
628                 mGroupId = "";
629             }
630             return this;
631         }
632 
633         /**
634          * Sets the audio routes supported by this {@link PhoneAccount}.
635          *
636          * @param routes bit mask of available routes.
637          * @return The builder.
638          * @hide
639          */
setSupportedAudioRoutes(int routes)640         public Builder setSupportedAudioRoutes(int routes) {
641             mSupportedAudioRoutes = routes;
642             return this;
643         }
644 
645         /**
646          * Creates an instance of a {@link PhoneAccount} based on the current builder settings.
647          *
648          * @return The {@link PhoneAccount}.
649          */
build()650         public PhoneAccount build() {
651             // If no supported URI schemes were defined, assume "tel" is supported.
652             if (mSupportedUriSchemes.isEmpty()) {
653                 addSupportedUriScheme(SCHEME_TEL);
654             }
655 
656             return new PhoneAccount(
657                     mAccountHandle,
658                     mAddress,
659                     mSubscriptionAddress,
660                     mCapabilities,
661                     mIcon,
662                     mHighlightColor,
663                     mLabel,
664                     mShortDescription,
665                     mSupportedUriSchemes,
666                     mExtras,
667                     mSupportedAudioRoutes,
668                     mIsEnabled,
669                     mGroupId);
670         }
671     }
672 
PhoneAccount( PhoneAccountHandle account, Uri address, Uri subscriptionAddress, int capabilities, Icon icon, int highlightColor, CharSequence label, CharSequence shortDescription, List<String> supportedUriSchemes, Bundle extras, int supportedAudioRoutes, boolean isEnabled, String groupId)673     private PhoneAccount(
674             PhoneAccountHandle account,
675             Uri address,
676             Uri subscriptionAddress,
677             int capabilities,
678             Icon icon,
679             int highlightColor,
680             CharSequence label,
681             CharSequence shortDescription,
682             List<String> supportedUriSchemes,
683             Bundle extras,
684             int supportedAudioRoutes,
685             boolean isEnabled,
686             String groupId) {
687         mAccountHandle = account;
688         mAddress = address;
689         mSubscriptionAddress = subscriptionAddress;
690         mCapabilities = capabilities;
691         mIcon = icon;
692         mHighlightColor = highlightColor;
693         mLabel = label;
694         mShortDescription = shortDescription;
695         mSupportedUriSchemes = Collections.unmodifiableList(supportedUriSchemes);
696         mExtras = extras;
697         mSupportedAudioRoutes = supportedAudioRoutes;
698         mIsEnabled = isEnabled;
699         mGroupId = groupId;
700     }
701 
builder( PhoneAccountHandle accountHandle, CharSequence label)702     public static Builder builder(
703             PhoneAccountHandle accountHandle,
704             CharSequence label) {
705         return new Builder(accountHandle, label);
706     }
707 
708     /**
709      * Returns a builder initialized with the current {@link PhoneAccount} instance.
710      *
711      * @return The builder.
712      */
toBuilder()713     public Builder toBuilder() { return new Builder(this); }
714 
715     /**
716      * The unique identifier of this {@code PhoneAccount}.
717      *
718      * @return A {@code PhoneAccountHandle}.
719      */
getAccountHandle()720     public PhoneAccountHandle getAccountHandle() {
721         return mAccountHandle;
722     }
723 
724     /**
725      * The address (e.g., a phone number) associated with this {@code PhoneAccount}. This
726      * represents the destination from which outgoing calls using this {@code PhoneAccount}
727      * will appear to come, if applicable, and the destination to which incoming calls using this
728      * {@code PhoneAccount} may be addressed.
729      *
730      * @return A address expressed as a {@code Uri}, for example, a phone number.
731      */
getAddress()732     public Uri getAddress() {
733         return mAddress;
734     }
735 
736     /**
737      * The raw callback number used for this {@code PhoneAccount}, as distinct from
738      * {@link #getAddress()}. For the majority of {@code PhoneAccount}s this should be registered
739      * as {@code null}.  It is used by the system for SIM-based {@code PhoneAccount} registration
740      * where {@link android.telephony.TelephonyManager#setLine1NumberForDisplay(String, String)}
741      * has been used to alter the callback number.
742      * <p>
743      *
744      * @return The subscription number, suitable for display to the user.
745      */
getSubscriptionAddress()746     public Uri getSubscriptionAddress() {
747         return mSubscriptionAddress;
748     }
749 
750     /**
751      * The capabilities of this {@code PhoneAccount}.
752      *
753      * @return A bit field of flags describing this {@code PhoneAccount}'s capabilities.
754      */
getCapabilities()755     public int getCapabilities() {
756         return mCapabilities;
757     }
758 
759     /**
760      * Determines if this {@code PhoneAccount} has a capabilities specified by the passed in
761      * bit mask.
762      *
763      * @param capability The capabilities to check.
764      * @return {@code true} if the phone account has the capability.
765      */
hasCapabilities(int capability)766     public boolean hasCapabilities(int capability) {
767         return (mCapabilities & capability) == capability;
768     }
769 
770     /**
771      * Determines if this {@code PhoneAccount} has routes specified by the passed in bit mask.
772      *
773      * @param route The routes to check.
774      * @return {@code true} if the phone account has the routes.
775      * @hide
776      */
hasAudioRoutes(int routes)777     public boolean hasAudioRoutes(int routes) {
778         return (mSupportedAudioRoutes & routes) == routes;
779     }
780 
781     /**
782      * A short label describing a {@code PhoneAccount}.
783      *
784      * @return A label for this {@code PhoneAccount}.
785      */
getLabel()786     public CharSequence getLabel() {
787         return mLabel;
788     }
789 
790     /**
791      * A short paragraph describing this {@code PhoneAccount}.
792      *
793      * @return A description for this {@code PhoneAccount}.
794      */
getShortDescription()795     public CharSequence getShortDescription() {
796         return mShortDescription;
797     }
798 
799     /**
800      * The URI schemes supported by this {@code PhoneAccount}.
801      *
802      * @return The URI schemes.
803      */
getSupportedUriSchemes()804     public List<String> getSupportedUriSchemes() {
805         return mSupportedUriSchemes;
806     }
807 
808     /**
809      * The extras associated with this {@code PhoneAccount}.
810      * <p>
811      * A {@link ConnectionService} may provide implementation specific information about the
812      * {@link PhoneAccount} via the extras.
813      *
814      * @return The extras.
815      */
getExtras()816     public Bundle getExtras() {
817         return mExtras;
818     }
819 
820     /**
821      * The audio routes supported by this {@code PhoneAccount}.
822      *
823      * @hide
824      */
getSupportedAudioRoutes()825     public int getSupportedAudioRoutes() {
826         return mSupportedAudioRoutes;
827     }
828 
829     /**
830      * The icon to represent this {@code PhoneAccount}.
831      *
832      * @return The icon.
833      */
getIcon()834     public Icon getIcon() {
835         return mIcon;
836     }
837 
838     /**
839      * Indicates whether the user has enabled this {@code PhoneAccount} or not. This value is only
840      * populated for {@code PhoneAccount}s returned by {@link TelecomManager#getPhoneAccount}.
841      *
842      * @return {@code true} if the account is enabled by the user, {@code false} otherwise.
843      */
isEnabled()844     public boolean isEnabled() {
845         return mIsEnabled;
846     }
847 
848     /**
849      * A non-empty {@link String} representing the group that A {@link PhoneAccount} is in or an
850      * empty {@link String} if the {@link PhoneAccount} is not in a group. If this
851      * {@link PhoneAccount} is in a group, this new {@link PhoneAccount} will replace a registered
852      * {@link PhoneAccount} that is in the same group. When the {@link PhoneAccount} is replaced,
853      * its user defined defaults and enabled status will also pass to this new {@link PhoneAccount}.
854      * Only {@link PhoneAccount}s that share the same {@link ConnectionService} can be replaced.
855      *
856      * @return A non-empty String Id if this {@link PhoneAccount} belongs to a group.
857      * @hide
858      */
getGroupId()859     public String getGroupId() {
860         return mGroupId;
861     }
862 
863     /**
864      * Determines if the {@link PhoneAccount} supports calls to/from addresses with a specified URI
865      * scheme.
866      *
867      * @param uriScheme The URI scheme to check.
868      * @return {@code true} if the {@code PhoneAccount} supports calls to/from addresses with the
869      * specified URI scheme.
870      */
supportsUriScheme(String uriScheme)871     public boolean supportsUriScheme(String uriScheme) {
872         if (mSupportedUriSchemes == null || uriScheme == null) {
873             return false;
874         }
875 
876         for (String scheme : mSupportedUriSchemes) {
877             if (scheme != null && scheme.equals(uriScheme)) {
878                 return true;
879             }
880         }
881         return false;
882     }
883 
884     /**
885      * A highlight color to use in displaying information about this {@code PhoneAccount}.
886      *
887      * @return A hexadecimal color value.
888      */
getHighlightColor()889     public int getHighlightColor() {
890         return mHighlightColor;
891     }
892 
893     /**
894      * Sets the enabled state of the phone account.
895      * @hide
896      */
setIsEnabled(boolean isEnabled)897     public void setIsEnabled(boolean isEnabled) {
898         mIsEnabled = isEnabled;
899     }
900 
901     /**
902      * @return {@code true} if the {@link PhoneAccount} is self-managed, {@code false} otherwise.
903      * @hide
904      */
isSelfManaged()905     public boolean isSelfManaged() {
906         return (mCapabilities & CAPABILITY_SELF_MANAGED) == CAPABILITY_SELF_MANAGED;
907     }
908 
909     //
910     // Parcelable implementation
911     //
912 
913     @Override
describeContents()914     public int describeContents() {
915         return 0;
916     }
917 
918     @Override
writeToParcel(Parcel out, int flags)919     public void writeToParcel(Parcel out, int flags) {
920         if (mAccountHandle == null) {
921             out.writeInt(0);
922         } else {
923             out.writeInt(1);
924             mAccountHandle.writeToParcel(out, flags);
925         }
926         if (mAddress == null) {
927             out.writeInt(0);
928         } else {
929             out.writeInt(1);
930             mAddress.writeToParcel(out, flags);
931         }
932         if (mSubscriptionAddress == null) {
933             out.writeInt(0);
934         } else {
935             out.writeInt(1);
936             mSubscriptionAddress.writeToParcel(out, flags);
937         }
938         out.writeInt(mCapabilities);
939         out.writeInt(mHighlightColor);
940         out.writeCharSequence(mLabel);
941         out.writeCharSequence(mShortDescription);
942         out.writeStringList(mSupportedUriSchemes);
943 
944         if (mIcon == null) {
945             out.writeInt(0);
946         } else {
947             out.writeInt(1);
948             mIcon.writeToParcel(out, flags);
949         }
950         out.writeByte((byte) (mIsEnabled ? 1 : 0));
951         out.writeBundle(mExtras);
952         out.writeString(mGroupId);
953         out.writeInt(mSupportedAudioRoutes);
954     }
955 
956     public static final @android.annotation.NonNull Creator<PhoneAccount> CREATOR
957             = new Creator<PhoneAccount>() {
958         @Override
959         public PhoneAccount createFromParcel(Parcel in) {
960             return new PhoneAccount(in);
961         }
962 
963         @Override
964         public PhoneAccount[] newArray(int size) {
965             return new PhoneAccount[size];
966         }
967     };
968 
PhoneAccount(Parcel in)969     private PhoneAccount(Parcel in) {
970         if (in.readInt() > 0) {
971             mAccountHandle = PhoneAccountHandle.CREATOR.createFromParcel(in);
972         } else {
973             mAccountHandle = null;
974         }
975         if (in.readInt() > 0) {
976             mAddress = Uri.CREATOR.createFromParcel(in);
977         } else {
978             mAddress = null;
979         }
980         if (in.readInt() > 0) {
981             mSubscriptionAddress = Uri.CREATOR.createFromParcel(in);
982         } else {
983             mSubscriptionAddress = null;
984         }
985         mCapabilities = in.readInt();
986         mHighlightColor = in.readInt();
987         mLabel = in.readCharSequence();
988         mShortDescription = in.readCharSequence();
989         mSupportedUriSchemes = Collections.unmodifiableList(in.createStringArrayList());
990         if (in.readInt() > 0) {
991             mIcon = Icon.CREATOR.createFromParcel(in);
992         } else {
993             mIcon = null;
994         }
995         mIsEnabled = in.readByte() == 1;
996         mExtras = in.readBundle();
997         mGroupId = in.readString();
998         mSupportedAudioRoutes = in.readInt();
999     }
1000 
1001     @Override
toString()1002     public String toString() {
1003         StringBuilder sb = new StringBuilder().append("[[")
1004                 .append(mIsEnabled ? 'X' : ' ')
1005                 .append("] PhoneAccount: ")
1006                 .append(mAccountHandle)
1007                 .append(" Capabilities: ")
1008                 .append(capabilitiesToString())
1009                 .append(" Audio Routes: ")
1010                 .append(audioRoutesToString())
1011                 .append(" Schemes: ");
1012         for (String scheme : mSupportedUriSchemes) {
1013             sb.append(scheme)
1014                     .append(" ");
1015         }
1016         sb.append(" Extras: ");
1017         sb.append(mExtras);
1018         sb.append(" GroupId: ");
1019         sb.append(Log.pii(mGroupId));
1020         sb.append("]");
1021         return sb.toString();
1022     }
1023 
1024     /**
1025      * Generates a string representation of a capabilities bitmask.
1026      *
1027      * @return String representation of the capabilities bitmask.
1028      * @hide
1029      */
capabilitiesToString()1030     public String capabilitiesToString() {
1031         StringBuilder sb = new StringBuilder();
1032         if (hasCapabilities(CAPABILITY_SELF_MANAGED)) {
1033             sb.append("SelfManaged ");
1034         }
1035         if (hasCapabilities(CAPABILITY_SUPPORTS_VIDEO_CALLING)) {
1036             sb.append("SuppVideo ");
1037         }
1038         if (hasCapabilities(CAPABILITY_VIDEO_CALLING)) {
1039             sb.append("Video ");
1040         }
1041         if (hasCapabilities(CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE)) {
1042             sb.append("Presence ");
1043         }
1044         if (hasCapabilities(CAPABILITY_CALL_PROVIDER)) {
1045             sb.append("CallProvider ");
1046         }
1047         if (hasCapabilities(CAPABILITY_CALL_SUBJECT)) {
1048             sb.append("CallSubject ");
1049         }
1050         if (hasCapabilities(CAPABILITY_CONNECTION_MANAGER)) {
1051             sb.append("ConnectionMgr ");
1052         }
1053         if (hasCapabilities(CAPABILITY_EMERGENCY_CALLS_ONLY)) {
1054             sb.append("EmergOnly ");
1055         }
1056         if (hasCapabilities(CAPABILITY_MULTI_USER)) {
1057             sb.append("MultiUser ");
1058         }
1059         if (hasCapabilities(CAPABILITY_PLACE_EMERGENCY_CALLS)) {
1060             sb.append("PlaceEmerg ");
1061         }
1062         if (hasCapabilities(CAPABILITY_EMERGENCY_PREFERRED)) {
1063             sb.append("EmerPrefer ");
1064         }
1065         if (hasCapabilities(CAPABILITY_EMERGENCY_VIDEO_CALLING)) {
1066             sb.append("EmergVideo ");
1067         }
1068         if (hasCapabilities(CAPABILITY_SIM_SUBSCRIPTION)) {
1069             sb.append("SimSub ");
1070         }
1071         if (hasCapabilities(CAPABILITY_RTT)) {
1072             sb.append("Rtt");
1073         }
1074         if (hasCapabilities(CAPABILITY_ADHOC_CONFERENCE_CALLING)) {
1075             sb.append("AdhocConf");
1076         }
1077         return sb.toString();
1078     }
1079 
audioRoutesToString()1080     private String audioRoutesToString() {
1081         StringBuilder sb = new StringBuilder();
1082 
1083         if (hasAudioRoutes(CallAudioState.ROUTE_BLUETOOTH)) {
1084             sb.append("B");
1085         }
1086         if (hasAudioRoutes(CallAudioState.ROUTE_EARPIECE)) {
1087             sb.append("E");
1088         }
1089         if (hasAudioRoutes(CallAudioState.ROUTE_SPEAKER)) {
1090             sb.append("S");
1091         }
1092         if (hasAudioRoutes(CallAudioState.ROUTE_WIRED_HEADSET)) {
1093             sb.append("W");
1094         }
1095 
1096         return sb.toString();
1097     }
1098 
1099     /**
1100      * Determines if two {@link Bundle}s are equal.
1101      * @param extras First {@link Bundle} to check.
1102      * @param newExtras {@link Bundle} to compare against.
1103      * @return {@code true} if the {@link Bundle}s are equal, {@code false} otherwise.
1104      */
areBundlesEqual(Bundle extras, Bundle newExtras)1105     private static boolean areBundlesEqual(Bundle extras, Bundle newExtras) {
1106         if (extras == null || newExtras == null) {
1107             return extras == newExtras;
1108         }
1109 
1110         if (extras.size() != newExtras.size()) {
1111             return false;
1112         }
1113 
1114         for(String key : extras.keySet()) {
1115             if (key != null) {
1116                 final Object value = extras.get(key);
1117                 final Object newValue = newExtras.get(key);
1118                 if (!Objects.equals(value, newValue)) {
1119                     return false;
1120                 }
1121             }
1122         }
1123         return true;
1124     }
1125 }
1126