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