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