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