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