PhoneAccount.java revision 9016ecab3be175dace3e1ad3e1c8558fef1a4720
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.content.Context;
20import android.content.pm.PackageManager;
21import android.content.res.Resources.NotFoundException;
22import android.graphics.drawable.Drawable;
23import android.net.Uri;
24import android.os.Parcel;
25import android.os.Parcelable;
26import android.text.TextUtils;
27
28import java.lang.String;
29import java.util.ArrayList;
30import java.util.Collections;
31import java.util.List;
32import java.util.MissingResourceException;
33
34/**
35 * Describes a distinct account, line of service or call placement method that the system
36 * can use to place phone calls.
37 */
38public class PhoneAccount implements Parcelable {
39
40    /**
41     * Flag indicating that this {@code PhoneAccount} can act as a connection manager for
42     * other connections. The {@link ConnectionService} associated with this {@code PhoneAccount}
43     * will be allowed to manage phone calls including using its own proprietary phone-call
44     * implementation (like VoIP calling) to make calls instead of the telephony stack.
45     * <p>
46     * When a user opts to place a call using the SIM-based telephony stack, the
47     * {@link ConnectionService} associated with this {@code PhoneAccount} will be attempted first
48     * if the user has explicitly selected it to be used as the default connection manager.
49     * <p>
50     * See {@link #getCapabilities}
51     */
52    public static final int CAPABILITY_CONNECTION_MANAGER = 0x1;
53
54    /**
55     * Flag indicating that this {@code PhoneAccount} can make phone calls in place of
56     * traditional SIM-based telephony calls. This account will be treated as a distinct method
57     * for placing calls alongside the traditional SIM-based telephony stack. This flag is
58     * distinct from {@link #CAPABILITY_CONNECTION_MANAGER} in that it is not allowed to manage
59     * calls from or use the built-in telephony stack to place its calls.
60     * <p>
61     * See {@link #getCapabilities}
62     * <p>
63     * {@hide}
64     */
65    public static final int CAPABILITY_CALL_PROVIDER = 0x2;
66
67    /**
68     * Flag indicating that this {@code PhoneAccount} represents a built-in PSTN SIM
69     * subscription.
70     * <p>
71     * Only the Android framework can register a {@code PhoneAccount} having this capability.
72     * <p>
73     * See {@link #getCapabilities}
74     */
75    public static final int CAPABILITY_SIM_SUBSCRIPTION = 0x4;
76
77    /**
78     * Flag indicating that this {@code PhoneAccount} is capable of placing video calls.
79     * <p>
80     * See {@link #getCapabilities}
81     * @hide
82     */
83    public static final int CAPABILITY_VIDEO_CALLING = 0x8;
84
85    /**
86     * Flag indicating that this {@code PhoneAccount} is capable of placing emergency calls.
87     * By default all PSTN {@code PhoneAccount}s are capable of placing emergency calls.
88     * <p>
89     * See {@link #getCapabilities}
90     */
91    public static final int CAPABILITY_PLACE_EMERGENCY_CALLS = 0x10;
92
93    /**
94     * URI scheme for telephone number URIs.
95     */
96    public static final String SCHEME_TEL = "tel";
97
98    /**
99     * URI scheme for voicemail URIs.
100     */
101    public static final String SCHEME_VOICEMAIL = "voicemail";
102
103    /**
104     * URI scheme for SIP URIs.
105     */
106    public static final String SCHEME_SIP = "sip";
107
108    /**
109     * Indicating no color is set.
110     */
111    public static final int NO_COLOR = -1;
112
113    private final PhoneAccountHandle mAccountHandle;
114    private final Uri mAddress;
115    private final Uri mSubscriptionAddress;
116    private final int mCapabilities;
117    private final int mIconResId;
118    private final int mColor;
119    private final CharSequence mLabel;
120    private final CharSequence mShortDescription;
121    private final List<String> mSupportedUriSchemes;
122
123    public static class Builder {
124        private PhoneAccountHandle mAccountHandle;
125        private Uri mAddress;
126        private Uri mSubscriptionAddress;
127        private int mCapabilities;
128        private int mIconResId;
129        private int mColor = NO_COLOR;
130        private CharSequence mLabel;
131        private CharSequence mShortDescription;
132        private List<String> mSupportedUriSchemes = new ArrayList<String>();
133
134        public Builder(PhoneAccountHandle accountHandle, CharSequence label) {
135            this.mAccountHandle = accountHandle;
136            this.mLabel = label;
137        }
138
139        /**
140         * Creates an instance of the {@link PhoneAccount.Builder} from an existing
141         * {@link PhoneAccount}.
142         *
143         * @param phoneAccount The {@link PhoneAccount} used to initialize the builder.
144         */
145        public Builder(PhoneAccount phoneAccount) {
146            mAccountHandle = phoneAccount.getAccountHandle();
147            mAddress = phoneAccount.getAddress();
148            mSubscriptionAddress = phoneAccount.getSubscriptionAddress();
149            mCapabilities = phoneAccount.getCapabilities();
150            mIconResId = phoneAccount.getIconResId();
151            mColor = phoneAccount.getColor();
152            mLabel = phoneAccount.getLabel();
153            mShortDescription = phoneAccount.getShortDescription();
154            mSupportedUriSchemes.addAll(phoneAccount.getSupportedUriSchemes());
155        }
156
157        public Builder setAddress(Uri value) {
158            this.mAddress = value;
159            return this;
160        }
161
162        public Builder setSubscriptionAddress(Uri value) {
163            this.mSubscriptionAddress = value;
164            return this;
165        }
166
167        public Builder setCapabilities(int value) {
168            this.mCapabilities = value;
169            return this;
170        }
171
172        public Builder setIconResId(int value) {
173            this.mIconResId = value;
174            return this;
175        }
176
177        public Builder setColor(int value) {
178            this.mColor = value;
179            return this;
180        }
181
182        public Builder setShortDescription(CharSequence value) {
183            this.mShortDescription = value;
184            return this;
185        }
186
187        /**
188         * Specifies an additional URI scheme supported by the {@link PhoneAccount}.
189         *
190         * @param uriScheme The URI scheme.
191         * @return The Builder.
192         * @hide
193         */
194        public Builder addSupportedUriScheme(String uriScheme) {
195            if (!TextUtils.isEmpty(uriScheme) && !mSupportedUriSchemes.contains(uriScheme)) {
196                this.mSupportedUriSchemes.add(uriScheme);
197            }
198            return this;
199        }
200
201        /**
202         * Specifies the URI schemes supported by the {@link PhoneAccount}.
203         *
204         * @param uriSchemes The URI schemes.
205         * @return The Builder.
206         */
207        public Builder setSupportedUriSchemes(List<String> uriSchemes) {
208            mSupportedUriSchemes.clear();
209
210            if (uriSchemes != null && !uriSchemes.isEmpty()) {
211                for (String uriScheme : uriSchemes) {
212                    addSupportedUriScheme(uriScheme);
213                }
214            }
215            return this;
216        }
217
218        /**
219         * Creates an instance of a {@link PhoneAccount} based on the current builder settings.
220         *
221         * @return The {@link PhoneAccount}.
222         */
223        public PhoneAccount build() {
224            // If no supported URI schemes were defined, assume "tel" is supported.
225            if (mSupportedUriSchemes.isEmpty()) {
226                addSupportedUriScheme(SCHEME_TEL);
227            }
228
229            return new PhoneAccount(
230                    mAccountHandle,
231                    mAddress,
232                    mSubscriptionAddress,
233                    mCapabilities,
234                    mIconResId,
235                    mColor,
236                    mLabel,
237                    mShortDescription,
238                    mSupportedUriSchemes);
239        }
240    }
241
242    private PhoneAccount(
243            PhoneAccountHandle account,
244            Uri address,
245            Uri subscriptionAddress,
246            int capabilities,
247            int iconResId,
248            int color,
249            CharSequence label,
250            CharSequence shortDescription,
251            List<String> supportedUriSchemes) {
252        mAccountHandle = account;
253        mAddress = address;
254        mSubscriptionAddress = subscriptionAddress;
255        mCapabilities = capabilities;
256        mIconResId = iconResId;
257        mColor = color;
258        mLabel = label;
259        mShortDescription = shortDescription;
260        mSupportedUriSchemes = Collections.unmodifiableList(supportedUriSchemes);
261    }
262
263    public static Builder builder(
264            PhoneAccountHandle accountHandle,
265            CharSequence label) {
266        return new Builder(accountHandle, label);
267    }
268
269    /**
270     * Returns a builder initialized with the current {@link PhoneAccount} instance.
271     *
272     * @return The builder.
273     * @hide
274     */
275    public Builder toBuilder() { return new Builder(this); }
276
277    /**
278     * The unique identifier of this {@code PhoneAccount}.
279     *
280     * @return A {@code PhoneAccountHandle}.
281     */
282    public PhoneAccountHandle getAccountHandle() {
283        return mAccountHandle;
284    }
285
286    /**
287     * The address (e.g., a phone number) associated with this {@code PhoneAccount}. This
288     * represents the destination from which outgoing calls using this {@code PhoneAccount}
289     * will appear to come, if applicable, and the destination to which incoming calls using this
290     * {@code PhoneAccount} may be addressed.
291     *
292     * @return A address expressed as a {@code Uri}, for example, a phone number.
293     */
294    public Uri getAddress() {
295        return mAddress;
296    }
297
298    /**
299     * The raw callback number used for this {@code PhoneAccount}, as distinct from
300     * {@link #getAddress()}. For the majority of {@code PhoneAccount}s this should be registered
301     * as {@code null}.  It is used by the system for SIM-based {@code PhoneAccount} registration
302     * where {@link android.telephony.TelephonyManager#setLine1NumberForDisplay(String, String)}
303     * has been used to alter the callback number.
304     * <p>
305     *
306     * @return The subscription number, suitable for display to the user.
307     */
308    public Uri getSubscriptionAddress() {
309        return mSubscriptionAddress;
310    }
311
312    /**
313     * The capabilities of this {@code PhoneAccount}.
314     *
315     * @return A bit field of flags describing this {@code PhoneAccount}'s capabilities.
316     */
317    public int getCapabilities() {
318        return mCapabilities;
319    }
320
321    /**
322     * Determines if this {@code PhoneAccount} has a capabilities specified by the passed in
323     * bit mask.
324     *
325     * @param capability The capabilities to check.
326     * @return {@code True} if the phone account has the capability.
327     */
328    public boolean hasCapabilities(int capability) {
329        return (mCapabilities & capability) == capability;
330    }
331
332    /**
333     * A short label describing a {@code PhoneAccount}.
334     *
335     * @return A label for this {@code PhoneAccount}.
336     */
337    public CharSequence getLabel() {
338        return mLabel;
339    }
340
341    /**
342     * A short paragraph describing this {@code PhoneAccount}.
343     *
344     * @return A description for this {@code PhoneAccount}.
345     */
346    public CharSequence getShortDescription() {
347        return mShortDescription;
348    }
349
350    /**
351     * The URI schemes supported by this {@code PhoneAccount}.
352     *
353     * @return The URI schemes.
354     */
355    public List<String> getSupportedUriSchemes() {
356        return mSupportedUriSchemes;
357    }
358
359    /**
360     * Determines if the {@link PhoneAccount} supports calls to/from addresses with a specified URI
361     * scheme.
362     *
363     * @param uriScheme The URI scheme to check.
364     * @return {@code True} if the {@code PhoneAccount} supports calls to/from addresses with the
365     * specified URI scheme.
366     */
367    public boolean supportsUriScheme(String uriScheme) {
368        if (mSupportedUriSchemes == null || uriScheme == null) {
369            return false;
370        }
371
372        for (String scheme : mSupportedUriSchemes) {
373            if (scheme != null && scheme.equals(uriScheme)) {
374                return true;
375            }
376        }
377        return false;
378    }
379
380    /**
381     * The icon resource ID for the icon of this {@code PhoneAccount}.
382     *
383     * @return A resource ID.
384     */
385    public int getIconResId() {
386        return mIconResId;
387    }
388
389    /**
390     * A highlight color to use in displaying information about this {@code PhoneAccount}.
391     *
392     * @return A hexadecimal color value.
393     */
394    public int getColor() {
395        return mColor;
396    }
397
398    /**
399     * An icon to represent this {@code PhoneAccount} in a user interface.
400     *
401     * @return An icon for this {@code PhoneAccount}.
402     */
403    public Drawable getIcon(Context context) {
404        return getIcon(context, mIconResId);
405    }
406
407    private Drawable getIcon(Context context, int resId) {
408        if (resId == 0) {
409            return null;
410        }
411
412        Context packageContext;
413        try {
414            packageContext = context.createPackageContext(
415                    mAccountHandle.getComponentName().getPackageName(), 0);
416        } catch (PackageManager.NameNotFoundException e) {
417            Log.w(this, "Cannot find package %s",
418                    mAccountHandle.getComponentName().getPackageName());
419            return null;
420        }
421        try {
422            return packageContext.getDrawable(resId);
423        } catch (NotFoundException|MissingResourceException e) {
424            Log.e(this, e, "Cannot find icon %d in package %s",
425                    resId, mAccountHandle.getComponentName().getPackageName());
426            return null;
427        }
428    }
429
430    //
431    // Parcelable implementation
432    //
433
434    @Override
435    public int describeContents() {
436        return 0;
437    }
438
439    @Override
440    public void writeToParcel(Parcel out, int flags) {
441        out.writeParcelable(mAccountHandle, 0);
442        out.writeParcelable(mAddress, 0);
443        out.writeParcelable(mSubscriptionAddress, 0);
444        out.writeInt(mCapabilities);
445        out.writeInt(mIconResId);
446        out.writeInt(mColor);
447        out.writeCharSequence(mLabel);
448        out.writeCharSequence(mShortDescription);
449        out.writeList(mSupportedUriSchemes);
450    }
451
452    public static final Creator<PhoneAccount> CREATOR
453            = new Creator<PhoneAccount>() {
454        @Override
455        public PhoneAccount createFromParcel(Parcel in) {
456            return new PhoneAccount(in);
457        }
458
459        @Override
460        public PhoneAccount[] newArray(int size) {
461            return new PhoneAccount[size];
462        }
463    };
464
465    private PhoneAccount(Parcel in) {
466        ClassLoader classLoader = PhoneAccount.class.getClassLoader();
467
468        mAccountHandle = in.readParcelable(getClass().getClassLoader());
469        mAddress = in.readParcelable(getClass().getClassLoader());
470        mSubscriptionAddress = in.readParcelable(getClass().getClassLoader());
471        mCapabilities = in.readInt();
472        mIconResId = in.readInt();
473        mColor = in.readInt();
474        mLabel = in.readCharSequence();
475        mShortDescription = in.readCharSequence();
476
477        List<String> supportedUriSchemes = new ArrayList<>();
478        in.readList(supportedUriSchemes, classLoader);
479        mSupportedUriSchemes = Collections.unmodifiableList(supportedUriSchemes);
480    }
481
482    @Override
483    public String toString() {
484        StringBuilder sb = new StringBuilder().append("[PhoneAccount: ")
485                .append(mAccountHandle)
486                .append(" Capabilities: ")
487                .append(mCapabilities)
488                .append(" Schemes: ");
489        for (String scheme : mSupportedUriSchemes) {
490            sb.append(scheme)
491                    .append(" ");
492        }
493        sb.append("]");
494        return sb.toString();
495    }
496}
497