OSDN Git Service

DO NOT MERGE. Grant MMS Uri permissions as the calling UID.
[android-x86/frameworks-base.git] / telecomm / java / android / telecom / PhoneAccount.java
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.ComponentName;
21 import android.content.Context;
22 import android.content.pm.PackageManager;
23 import android.content.res.Resources.NotFoundException;
24 import android.graphics.Bitmap;
25 import android.graphics.Color;
26 import android.graphics.drawable.BitmapDrawable;
27 import android.graphics.drawable.ColorDrawable;
28 import android.graphics.drawable.Drawable;
29 import android.graphics.drawable.Icon;
30 import android.net.Uri;
31 import android.os.Bundle;
32 import android.os.Parcel;
33 import android.os.Parcelable;
34 import android.text.TextUtils;
35
36 import java.lang.String;
37 import java.util.ArrayList;
38 import java.util.Collections;
39 import java.util.List;
40 import java.util.MissingResourceException;
41
42 /**
43  * Represents a distinct method to place or receive a phone call. Apps which can place calls and
44  * want those calls to be integrated into the dialer and in-call UI should build an instance of
45  * this class and register it with the system using {@link TelecomManager}.
46  * <p>
47  * {@link TelecomManager} uses registered {@link PhoneAccount}s to present the user with
48  * alternative options when placing a phone call. When building a {@link PhoneAccount}, the app
49  * should supply a valid {@link PhoneAccountHandle} that references the connection service
50  * implementation Telecom will use to interact with the app.
51  */
52 public final class PhoneAccount implements Parcelable {
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      * Flag indicating that this {@code PhoneAccount} can act as a connection manager for
82      * other connections. The {@link ConnectionService} associated with this {@code PhoneAccount}
83      * will be allowed to manage phone calls including using its own proprietary phone-call
84      * implementation (like VoIP calling) to make calls instead of the telephony stack.
85      * <p>
86      * When a user opts to place a call using the SIM-based telephony stack, the
87      * {@link ConnectionService} associated with this {@code PhoneAccount} will be attempted first
88      * if the user has explicitly selected it to be used as the default connection manager.
89      * <p>
90      * See {@link #getCapabilities}
91      */
92     public static final int CAPABILITY_CONNECTION_MANAGER = 0x1;
93
94     /**
95      * Flag indicating that this {@code PhoneAccount} can make phone calls in place of
96      * traditional SIM-based telephony calls. This account will be treated as a distinct method
97      * for placing calls alongside the traditional SIM-based telephony stack. This flag is
98      * distinct from {@link #CAPABILITY_CONNECTION_MANAGER} in that it is not allowed to manage
99      * or place calls from the built-in telephony stack.
100      * <p>
101      * See {@link #getCapabilities}
102      * <p>
103      */
104     public static final int CAPABILITY_CALL_PROVIDER = 0x2;
105
106     /**
107      * Flag indicating that this {@code PhoneAccount} represents a built-in PSTN SIM
108      * subscription.
109      * <p>
110      * Only the Android framework can register a {@code PhoneAccount} having this capability.
111      * <p>
112      * See {@link #getCapabilities}
113      */
114     public static final int CAPABILITY_SIM_SUBSCRIPTION = 0x4;
115
116     /**
117      * Flag indicating that this {@code PhoneAccount} is capable of placing video calls.
118      * <p>
119      * See {@link #getCapabilities}
120      */
121     public static final int CAPABILITY_VIDEO_CALLING = 0x8;
122
123     /**
124      * Flag indicating that this {@code PhoneAccount} is capable of placing emergency calls.
125      * By default all PSTN {@code PhoneAccount}s are capable of placing emergency calls.
126      * <p>
127      * See {@link #getCapabilities}
128      */
129     public static final int CAPABILITY_PLACE_EMERGENCY_CALLS = 0x10;
130
131     /**
132      * Flag indicating that this {@code PhoneAccount} is capable of being used by all users. This
133      * should only be used by system apps (and will be ignored for all other apps trying to use it).
134      * <p>
135      * See {@link #getCapabilities}
136      * @hide
137      */
138     @SystemApi
139     public static final int CAPABILITY_MULTI_USER = 0x20;
140
141     /**
142      * Flag indicating that this {@code PhoneAccount} supports a subject for Calls.  This means a
143      * caller is able to specify a short subject line for an outgoing call.  A capable receiving
144      * device displays the call subject on the incoming call screen.
145      * <p>
146      * See {@link #getCapabilities}
147      */
148     public static final int CAPABILITY_CALL_SUBJECT = 0x40;
149
150     /**
151      * Flag indicating that this {@code PhoneAccount} should only be used for emergency calls.
152      * <p>
153      * See {@link #getCapabilities}
154      * @hide
155      */
156     public static final int CAPABILITY_EMERGENCY_CALLS_ONLY = 0x80;
157
158     /**
159      * Flag indicating that for this {@code PhoneAccount}, the ability to make a video call to a
160      * number relies on presence.  Should only be set if the {@code PhoneAccount} also has
161      * {@link #CAPABILITY_VIDEO_CALLING}.
162      * <p>
163      * When set, the {@link ConnectionService} is responsible for toggling the
164      * {@link android.provider.ContactsContract.Data#CARRIER_PRESENCE_VT_CAPABLE} bit on the
165      * {@link android.provider.ContactsContract.Data#CARRIER_PRESENCE} column to indicate whether
166      * a contact's phone number supports video calling.
167      * <p>
168      * See {@link #getCapabilities}
169      */
170     public static final int CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE = 0x100;
171
172     /**
173      * Flag indicating that for this {@link PhoneAccount}, emergency video calling is allowed.
174      * <p>
175      * When set, Telecom will allow emergency video calls to be placed.  When not set, Telecom will
176      * convert all outgoing video calls to emergency numbers to audio-only.
177      * @hide
178      */
179     public static final int CAPABILITY_EMERGENCY_VIDEO_CALLING = 0x200;
180
181     /**
182      * URI scheme for telephone number URIs.
183      */
184     public static final String SCHEME_TEL = "tel";
185
186     /**
187      * URI scheme for voicemail URIs.
188      */
189     public static final String SCHEME_VOICEMAIL = "voicemail";
190
191     /**
192      * URI scheme for SIP URIs.
193      */
194     public static final String SCHEME_SIP = "sip";
195
196     /**
197      * Indicating no icon tint is set.
198      * @hide
199      */
200     public static final int NO_ICON_TINT = 0;
201
202     /**
203      * Indicating no hightlight color is set.
204      */
205     public static final int NO_HIGHLIGHT_COLOR = 0;
206
207     /**
208      * Indicating no resource ID is set.
209      */
210     public static final int NO_RESOURCE_ID = -1;
211
212     private final PhoneAccountHandle mAccountHandle;
213     private final Uri mAddress;
214     private final Uri mSubscriptionAddress;
215     private final int mCapabilities;
216     private final int mHighlightColor;
217     private final CharSequence mLabel;
218     private final CharSequence mShortDescription;
219     private final List<String> mSupportedUriSchemes;
220     private final Icon mIcon;
221     private final Bundle mExtras;
222     private boolean mIsEnabled;
223
224     /**
225      * Helper class for creating a {@link PhoneAccount}.
226      */
227     public static class Builder {
228         private PhoneAccountHandle mAccountHandle;
229         private Uri mAddress;
230         private Uri mSubscriptionAddress;
231         private int mCapabilities;
232         private int mHighlightColor = NO_HIGHLIGHT_COLOR;
233         private CharSequence mLabel;
234         private CharSequence mShortDescription;
235         private List<String> mSupportedUriSchemes = new ArrayList<String>();
236         private Icon mIcon;
237         private Bundle mExtras;
238         private boolean mIsEnabled = false;
239
240         /**
241          * Creates a builder with the specified {@link PhoneAccountHandle} and label.
242          */
243         public Builder(PhoneAccountHandle accountHandle, CharSequence label) {
244             this.mAccountHandle = accountHandle;
245             this.mLabel = label;
246         }
247
248         /**
249          * Creates an instance of the {@link PhoneAccount.Builder} from an existing
250          * {@link PhoneAccount}.
251          *
252          * @param phoneAccount The {@link PhoneAccount} used to initialize the builder.
253          */
254         public Builder(PhoneAccount phoneAccount) {
255             mAccountHandle = phoneAccount.getAccountHandle();
256             mAddress = phoneAccount.getAddress();
257             mSubscriptionAddress = phoneAccount.getSubscriptionAddress();
258             mCapabilities = phoneAccount.getCapabilities();
259             mHighlightColor = phoneAccount.getHighlightColor();
260             mLabel = phoneAccount.getLabel();
261             mShortDescription = phoneAccount.getShortDescription();
262             mSupportedUriSchemes.addAll(phoneAccount.getSupportedUriSchemes());
263             mIcon = phoneAccount.getIcon();
264             mIsEnabled = phoneAccount.isEnabled();
265             mExtras = phoneAccount.getExtras();
266         }
267
268         /**
269          * Sets the address. See {@link PhoneAccount#getAddress}.
270          *
271          * @param value The address of the phone account.
272          * @return The builder.
273          */
274         public Builder setAddress(Uri value) {
275             this.mAddress = value;
276             return this;
277         }
278
279         /**
280          * Sets the subscription address. See {@link PhoneAccount#getSubscriptionAddress}.
281          *
282          * @param value The subscription address.
283          * @return The builder.
284          */
285         public Builder setSubscriptionAddress(Uri value) {
286             this.mSubscriptionAddress = value;
287             return this;
288         }
289
290         /**
291          * Sets the capabilities. See {@link PhoneAccount#getCapabilities}.
292          *
293          * @param value The capabilities to set.
294          * @return The builder.
295          */
296         public Builder setCapabilities(int value) {
297             this.mCapabilities = value;
298             return this;
299         }
300
301         /**
302          * Sets the icon. See {@link PhoneAccount#getIcon}.
303          *
304          * @param icon The icon to set.
305          */
306         public Builder setIcon(Icon icon) {
307             mIcon = icon;
308             return this;
309         }
310
311         /**
312          * Sets the highlight color. See {@link PhoneAccount#getHighlightColor}.
313          *
314          * @param value The highlight color.
315          * @return The builder.
316          */
317         public Builder setHighlightColor(int value) {
318             this.mHighlightColor = value;
319             return this;
320         }
321
322         /**
323          * Sets the short description. See {@link PhoneAccount#getShortDescription}.
324          *
325          * @param value The short description.
326          * @return The builder.
327          */
328         public Builder setShortDescription(CharSequence value) {
329             this.mShortDescription = value;
330             return this;
331         }
332
333         /**
334          * Specifies an additional URI scheme supported by the {@link PhoneAccount}.
335          *
336          * @param uriScheme The URI scheme.
337          * @return The builder.
338          */
339         public Builder addSupportedUriScheme(String uriScheme) {
340             if (!TextUtils.isEmpty(uriScheme) && !mSupportedUriSchemes.contains(uriScheme)) {
341                 this.mSupportedUriSchemes.add(uriScheme);
342             }
343             return this;
344         }
345
346         /**
347          * Specifies the URI schemes supported by the {@link PhoneAccount}.
348          *
349          * @param uriSchemes The URI schemes.
350          * @return The builder.
351          */
352         public Builder setSupportedUriSchemes(List<String> uriSchemes) {
353             mSupportedUriSchemes.clear();
354
355             if (uriSchemes != null && !uriSchemes.isEmpty()) {
356                 for (String uriScheme : uriSchemes) {
357                     addSupportedUriScheme(uriScheme);
358                 }
359             }
360             return this;
361         }
362
363         /**
364          * Specifies the extras associated with the {@link PhoneAccount}.
365          * <p>
366          * {@code PhoneAccount}s only support extra values of type: {@link String}, {@link Integer},
367          * and {@link Boolean}.  Extras which are not of these types are ignored.
368          *
369          * @param extras
370          * @return
371          */
372         public Builder setExtras(Bundle extras) {
373             mExtras = extras;
374             return this;
375         }
376
377         /**
378          * Sets the enabled state of the phone account.
379          *
380          * @param isEnabled The enabled state.
381          * @return The builder.
382          * @hide
383          */
384         public Builder setIsEnabled(boolean isEnabled) {
385             mIsEnabled = isEnabled;
386             return this;
387         }
388
389         /**
390          * Creates an instance of a {@link PhoneAccount} based on the current builder settings.
391          *
392          * @return The {@link PhoneAccount}.
393          */
394         public PhoneAccount build() {
395             // If no supported URI schemes were defined, assume "tel" is supported.
396             if (mSupportedUriSchemes.isEmpty()) {
397                 addSupportedUriScheme(SCHEME_TEL);
398             }
399
400             return new PhoneAccount(
401                     mAccountHandle,
402                     mAddress,
403                     mSubscriptionAddress,
404                     mCapabilities,
405                     mIcon,
406                     mHighlightColor,
407                     mLabel,
408                     mShortDescription,
409                     mSupportedUriSchemes,
410                     mExtras,
411                     mIsEnabled);
412         }
413     }
414
415     private PhoneAccount(
416             PhoneAccountHandle account,
417             Uri address,
418             Uri subscriptionAddress,
419             int capabilities,
420             Icon icon,
421             int highlightColor,
422             CharSequence label,
423             CharSequence shortDescription,
424             List<String> supportedUriSchemes,
425             Bundle extras,
426             boolean isEnabled) {
427         mAccountHandle = account;
428         mAddress = address;
429         mSubscriptionAddress = subscriptionAddress;
430         mCapabilities = capabilities;
431         mIcon = icon;
432         mHighlightColor = highlightColor;
433         mLabel = label;
434         mShortDescription = shortDescription;
435         mSupportedUriSchemes = Collections.unmodifiableList(supportedUriSchemes);
436         mExtras = extras;
437         mIsEnabled = isEnabled;
438     }
439
440     public static Builder builder(
441             PhoneAccountHandle accountHandle,
442             CharSequence label) {
443         return new Builder(accountHandle, label);
444     }
445
446     /**
447      * Returns a builder initialized with the current {@link PhoneAccount} instance.
448      *
449      * @return The builder.
450      */
451     public Builder toBuilder() { return new Builder(this); }
452
453     /**
454      * The unique identifier of this {@code PhoneAccount}.
455      *
456      * @return A {@code PhoneAccountHandle}.
457      */
458     public PhoneAccountHandle getAccountHandle() {
459         return mAccountHandle;
460     }
461
462     /**
463      * The address (e.g., a phone number) associated with this {@code PhoneAccount}. This
464      * represents the destination from which outgoing calls using this {@code PhoneAccount}
465      * will appear to come, if applicable, and the destination to which incoming calls using this
466      * {@code PhoneAccount} may be addressed.
467      *
468      * @return A address expressed as a {@code Uri}, for example, a phone number.
469      */
470     public Uri getAddress() {
471         return mAddress;
472     }
473
474     /**
475      * The raw callback number used for this {@code PhoneAccount}, as distinct from
476      * {@link #getAddress()}. For the majority of {@code PhoneAccount}s this should be registered
477      * as {@code null}.  It is used by the system for SIM-based {@code PhoneAccount} registration
478      * where {@link android.telephony.TelephonyManager#setLine1NumberForDisplay(String, String)}
479      * has been used to alter the callback number.
480      * <p>
481      *
482      * @return The subscription number, suitable for display to the user.
483      */
484     public Uri getSubscriptionAddress() {
485         return mSubscriptionAddress;
486     }
487
488     /**
489      * The capabilities of this {@code PhoneAccount}.
490      *
491      * @return A bit field of flags describing this {@code PhoneAccount}'s capabilities.
492      */
493     public int getCapabilities() {
494         return mCapabilities;
495     }
496
497     /**
498      * Determines if this {@code PhoneAccount} has a capabilities specified by the passed in
499      * bit mask.
500      *
501      * @param capability The capabilities to check.
502      * @return {@code true} if the phone account has the capability.
503      */
504     public boolean hasCapabilities(int capability) {
505         return (mCapabilities & capability) == capability;
506     }
507
508     /**
509      * A short label describing a {@code PhoneAccount}.
510      *
511      * @return A label for this {@code PhoneAccount}.
512      */
513     public CharSequence getLabel() {
514         return mLabel;
515     }
516
517     /**
518      * A short paragraph describing this {@code PhoneAccount}.
519      *
520      * @return A description for this {@code PhoneAccount}.
521      */
522     public CharSequence getShortDescription() {
523         return mShortDescription;
524     }
525
526     /**
527      * The URI schemes supported by this {@code PhoneAccount}.
528      *
529      * @return The URI schemes.
530      */
531     public List<String> getSupportedUriSchemes() {
532         return mSupportedUriSchemes;
533     }
534
535     /**
536      * The extras associated with this {@code PhoneAccount}.
537      * <p>
538      * A {@link ConnectionService} may provide implementation specific information about the
539      * {@link PhoneAccount} via the extras.
540      *
541      * @return The extras.
542      */
543     public Bundle getExtras() {
544         return mExtras;
545     }
546
547     /**
548      * The icon to represent this {@code PhoneAccount}.
549      *
550      * @return The icon.
551      */
552     public Icon getIcon() {
553         return mIcon;
554     }
555
556     /**
557      * Indicates whether the user has enabled this {@code PhoneAccount} or not. This value is only
558      * populated for {@code PhoneAccount}s returned by {@link TelecomManager#getPhoneAccount}.
559      *
560      * @return {@code true} if the account is enabled by the user, {@code false} otherwise.
561      */
562     public boolean isEnabled() {
563         return mIsEnabled;
564     }
565
566     /**
567      * Determines if the {@link PhoneAccount} supports calls to/from addresses with a specified URI
568      * scheme.
569      *
570      * @param uriScheme The URI scheme to check.
571      * @return {@code true} if the {@code PhoneAccount} supports calls to/from addresses with the
572      * specified URI scheme.
573      */
574     public boolean supportsUriScheme(String uriScheme) {
575         if (mSupportedUriSchemes == null || uriScheme == null) {
576             return false;
577         }
578
579         for (String scheme : mSupportedUriSchemes) {
580             if (scheme != null && scheme.equals(uriScheme)) {
581                 return true;
582             }
583         }
584         return false;
585     }
586
587     /**
588      * A highlight color to use in displaying information about this {@code PhoneAccount}.
589      *
590      * @return A hexadecimal color value.
591      */
592     public int getHighlightColor() {
593         return mHighlightColor;
594     }
595
596     /**
597      * Sets the enabled state of the phone account.
598      * @hide
599      */
600     public void setIsEnabled(boolean isEnabled) {
601         mIsEnabled = isEnabled;
602     }
603
604     //
605     // Parcelable implementation
606     //
607
608     @Override
609     public int describeContents() {
610         return 0;
611     }
612
613     @Override
614     public void writeToParcel(Parcel out, int flags) {
615         if (mAccountHandle == null) {
616             out.writeInt(0);
617         } else {
618             out.writeInt(1);
619             mAccountHandle.writeToParcel(out, flags);
620         }
621         if (mAddress == null) {
622             out.writeInt(0);
623         } else {
624             out.writeInt(1);
625             mAddress.writeToParcel(out, flags);
626         }
627         if (mSubscriptionAddress == null) {
628             out.writeInt(0);
629         } else {
630             out.writeInt(1);
631             mSubscriptionAddress.writeToParcel(out, flags);
632         }
633         out.writeInt(mCapabilities);
634         out.writeInt(mHighlightColor);
635         out.writeCharSequence(mLabel);
636         out.writeCharSequence(mShortDescription);
637         out.writeStringList(mSupportedUriSchemes);
638
639         if (mIcon == null) {
640             out.writeInt(0);
641         } else {
642             out.writeInt(1);
643             mIcon.writeToParcel(out, flags);
644         }
645         out.writeByte((byte) (mIsEnabled ? 1 : 0));
646         out.writeBundle(mExtras);
647     }
648
649     public static final Creator<PhoneAccount> CREATOR
650             = new Creator<PhoneAccount>() {
651         @Override
652         public PhoneAccount createFromParcel(Parcel in) {
653             return new PhoneAccount(in);
654         }
655
656         @Override
657         public PhoneAccount[] newArray(int size) {
658             return new PhoneAccount[size];
659         }
660     };
661
662     private PhoneAccount(Parcel in) {
663         if (in.readInt() > 0) {
664             mAccountHandle = PhoneAccountHandle.CREATOR.createFromParcel(in);
665         } else {
666             mAccountHandle = null;
667         }
668         if (in.readInt() > 0) {
669             mAddress = Uri.CREATOR.createFromParcel(in);
670         } else {
671             mAddress = null;
672         }
673         if (in.readInt() > 0) {
674             mSubscriptionAddress = Uri.CREATOR.createFromParcel(in);
675         } else {
676             mSubscriptionAddress = null;
677         }
678         mCapabilities = in.readInt();
679         mHighlightColor = in.readInt();
680         mLabel = in.readCharSequence();
681         mShortDescription = in.readCharSequence();
682         mSupportedUriSchemes = Collections.unmodifiableList(in.createStringArrayList());
683         if (in.readInt() > 0) {
684             mIcon = Icon.CREATOR.createFromParcel(in);
685         } else {
686             mIcon = null;
687         }
688         mIsEnabled = in.readByte() == 1;
689         mExtras = in.readBundle();
690     }
691
692     @Override
693     public String toString() {
694         StringBuilder sb = new StringBuilder().append("[[")
695                 .append(mIsEnabled ? 'X' : ' ')
696                 .append("] PhoneAccount: ")
697                 .append(mAccountHandle)
698                 .append(" Capabilities: ")
699                 .append(capabilitiesToString(mCapabilities))
700                 .append(" Schemes: ");
701         for (String scheme : mSupportedUriSchemes) {
702             sb.append(scheme)
703                     .append(" ");
704         }
705         sb.append(" Extras: ");
706         sb.append(mExtras);
707         sb.append("]");
708         return sb.toString();
709     }
710
711     /**
712      * Generates a string representation of a capabilities bitmask.
713      *
714      * @param capabilities The capabilities bitmask.
715      * @return String representation of the capabilities bitmask.
716      */
717     private String capabilitiesToString(int capabilities) {
718         StringBuilder sb = new StringBuilder();
719         if (hasCapabilities(CAPABILITY_VIDEO_CALLING)) {
720             sb.append("Video ");
721         }
722         if (hasCapabilities(CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE)) {
723             sb.append("Presence ");
724         }
725         if (hasCapabilities(CAPABILITY_CALL_PROVIDER)) {
726             sb.append("CallProvider ");
727         }
728         if (hasCapabilities(CAPABILITY_CALL_SUBJECT)) {
729             sb.append("CallSubject ");
730         }
731         if (hasCapabilities(CAPABILITY_CONNECTION_MANAGER)) {
732             sb.append("ConnectionMgr ");
733         }
734         if (hasCapabilities(CAPABILITY_EMERGENCY_CALLS_ONLY)) {
735             sb.append("EmergOnly ");
736         }
737         if (hasCapabilities(CAPABILITY_MULTI_USER)) {
738             sb.append("MultiUser ");
739         }
740         if (hasCapabilities(CAPABILITY_PLACE_EMERGENCY_CALLS)) {
741             sb.append("PlaceEmerg ");
742         }
743         if (hasCapabilities(CAPABILITY_EMERGENCY_VIDEO_CALLING)) {
744             sb.append("EmergVideo ");
745         }
746         if (hasCapabilities(CAPABILITY_SIM_SUBSCRIPTION)) {
747             sb.append("SimSub ");
748         }
749         return sb.toString();
750     }
751 }