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