PhoneAccount.java revision ef9f6f957d897ea0ed82114185b8fa3fefd4917b
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     * Flag indicating that this {@code PhoneAccount} is always enabled and cannot be disabled by
95     * the user.
96     * This capability is reserved for important {@code PhoneAccount}s such as the emergency calling
97     * only {@code PhoneAccount}.
98     * <p>
99     * See {@link #getCapabilities}
100     * @hide
101     */
102    public static final int CAPABILITY_ALWAYS_ENABLED = 0x20;
103
104    /**
105     * URI scheme for telephone number URIs.
106     */
107    public static final String SCHEME_TEL = "tel";
108
109    /**
110     * URI scheme for voicemail URIs.
111     */
112    public static final String SCHEME_VOICEMAIL = "voicemail";
113
114    /**
115     * URI scheme for SIP URIs.
116     */
117    public static final String SCHEME_SIP = "sip";
118
119    private final PhoneAccountHandle mAccountHandle;
120    private final Uri mAddress;
121    private final Uri mSubscriptionAddress;
122    private final int mCapabilities;
123    private final int mIconResId;
124    private final CharSequence mLabel;
125    private final CharSequence mShortDescription;
126    private final List<String> mSupportedUriSchemes;
127    private final boolean mIsEnabled;
128
129    public static class Builder {
130        private PhoneAccountHandle mAccountHandle;
131        private Uri mAddress;
132        private Uri mSubscriptionAddress;
133        private int mCapabilities;
134        private int mIconResId;
135        private CharSequence mLabel;
136        private CharSequence mShortDescription;
137        private List<String> mSupportedUriSchemes = new ArrayList<String>();
138        private boolean mIsEnabled = false;
139
140        public Builder(PhoneAccountHandle accountHandle, CharSequence label) {
141            this.mAccountHandle = accountHandle;
142            this.mLabel = label;
143        }
144
145        /**
146         * Creates an instance of the {@link PhoneAccount.Builder} from an existing
147         * {@link PhoneAccount}.
148         *
149         * @param phoneAccount The {@link PhoneAccount} used to initialize the builder.
150         */
151        public Builder(PhoneAccount phoneAccount) {
152            mAccountHandle = phoneAccount.getAccountHandle();
153            mAddress = phoneAccount.getAddress();
154            mSubscriptionAddress = phoneAccount.getSubscriptionAddress();
155            mCapabilities = phoneAccount.getCapabilities();
156            mIconResId = phoneAccount.getIconResId();
157            mLabel = phoneAccount.getLabel();
158            mShortDescription = phoneAccount.getShortDescription();
159            mSupportedUriSchemes.addAll(phoneAccount.getSupportedUriSchemes());
160            mIsEnabled = phoneAccount.isEnabled();
161        }
162
163        public Builder setAddress(Uri value) {
164            this.mAddress = value;
165            return this;
166        }
167
168        public Builder setSubscriptionAddress(Uri value) {
169            this.mSubscriptionAddress = value;
170            return this;
171        }
172
173        public Builder setCapabilities(int value) {
174            this.mCapabilities = value;
175            return this;
176        }
177
178        public Builder setIconResId(int value) {
179            this.mIconResId = value;
180            return this;
181        }
182
183        public Builder setShortDescription(CharSequence value) {
184            this.mShortDescription = value;
185            return this;
186        }
187
188        /**
189         * Specifies an additional URI scheme supported by the {@link PhoneAccount}.
190         *
191         * @param uriScheme The URI scheme.
192         * @return The Builder.
193         * @hide
194         */
195        public Builder addSupportedUriScheme(String uriScheme) {
196            if (!TextUtils.isEmpty(uriScheme) && !mSupportedUriSchemes.contains(uriScheme)) {
197                this.mSupportedUriSchemes.add(uriScheme);
198            }
199            return this;
200        }
201
202        /**
203         * Specifies the URI schemes supported by the {@link PhoneAccount}.
204         *
205         * @param uriSchemes The URI schemes.
206         * @return The Builder.
207         */
208        public Builder setSupportedUriSchemes(List<String> uriSchemes) {
209            mSupportedUriSchemes.clear();
210
211            if (uriSchemes != null && !uriSchemes.isEmpty()) {
212                for (String uriScheme : uriSchemes) {
213                    addSupportedUriScheme(uriScheme);
214                }
215            }
216            return this;
217        }
218
219        /**
220         * Specifies whether the {@link PhoneAccount} is enabled or not.  {@link PhoneAccount}s are
221         * by default not enabled.
222         *
223         * @param value {@code True} if the {@link PhoneAccount} is enabled.
224         * @return The Builder.
225         * @hide
226         */
227        public Builder setEnabled(boolean value) {
228            this.mIsEnabled = value;
229            return this;
230        }
231
232        /**
233         * Creates an instance of a {@link PhoneAccount} based on the current builder settings.
234         *
235         * @return The {@link PhoneAccount}.
236         */
237        public PhoneAccount build() {
238            // If no supported URI schemes were defined, assume "tel" is supported.
239            if (mSupportedUriSchemes.isEmpty()) {
240                addSupportedUriScheme(SCHEME_TEL);
241            }
242
243            return new PhoneAccount(
244                    mAccountHandle,
245                    mAddress,
246                    mSubscriptionAddress,
247                    mCapabilities,
248                    mIconResId,
249                    mLabel,
250                    mShortDescription,
251                    mSupportedUriSchemes,
252                    mIsEnabled);
253        }
254    }
255
256    private PhoneAccount(
257            PhoneAccountHandle account,
258            Uri address,
259            Uri subscriptionAddress,
260            int capabilities,
261            int iconResId,
262            CharSequence label,
263            CharSequence shortDescription,
264            List<String> supportedUriSchemes,
265            boolean enabled) {
266        mAccountHandle = account;
267        mAddress = address;
268        mSubscriptionAddress = subscriptionAddress;
269        mCapabilities = capabilities;
270        mIconResId = iconResId;
271        mLabel = label;
272        mShortDescription = shortDescription;
273        mSupportedUriSchemes = Collections.unmodifiableList(supportedUriSchemes);
274        mIsEnabled = enabled;
275    }
276
277    public static Builder builder(
278            PhoneAccountHandle accountHandle,
279            CharSequence label) {
280        return new Builder(accountHandle, label);
281    }
282
283    /**
284     * Returns a builder initialized with the current {@link PhoneAccount} instance.
285     *
286     * @return The builder.
287     * @hide
288     */
289    public Builder toBuilder() { return new Builder(this); }
290
291    /**
292     * The unique identifier of this {@code PhoneAccount}.
293     *
294     * @return A {@code PhoneAccountHandle}.
295     */
296    public PhoneAccountHandle getAccountHandle() {
297        return mAccountHandle;
298    }
299
300    /**
301     * The address (e.g., a phone number) associated with this {@code PhoneAccount}. This
302     * represents the destination from which outgoing calls using this {@code PhoneAccount}
303     * will appear to come, if applicable, and the destination to which incoming calls using this
304     * {@code PhoneAccount} may be addressed.
305     *
306     * @return A address expressed as a {@code Uri}, for example, a phone number.
307     */
308    public Uri getAddress() {
309        return mAddress;
310    }
311
312    /**
313     * The raw callback number used for this {@code PhoneAccount}, as distinct from
314     * {@link #getAddress()}. For the majority of {@code PhoneAccount}s this should be registered
315     * as {@code null}.  It is used by the system for SIM-based {@code PhoneAccount} registration
316     * where {@link android.telephony.TelephonyManager#setLine1NumberForDisplay(String, String)}
317     * has been used to alter the callback number.
318     * <p>
319     *
320     * @return The subscription number, suitable for display to the user.
321     */
322    public Uri getSubscriptionAddress() {
323        return mSubscriptionAddress;
324    }
325
326    /**
327     * The capabilities of this {@code PhoneAccount}.
328     *
329     * @return A bit field of flags describing this {@code PhoneAccount}'s capabilities.
330     */
331    public int getCapabilities() {
332        return mCapabilities;
333    }
334
335    /**
336     * Determines if this {@code PhoneAccount} has a capabilities specified by the passed in
337     * bit mask.
338     *
339     * @param capability The capabilities to check.
340     * @return {@code True} if the phone account has the capability.
341     */
342    public boolean hasCapabilities(int capability) {
343        return (mCapabilities & capability) == capability;
344    }
345
346    /**
347     * A short label describing a {@code PhoneAccount}.
348     *
349     * @return A label for this {@code PhoneAccount}.
350     */
351    public CharSequence getLabel() {
352        return mLabel;
353    }
354
355    /**
356     * A short paragraph describing this {@code PhoneAccount}.
357     *
358     * @return A description for this {@code PhoneAccount}.
359     */
360    public CharSequence getShortDescription() {
361        return mShortDescription;
362    }
363
364    /**
365     * The URI schemes supported by this {@code PhoneAccount}.
366     *
367     * @return The URI schemes.
368     */
369    public List<String> getSupportedUriSchemes() {
370        return mSupportedUriSchemes;
371    }
372
373    /**
374     * Determines if the {@link PhoneAccount} supports calls to/from addresses with a specified URI
375     * scheme.
376     *
377     * @param uriScheme The URI scheme to check.
378     * @return {@code True} if the {@code PhoneAccount} supports calls to/from addresses with the
379     * specified URI scheme.
380     */
381    public boolean supportsUriScheme(String uriScheme) {
382        if (mSupportedUriSchemes == null || uriScheme == null) {
383            return false;
384        }
385
386        for (String scheme : mSupportedUriSchemes) {
387            if (scheme != null && scheme.equals(uriScheme)) {
388                return true;
389            }
390        }
391        return false;
392    }
393
394    /**
395     * Determines whether this {@code PhoneAccount} is enabled.
396     *
397     * @return {@code True} if this {@code PhoneAccount} is enabled..
398     */
399    public boolean isEnabled() {
400        return mIsEnabled;
401    }
402
403    /**
404     * The icon resource ID for the icon of this {@code PhoneAccount}.
405     *
406     * @return A resource ID.
407     */
408    public int getIconResId() {
409        return mIconResId;
410    }
411
412    /**
413     * An icon to represent this {@code PhoneAccount} in a user interface.
414     *
415     * @return An icon for this {@code PhoneAccount}.
416     */
417    public Drawable getIcon(Context context) {
418        return getIcon(context, mIconResId);
419    }
420
421    private Drawable getIcon(Context context, int resId) {
422        Context packageContext;
423        try {
424            packageContext = context.createPackageContext(
425                    mAccountHandle.getComponentName().getPackageName(), 0);
426        } catch (PackageManager.NameNotFoundException e) {
427            Log.w(this, "Cannot find package %s", mAccountHandle.getComponentName().getPackageName());
428            return null;
429        }
430        try {
431            return packageContext.getDrawable(resId);
432        } catch (NotFoundException|MissingResourceException e) {
433            Log.e(this, e, "Cannot find icon %d in package %s",
434                    resId, mAccountHandle.getComponentName().getPackageName());
435            return null;
436        }
437    }
438
439    //
440    // Parcelable implementation
441    //
442
443    @Override
444    public int describeContents() {
445        return 0;
446    }
447
448    @Override
449    public void writeToParcel(Parcel out, int flags) {
450        out.writeParcelable(mAccountHandle, 0);
451        out.writeParcelable(mAddress, 0);
452        out.writeParcelable(mSubscriptionAddress, 0);
453        out.writeInt(mCapabilities);
454        out.writeInt(mIconResId);
455        out.writeCharSequence(mLabel);
456        out.writeCharSequence(mShortDescription);
457        out.writeList(mSupportedUriSchemes);
458        out.writeInt(mIsEnabled ? 1 : 0);
459    }
460
461    public static final Creator<PhoneAccount> CREATOR
462            = new Creator<PhoneAccount>() {
463        @Override
464        public PhoneAccount createFromParcel(Parcel in) {
465            return new PhoneAccount(in);
466        }
467
468        @Override
469        public PhoneAccount[] newArray(int size) {
470            return new PhoneAccount[size];
471        }
472    };
473
474    private PhoneAccount(Parcel in) {
475        ClassLoader classLoader = PhoneAccount.class.getClassLoader();
476
477        mAccountHandle = in.readParcelable(getClass().getClassLoader());
478        mAddress = in.readParcelable(getClass().getClassLoader());
479        mSubscriptionAddress = in.readParcelable(getClass().getClassLoader());
480        mCapabilities = in.readInt();
481        mIconResId = in.readInt();
482        mLabel = in.readCharSequence();
483        mShortDescription = in.readCharSequence();
484
485        List<String> supportedUriSchemes = new ArrayList<>();
486        in.readList(supportedUriSchemes, classLoader);
487        mSupportedUriSchemes = Collections.unmodifiableList(supportedUriSchemes);
488        mIsEnabled = in.readInt() == 1;
489    }
490}
491