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