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.Parcel;
32 import android.os.Parcelable;
33 import android.text.TextUtils;
34 
35 import java.lang.String;
36 import java.util.ArrayList;
37 import java.util.Collections;
38 import java.util.List;
39 import java.util.MissingResourceException;
40 
41 /**
42  * Represents a distinct method to place or receive a phone call. Apps which can place calls and
43  * want those calls to be integrated into the dialer and in-call UI should build an instance of
44  * this class and register it with the system using {@link TelecomManager}.
45  * <p>
46  * {@link TelecomManager} uses registered {@link PhoneAccount}s to present the user with
47  * alternative options when placing a phone call. When building a {@link PhoneAccount}, the app
48  * should supply a valid {@link PhoneAccountHandle} that references the connection service
49  * implementation Telecom will use to interact with the app.
50  */
51 public final class PhoneAccount implements Parcelable {
52 
53     /**
54      * Flag indicating that this {@code PhoneAccount} can act as a connection manager for
55      * other connections. The {@link ConnectionService} associated with this {@code PhoneAccount}
56      * will be allowed to manage phone calls including using its own proprietary phone-call
57      * implementation (like VoIP calling) to make calls instead of the telephony stack.
58      * <p>
59      * When a user opts to place a call using the SIM-based telephony stack, the
60      * {@link ConnectionService} associated with this {@code PhoneAccount} will be attempted first
61      * if the user has explicitly selected it to be used as the default connection manager.
62      * <p>
63      * See {@link #getCapabilities}
64      */
65     public static final int CAPABILITY_CONNECTION_MANAGER = 0x1;
66 
67     /**
68      * Flag indicating that this {@code PhoneAccount} can make phone calls in place of
69      * traditional SIM-based telephony calls. This account will be treated as a distinct method
70      * for placing calls alongside the traditional SIM-based telephony stack. This flag is
71      * distinct from {@link #CAPABILITY_CONNECTION_MANAGER} in that it is not allowed to manage
72      * or place calls from the built-in telephony stack.
73      * <p>
74      * See {@link #getCapabilities}
75      * <p>
76      */
77     public static final int CAPABILITY_CALL_PROVIDER = 0x2;
78 
79     /**
80      * Flag indicating that this {@code PhoneAccount} represents a built-in PSTN SIM
81      * subscription.
82      * <p>
83      * Only the Android framework can register a {@code PhoneAccount} having this capability.
84      * <p>
85      * See {@link #getCapabilities}
86      */
87     public static final int CAPABILITY_SIM_SUBSCRIPTION = 0x4;
88 
89     /**
90      * Flag indicating that this {@code PhoneAccount} is capable of placing video calls.
91      * <p>
92      * See {@link #getCapabilities}
93      */
94     public static final int CAPABILITY_VIDEO_CALLING = 0x8;
95 
96     /**
97      * Flag indicating that this {@code PhoneAccount} is capable of placing emergency calls.
98      * By default all PSTN {@code PhoneAccount}s are capable of placing emergency calls.
99      * <p>
100      * See {@link #getCapabilities}
101      */
102     public static final int CAPABILITY_PLACE_EMERGENCY_CALLS = 0x10;
103 
104     /**
105      * Flag indicating that this {@code PhoneAccount} is capable of being used by all users. This
106      * should only be used by system apps (and will be ignored for all other apps trying to use it).
107      * <p>
108      * See {@link #getCapabilities}
109      * @hide
110      */
111     @SystemApi
112     public static final int CAPABILITY_MULTI_USER = 0x20;
113 
114     /**
115      * Flag indicating that this {@code PhoneAccount} supports a subject for Calls.  This means a
116      * caller is able to specify a short subject line for an outgoing call.  A capable receiving
117      * device displays the call subject on the incoming call screen.
118      * <p>
119      * See {@link #getCapabilities}
120      */
121     public static final int CAPABILITY_CALL_SUBJECT = 0x40;
122 
123     /**
124      * URI scheme for telephone number URIs.
125      */
126     public static final String SCHEME_TEL = "tel";
127 
128     /**
129      * URI scheme for voicemail URIs.
130      */
131     public static final String SCHEME_VOICEMAIL = "voicemail";
132 
133     /**
134      * URI scheme for SIP URIs.
135      */
136     public static final String SCHEME_SIP = "sip";
137 
138     /**
139      * Indicating no icon tint is set.
140      * @hide
141      */
142     public static final int NO_ICON_TINT = 0;
143 
144     /**
145      * Indicating no hightlight color is set.
146      */
147     public static final int NO_HIGHLIGHT_COLOR = 0;
148 
149     /**
150      * Indicating no resource ID is set.
151      */
152     public static final int NO_RESOURCE_ID = -1;
153 
154     private final PhoneAccountHandle mAccountHandle;
155     private final Uri mAddress;
156     private final Uri mSubscriptionAddress;
157     private final int mCapabilities;
158     private final int mHighlightColor;
159     private final CharSequence mLabel;
160     private final CharSequence mShortDescription;
161     private final List<String> mSupportedUriSchemes;
162     private final Icon mIcon;
163     private boolean mIsEnabled;
164 
165     /**
166      * Helper class for creating a {@link PhoneAccount}.
167      */
168     public static class Builder {
169         private PhoneAccountHandle mAccountHandle;
170         private Uri mAddress;
171         private Uri mSubscriptionAddress;
172         private int mCapabilities;
173         private int mHighlightColor = NO_HIGHLIGHT_COLOR;
174         private CharSequence mLabel;
175         private CharSequence mShortDescription;
176         private List<String> mSupportedUriSchemes = new ArrayList<String>();
177         private Icon mIcon;
178         private boolean mIsEnabled = false;
179 
180         /**
181          * Creates a builder with the specified {@link PhoneAccountHandle} and label.
182          */
Builder(PhoneAccountHandle accountHandle, CharSequence label)183         public Builder(PhoneAccountHandle accountHandle, CharSequence label) {
184             this.mAccountHandle = accountHandle;
185             this.mLabel = label;
186         }
187 
188         /**
189          * Creates an instance of the {@link PhoneAccount.Builder} from an existing
190          * {@link PhoneAccount}.
191          *
192          * @param phoneAccount The {@link PhoneAccount} used to initialize the builder.
193          */
Builder(PhoneAccount phoneAccount)194         public Builder(PhoneAccount phoneAccount) {
195             mAccountHandle = phoneAccount.getAccountHandle();
196             mAddress = phoneAccount.getAddress();
197             mSubscriptionAddress = phoneAccount.getSubscriptionAddress();
198             mCapabilities = phoneAccount.getCapabilities();
199             mHighlightColor = phoneAccount.getHighlightColor();
200             mLabel = phoneAccount.getLabel();
201             mShortDescription = phoneAccount.getShortDescription();
202             mSupportedUriSchemes.addAll(phoneAccount.getSupportedUriSchemes());
203             mIcon = phoneAccount.getIcon();
204             mIsEnabled = phoneAccount.isEnabled();
205         }
206 
207         /**
208          * Sets the address. See {@link PhoneAccount#getAddress}.
209          *
210          * @param value The address of the phone account.
211          * @return The builder.
212          */
setAddress(Uri value)213         public Builder setAddress(Uri value) {
214             this.mAddress = value;
215             return this;
216         }
217 
218         /**
219          * Sets the subscription address. See {@link PhoneAccount#getSubscriptionAddress}.
220          *
221          * @param value The subscription address.
222          * @return The builder.
223          */
setSubscriptionAddress(Uri value)224         public Builder setSubscriptionAddress(Uri value) {
225             this.mSubscriptionAddress = value;
226             return this;
227         }
228 
229         /**
230          * Sets the capabilities. See {@link PhoneAccount#getCapabilities}.
231          *
232          * @param value The capabilities to set.
233          * @return The builder.
234          */
setCapabilities(int value)235         public Builder setCapabilities(int value) {
236             this.mCapabilities = value;
237             return this;
238         }
239 
240         /**
241          * Sets the icon. See {@link PhoneAccount#getIcon}.
242          *
243          * @param icon The icon to set.
244          */
setIcon(Icon icon)245         public Builder setIcon(Icon icon) {
246             mIcon = icon;
247             return this;
248         }
249 
250         /**
251          * Sets the highlight color. See {@link PhoneAccount#getHighlightColor}.
252          *
253          * @param value The highlight color.
254          * @return The builder.
255          */
setHighlightColor(int value)256         public Builder setHighlightColor(int value) {
257             this.mHighlightColor = value;
258             return this;
259         }
260 
261         /**
262          * Sets the short description. See {@link PhoneAccount#getShortDescription}.
263          *
264          * @param value The short description.
265          * @return The builder.
266          */
setShortDescription(CharSequence value)267         public Builder setShortDescription(CharSequence value) {
268             this.mShortDescription = value;
269             return this;
270         }
271 
272         /**
273          * Specifies an additional URI scheme supported by the {@link PhoneAccount}.
274          *
275          * @param uriScheme The URI scheme.
276          * @return The builder.
277          */
addSupportedUriScheme(String uriScheme)278         public Builder addSupportedUriScheme(String uriScheme) {
279             if (!TextUtils.isEmpty(uriScheme) && !mSupportedUriSchemes.contains(uriScheme)) {
280                 this.mSupportedUriSchemes.add(uriScheme);
281             }
282             return this;
283         }
284 
285         /**
286          * Specifies the URI schemes supported by the {@link PhoneAccount}.
287          *
288          * @param uriSchemes The URI schemes.
289          * @return The builder.
290          */
setSupportedUriSchemes(List<String> uriSchemes)291         public Builder setSupportedUriSchemes(List<String> uriSchemes) {
292             mSupportedUriSchemes.clear();
293 
294             if (uriSchemes != null && !uriSchemes.isEmpty()) {
295                 for (String uriScheme : uriSchemes) {
296                     addSupportedUriScheme(uriScheme);
297                 }
298             }
299             return this;
300         }
301 
302         /**
303          * Sets the enabled state of the phone account.
304          *
305          * @param isEnabled The enabled state.
306          * @return The builder.
307          * @hide
308          */
setIsEnabled(boolean isEnabled)309         public Builder setIsEnabled(boolean isEnabled) {
310             mIsEnabled = isEnabled;
311             return this;
312         }
313 
314         /**
315          * Creates an instance of a {@link PhoneAccount} based on the current builder settings.
316          *
317          * @return The {@link PhoneAccount}.
318          */
build()319         public PhoneAccount build() {
320             // If no supported URI schemes were defined, assume "tel" is supported.
321             if (mSupportedUriSchemes.isEmpty()) {
322                 addSupportedUriScheme(SCHEME_TEL);
323             }
324 
325             return new PhoneAccount(
326                     mAccountHandle,
327                     mAddress,
328                     mSubscriptionAddress,
329                     mCapabilities,
330                     mIcon,
331                     mHighlightColor,
332                     mLabel,
333                     mShortDescription,
334                     mSupportedUriSchemes,
335                     mIsEnabled);
336         }
337     }
338 
PhoneAccount( PhoneAccountHandle account, Uri address, Uri subscriptionAddress, int capabilities, Icon icon, int highlightColor, CharSequence label, CharSequence shortDescription, List<String> supportedUriSchemes, boolean isEnabled)339     private PhoneAccount(
340             PhoneAccountHandle account,
341             Uri address,
342             Uri subscriptionAddress,
343             int capabilities,
344             Icon icon,
345             int highlightColor,
346             CharSequence label,
347             CharSequence shortDescription,
348             List<String> supportedUriSchemes,
349             boolean isEnabled) {
350         mAccountHandle = account;
351         mAddress = address;
352         mSubscriptionAddress = subscriptionAddress;
353         mCapabilities = capabilities;
354         mIcon = icon;
355         mHighlightColor = highlightColor;
356         mLabel = label;
357         mShortDescription = shortDescription;
358         mSupportedUriSchemes = Collections.unmodifiableList(supportedUriSchemes);
359         mIsEnabled = isEnabled;
360     }
361 
builder( PhoneAccountHandle accountHandle, CharSequence label)362     public static Builder builder(
363             PhoneAccountHandle accountHandle,
364             CharSequence label) {
365         return new Builder(accountHandle, label);
366     }
367 
368     /**
369      * Returns a builder initialized with the current {@link PhoneAccount} instance.
370      *
371      * @return The builder.
372      */
toBuilder()373     public Builder toBuilder() { return new Builder(this); }
374 
375     /**
376      * The unique identifier of this {@code PhoneAccount}.
377      *
378      * @return A {@code PhoneAccountHandle}.
379      */
getAccountHandle()380     public PhoneAccountHandle getAccountHandle() {
381         return mAccountHandle;
382     }
383 
384     /**
385      * The address (e.g., a phone number) associated with this {@code PhoneAccount}. This
386      * represents the destination from which outgoing calls using this {@code PhoneAccount}
387      * will appear to come, if applicable, and the destination to which incoming calls using this
388      * {@code PhoneAccount} may be addressed.
389      *
390      * @return A address expressed as a {@code Uri}, for example, a phone number.
391      */
getAddress()392     public Uri getAddress() {
393         return mAddress;
394     }
395 
396     /**
397      * The raw callback number used for this {@code PhoneAccount}, as distinct from
398      * {@link #getAddress()}. For the majority of {@code PhoneAccount}s this should be registered
399      * as {@code null}.  It is used by the system for SIM-based {@code PhoneAccount} registration
400      * where {@link android.telephony.TelephonyManager#setLine1NumberForDisplay(String, String)}
401      * has been used to alter the callback number.
402      * <p>
403      *
404      * @return The subscription number, suitable for display to the user.
405      */
getSubscriptionAddress()406     public Uri getSubscriptionAddress() {
407         return mSubscriptionAddress;
408     }
409 
410     /**
411      * The capabilities of this {@code PhoneAccount}.
412      *
413      * @return A bit field of flags describing this {@code PhoneAccount}'s capabilities.
414      */
getCapabilities()415     public int getCapabilities() {
416         return mCapabilities;
417     }
418 
419     /**
420      * Determines if this {@code PhoneAccount} has a capabilities specified by the passed in
421      * bit mask.
422      *
423      * @param capability The capabilities to check.
424      * @return {@code true} if the phone account has the capability.
425      */
hasCapabilities(int capability)426     public boolean hasCapabilities(int capability) {
427         return (mCapabilities & capability) == capability;
428     }
429 
430     /**
431      * A short label describing a {@code PhoneAccount}.
432      *
433      * @return A label for this {@code PhoneAccount}.
434      */
getLabel()435     public CharSequence getLabel() {
436         return mLabel;
437     }
438 
439     /**
440      * A short paragraph describing this {@code PhoneAccount}.
441      *
442      * @return A description for this {@code PhoneAccount}.
443      */
getShortDescription()444     public CharSequence getShortDescription() {
445         return mShortDescription;
446     }
447 
448     /**
449      * The URI schemes supported by this {@code PhoneAccount}.
450      *
451      * @return The URI schemes.
452      */
getSupportedUriSchemes()453     public List<String> getSupportedUriSchemes() {
454         return mSupportedUriSchemes;
455     }
456 
457     /**
458      * The icon to represent this {@code PhoneAccount}.
459      *
460      * @return The icon.
461      */
getIcon()462     public Icon getIcon() {
463         return mIcon;
464     }
465 
466     /**
467      * Indicates whether the user has enabled this {@code PhoneAccount} or not. This value is only
468      * populated for {@code PhoneAccount}s returned by {@link TelecomManager#getPhoneAccount}.
469      *
470      * @return {@code true} if the account is enabled by the user, {@code false} otherwise.
471      */
isEnabled()472     public boolean isEnabled() {
473         return mIsEnabled;
474     }
475 
476     /**
477      * Determines if the {@link PhoneAccount} supports calls to/from addresses with a specified URI
478      * scheme.
479      *
480      * @param uriScheme The URI scheme to check.
481      * @return {@code true} if the {@code PhoneAccount} supports calls to/from addresses with the
482      * specified URI scheme.
483      */
supportsUriScheme(String uriScheme)484     public boolean supportsUriScheme(String uriScheme) {
485         if (mSupportedUriSchemes == null || uriScheme == null) {
486             return false;
487         }
488 
489         for (String scheme : mSupportedUriSchemes) {
490             if (scheme != null && scheme.equals(uriScheme)) {
491                 return true;
492             }
493         }
494         return false;
495     }
496 
497     /**
498      * A highlight color to use in displaying information about this {@code PhoneAccount}.
499      *
500      * @return A hexadecimal color value.
501      */
getHighlightColor()502     public int getHighlightColor() {
503         return mHighlightColor;
504     }
505 
506     /**
507      * Sets the enabled state of the phone account.
508      * @hide
509      */
setIsEnabled(boolean isEnabled)510     public void setIsEnabled(boolean isEnabled) {
511         mIsEnabled = isEnabled;
512     }
513 
514     //
515     // Parcelable implementation
516     //
517 
518     @Override
describeContents()519     public int describeContents() {
520         return 0;
521     }
522 
523     @Override
writeToParcel(Parcel out, int flags)524     public void writeToParcel(Parcel out, int flags) {
525         if (mAccountHandle == null) {
526             out.writeInt(0);
527         } else {
528             out.writeInt(1);
529             mAccountHandle.writeToParcel(out, flags);
530         }
531         if (mAddress == null) {
532             out.writeInt(0);
533         } else {
534             out.writeInt(1);
535             mAddress.writeToParcel(out, flags);
536         }
537         if (mSubscriptionAddress == null) {
538             out.writeInt(0);
539         } else {
540             out.writeInt(1);
541             mSubscriptionAddress.writeToParcel(out, flags);
542         }
543         out.writeInt(mCapabilities);
544         out.writeInt(mHighlightColor);
545         out.writeCharSequence(mLabel);
546         out.writeCharSequence(mShortDescription);
547         out.writeStringList(mSupportedUriSchemes);
548 
549         if (mIcon == null) {
550             out.writeInt(0);
551         } else {
552             out.writeInt(1);
553             mIcon.writeToParcel(out, flags);
554         }
555         out.writeByte((byte) (mIsEnabled ? 1 : 0));
556     }
557 
558     public static final Creator<PhoneAccount> CREATOR
559             = new Creator<PhoneAccount>() {
560         @Override
561         public PhoneAccount createFromParcel(Parcel in) {
562             return new PhoneAccount(in);
563         }
564 
565         @Override
566         public PhoneAccount[] newArray(int size) {
567             return new PhoneAccount[size];
568         }
569     };
570 
PhoneAccount(Parcel in)571     private PhoneAccount(Parcel in) {
572         if (in.readInt() > 0) {
573             mAccountHandle = PhoneAccountHandle.CREATOR.createFromParcel(in);
574         } else {
575             mAccountHandle = null;
576         }
577         if (in.readInt() > 0) {
578             mAddress = Uri.CREATOR.createFromParcel(in);
579         } else {
580             mAddress = null;
581         }
582         if (in.readInt() > 0) {
583             mSubscriptionAddress = Uri.CREATOR.createFromParcel(in);
584         } else {
585             mSubscriptionAddress = null;
586         }
587         mCapabilities = in.readInt();
588         mHighlightColor = in.readInt();
589         mLabel = in.readCharSequence();
590         mShortDescription = in.readCharSequence();
591         mSupportedUriSchemes = Collections.unmodifiableList(in.createStringArrayList());
592         if (in.readInt() > 0) {
593             mIcon = Icon.CREATOR.createFromParcel(in);
594         } else {
595             mIcon = null;
596         }
597         mIsEnabled = in.readByte() == 1;
598     }
599 
600     @Override
toString()601     public String toString() {
602         StringBuilder sb = new StringBuilder().append("[[")
603                 .append(mIsEnabled ? 'X' : ' ')
604                 .append("] PhoneAccount: ")
605                 .append(mAccountHandle)
606                 .append(" Capabilities: ")
607                 .append(mCapabilities)
608                 .append(" Schemes: ");
609         for (String scheme : mSupportedUriSchemes) {
610             sb.append(scheme)
611                     .append(" ");
612         }
613         sb.append("]");
614         return sb.toString();
615     }
616 }
617