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