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