PhoneAccountRegistrar.java revision 1c5926fc5f3c828c5b16c25a5154e5a0306ea3e7
1176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon/*
2176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon * Copyright (C) 2014 The Android Open Source Project
3176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon *
4176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon * Licensed under the Apache License, Version 2.0 (the "License");
5176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon * you may not use this file except in compliance with the License.
6176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon * You may obtain a copy of the License at
7176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon *
8176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon *      http://www.apache.org/licenses/LICENSE-2.0
9176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon *
10176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon * Unless required by applicable law or agreed to in writing, software
11176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon * distributed under the License is distributed on an "AS IS" BASIS,
12176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon * See the License for the specific language governing permissions and
14176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon * limitations under the License.
15176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon */
16176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon
177cc70b4f0ad1064a4a0dce6056ad82b205887160Tyler Gunnpackage com.android.server.telecom;
18176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon
19cb59b679e98d346c9725697ce08b05dd4c2f0a69Tyler Gunnimport android.Manifest;
20af51ceb458f94b9a179145f222ae4ea84951e8beEvan Charltonimport android.content.Intent;
21af51ceb458f94b9a179145f222ae4ea84951e8beEvan Charltonimport android.content.pm.PackageManager;
22af51ceb458f94b9a179145f222ae4ea84951e8beEvan Charltonimport android.content.pm.ResolveInfo;
23cb59b679e98d346c9725697ce08b05dd4c2f0a69Tyler Gunnimport android.content.pm.ServiceInfo;
2491d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunnimport android.os.Environment;
2591d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunnimport android.os.UserHandle;
268425357e131867f33587641f23a1d1a328acf139Tyler Gunnimport android.provider.Settings;
277cc70b4f0ad1064a4a0dce6056ad82b205887160Tyler Gunnimport android.telecom.ConnectionService;
287cc70b4f0ad1064a4a0dce6056ad82b205887160Tyler Gunnimport android.telecom.PhoneAccount;
297cc70b4f0ad1064a4a0dce6056ad82b205887160Tyler Gunnimport android.telecom.PhoneAccountHandle;
307cc70b4f0ad1064a4a0dce6056ad82b205887160Tyler Gunnimport android.telecom.TelecomManager;
31176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordonimport android.content.ComponentName;
32176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordonimport android.content.Context;
33176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordonimport android.net.Uri;
34af51ceb458f94b9a179145f222ae4ea84951e8beEvan Charltonimport android.text.TextUtils;
35b78b27693afbe9736f0a54ec473328955251f885Ihab Awadimport android.util.AtomicFile;
36b78b27693afbe9736f0a54ec473328955251f885Ihab Awadimport android.util.Xml;
37b78b27693afbe9736f0a54ec473328955251f885Ihab Awad
3891d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunn// TODO: Needed for move to system service: import com.android.internal.R;
390e1dc5a99042dd05b94b16a41461a3632a3fe5eeSailesh Nepalimport com.android.internal.annotations.VisibleForTesting;
400e1dc5a99042dd05b94b16a41461a3632a3fe5eeSailesh Nepalimport com.android.internal.util.FastXmlSerializer;
410e1dc5a99042dd05b94b16a41461a3632a3fe5eeSailesh Nepalimport com.android.internal.util.XmlUtils;
420e1dc5a99042dd05b94b16a41461a3632a3fe5eeSailesh Nepal
43af51ceb458f94b9a179145f222ae4ea84951e8beEvan Charltonimport org.xmlpull.v1.XmlPullParser;
44af51ceb458f94b9a179145f222ae4ea84951e8beEvan Charltonimport org.xmlpull.v1.XmlPullParserException;
45af51ceb458f94b9a179145f222ae4ea84951e8beEvan Charltonimport org.xmlpull.v1.XmlSerializer;
46af51ceb458f94b9a179145f222ae4ea84951e8beEvan Charlton
47b78b27693afbe9736f0a54ec473328955251f885Ihab Awadimport java.io.BufferedInputStream;
48b78b27693afbe9736f0a54ec473328955251f885Ihab Awadimport java.io.BufferedOutputStream;
49b78b27693afbe9736f0a54ec473328955251f885Ihab Awadimport java.io.File;
50b78b27693afbe9736f0a54ec473328955251f885Ihab Awadimport java.io.FileNotFoundException;
51b78b27693afbe9736f0a54ec473328955251f885Ihab Awadimport java.io.FileOutputStream;
52b78b27693afbe9736f0a54ec473328955251f885Ihab Awadimport java.io.IOException;
53b78b27693afbe9736f0a54ec473328955251f885Ihab Awadimport java.io.InputStream;
548425357e131867f33587641f23a1d1a328acf139Tyler Gunnimport java.lang.Integer;
55cb59b679e98d346c9725697ce08b05dd4c2f0a69Tyler Gunnimport java.lang.SecurityException;
56d900ce6021fe457c97f1e8d82374bf30b08f2ee5Tyler Gunnimport java.lang.String;
57176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordonimport java.util.ArrayList;
58afe59e5194e394922819eacc1b2ee12754479bf4Santos Cordonimport java.util.Collections;
59d900ce6021fe457c97f1e8d82374bf30b08f2ee5Tyler Gunnimport java.util.Iterator;
60176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordonimport java.util.List;
61176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordonimport java.util.Objects;
62b78b27693afbe9736f0a54ec473328955251f885Ihab Awadimport java.util.concurrent.CopyOnWriteArrayList;
63176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon
64176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon/**
6589176375c8d97db25588f720952a4fadbce2f9a3Evan Charlton * Handles writing and reading PhoneAccountHandle registration entries. This is a simple verbatim
667cc70b4f0ad1064a4a0dce6056ad82b205887160Tyler Gunn * delegate for all the account handling methods on {@link android.telecom.TelecomManager} as implemented in
677cc70b4f0ad1064a4a0dce6056ad82b205887160Tyler Gunn * {@link TelecomServiceImpl}, with the notable exception that {@link TelecomServiceImpl} is
68104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad * responsible for security checking to make sure that the caller has proper authority over
6989176375c8d97db25588f720952a4fadbce2f9a3Evan Charlton * the {@code ComponentName}s they are declaring in their {@code PhoneAccountHandle}s.
70176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon */
71b78b27693afbe9736f0a54ec473328955251f885Ihab Awadpublic final class PhoneAccountRegistrar {
72176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon
735e8836a73b8db1529308867d5a41145cb16cbfb0Yorke Lee    public static final PhoneAccountHandle NO_ACCOUNT_SELECTED =
745e8836a73b8db1529308867d5a41145cb16cbfb0Yorke Lee            new PhoneAccountHandle(new ComponentName("null", "null"), "NO_ACCOUNT_SELECTED");
755e8836a73b8db1529308867d5a41145cb16cbfb0Yorke Lee
76b78b27693afbe9736f0a54ec473328955251f885Ihab Awad    public abstract static class Listener {
77b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        public void onAccountsChanged(PhoneAccountRegistrar registrar) {}
78b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        public void onDefaultOutgoingChanged(PhoneAccountRegistrar registrar) {}
79b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        public void onSimCallManagerChanged(PhoneAccountRegistrar registrar) {}
80b78b27693afbe9736f0a54ec473328955251f885Ihab Awad    }
81b78b27693afbe9736f0a54ec473328955251f885Ihab Awad
82b78b27693afbe9736f0a54ec473328955251f885Ihab Awad    private static final String FILE_NAME = "phone-account-registrar-state.xml";
838425357e131867f33587641f23a1d1a328acf139Tyler Gunn    @VisibleForTesting
848e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn    public static final int EXPECTED_STATE_VERSION = 3;
858425357e131867f33587641f23a1d1a328acf139Tyler Gunn
868425357e131867f33587641f23a1d1a328acf139Tyler Gunn    /** Keep in sync with the same in SipSettings.java */
878425357e131867f33587641f23a1d1a328acf139Tyler Gunn    private static final String SIP_SHARED_PREFERENCES = "SIP_PREFERENCES";
88b78b27693afbe9736f0a54ec473328955251f885Ihab Awad
89b78b27693afbe9736f0a54ec473328955251f885Ihab Awad    private final List<Listener> mListeners = new CopyOnWriteArrayList<>();
90b78b27693afbe9736f0a54ec473328955251f885Ihab Awad    private final AtomicFile mAtomicFile;
91afe59e5194e394922819eacc1b2ee12754479bf4Santos Cordon    private final Context mContext;
92b78b27693afbe9736f0a54ec473328955251f885Ihab Awad    private State mState;
93176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon
942692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad    public PhoneAccountRegistrar(Context context) {
95b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        this(context, FILE_NAME);
96b78b27693afbe9736f0a54ec473328955251f885Ihab Awad    }
97b78b27693afbe9736f0a54ec473328955251f885Ihab Awad
98b78b27693afbe9736f0a54ec473328955251f885Ihab Awad    @VisibleForTesting
99b78b27693afbe9736f0a54ec473328955251f885Ihab Awad    public PhoneAccountRegistrar(Context context, String fileName) {
10091d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunn        // TODO: This file path is subject to change -- it is storing the phone account registry
10191d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunn        // state file in the path /data/system/users/0/, which is likely not correct in a
10291d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunn        // multi-user setting.
10391d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunn        /** UNCOMMENT_FOR_MOVE_TO_SYSTEM_SERVICE
10491d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunn        String filePath = Environment.getUserSystemDirectory(UserHandle.myUserId()).
10591d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunn                getAbsolutePath();
10691d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunn        mAtomicFile = new AtomicFile(new File(filePath, fileName));
10791d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunn         UNCOMMENT_FOR_MOVE_TO_SYSTEM_SERVICE */
108b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        mAtomicFile = new AtomicFile(new File(context.getFilesDir(), fileName));
10991d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunn
110b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        mState = new State();
111afe59e5194e394922819eacc1b2ee12754479bf4Santos Cordon        mContext = context;
112b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        read();
113104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad    }
114176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon
1158425357e131867f33587641f23a1d1a328acf139Tyler Gunn    /**
1168425357e131867f33587641f23a1d1a328acf139Tyler Gunn     * Retrieves the default outgoing phone account supporting the specified uriScheme.
1178425357e131867f33587641f23a1d1a328acf139Tyler Gunn     * @param uriScheme The URI scheme for the outgoing call.
1188425357e131867f33587641f23a1d1a328acf139Tyler Gunn     * @return The {@link PhoneAccountHandle} to use.
1198425357e131867f33587641f23a1d1a328acf139Tyler Gunn     */
1208425357e131867f33587641f23a1d1a328acf139Tyler Gunn    public PhoneAccountHandle getDefaultOutgoingPhoneAccount(String uriScheme) {
1215e8836a73b8db1529308867d5a41145cb16cbfb0Yorke Lee        final PhoneAccountHandle userSelected = getUserSelectedOutgoingPhoneAccount();
1228425357e131867f33587641f23a1d1a328acf139Tyler Gunn
1235e8836a73b8db1529308867d5a41145cb16cbfb0Yorke Lee        if (userSelected != null) {
1248425357e131867f33587641f23a1d1a328acf139Tyler Gunn            // If there is a default PhoneAccount, ensure it supports calls to handles with the
1258425357e131867f33587641f23a1d1a328acf139Tyler Gunn            // specified uriScheme.
1268425357e131867f33587641f23a1d1a328acf139Tyler Gunn            final PhoneAccount userSelectedAccount = getPhoneAccount(userSelected);
1278425357e131867f33587641f23a1d1a328acf139Tyler Gunn            if (userSelectedAccount.supportsUriScheme(uriScheme)) {
1288425357e131867f33587641f23a1d1a328acf139Tyler Gunn                return userSelected;
1298425357e131867f33587641f23a1d1a328acf139Tyler Gunn            }
130293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        }
131293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad
132309198ec4d8b2738cf955316ea7a2f9418929fd1Nancy Chen        List<PhoneAccountHandle> outgoing = getCallCapablePhoneAccounts(uriScheme);
1336fb37c87836b5245046bd3b14320823ab839a10cIhab Awad        switch (outgoing.size()) {
134293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad            case 0:
135293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad                // There are no accounts, so there can be no default
136293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad                return null;
137293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad            case 1:
138293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad                // There is only one account, which is by definition the default
1396fb37c87836b5245046bd3b14320823ab839a10cIhab Awad                return outgoing.get(0);
140293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad            default:
141293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad                // There are multiple accounts with no selected default
142293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad                return null;
143f2a8491d71915c621518ac8a40bed3c2a35272a9Ihab Awad        }
144104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad    }
145104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad
1465e8836a73b8db1529308867d5a41145cb16cbfb0Yorke Lee    PhoneAccountHandle getUserSelectedOutgoingPhoneAccount() {
1475e8836a73b8db1529308867d5a41145cb16cbfb0Yorke Lee        if (mState.defaultOutgoing != null) {
1485e8836a73b8db1529308867d5a41145cb16cbfb0Yorke Lee            // Return the registered outgoing default iff it still exists (we keep a sticky
1495e8836a73b8db1529308867d5a41145cb16cbfb0Yorke Lee            // default to survive account deletion and re-addition)
1505e8836a73b8db1529308867d5a41145cb16cbfb0Yorke Lee            for (int i = 0; i < mState.accounts.size(); i++) {
1515e8836a73b8db1529308867d5a41145cb16cbfb0Yorke Lee                if (mState.accounts.get(i).getAccountHandle().equals(mState.defaultOutgoing)) {
1525e8836a73b8db1529308867d5a41145cb16cbfb0Yorke Lee                    return mState.defaultOutgoing;
1535e8836a73b8db1529308867d5a41145cb16cbfb0Yorke Lee                }
1545e8836a73b8db1529308867d5a41145cb16cbfb0Yorke Lee            }
1555e8836a73b8db1529308867d5a41145cb16cbfb0Yorke Lee            // At this point, there was a registered default but it has been deleted; proceed
1565e8836a73b8db1529308867d5a41145cb16cbfb0Yorke Lee            // as though there were no default
1575e8836a73b8db1529308867d5a41145cb16cbfb0Yorke Lee        }
1585e8836a73b8db1529308867d5a41145cb16cbfb0Yorke Lee        return null;
1595e8836a73b8db1529308867d5a41145cb16cbfb0Yorke Lee    }
1605e8836a73b8db1529308867d5a41145cb16cbfb0Yorke Lee
161a51a386c818d3e4116b38b68daf588e2ab5e0499Andrew Lee    public void setUserSelectedOutgoingPhoneAccount(PhoneAccountHandle accountHandle) {
16289176375c8d97db25588f720952a4fadbce2f9a3Evan Charlton        if (accountHandle == null) {
163104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad            // Asking to clear the default outgoing is a valid request
164293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad            mState.defaultOutgoing = null;
165104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad        } else {
166104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad            boolean found = false;
167293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad            for (PhoneAccount m : mState.accounts) {
16894d01629010a61f6112713f22330d5fd4baae851Evan Charlton                if (Objects.equals(accountHandle, m.getAccountHandle())) {
169104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad                    found = true;
170104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad                    break;
171104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad                }
172104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad            }
173104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad
174104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad            if (!found) {
175b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                Log.w(this, "Trying to set nonexistent default outgoing %s",
176b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                        accountHandle);
177b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                return;
178b78b27693afbe9736f0a54ec473328955251f885Ihab Awad            }
179b78b27693afbe9736f0a54ec473328955251f885Ihab Awad
1808e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn            if (!getPhoneAccount(accountHandle).hasCapabilities(
1818e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn                    PhoneAccount.CAPABILITY_CALL_PROVIDER)) {
182b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                Log.w(this, "Trying to set non-call-provider default outgoing %s",
18389176375c8d97db25588f720952a4fadbce2f9a3Evan Charlton                        accountHandle);
184104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad                return;
185104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad            }
186104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad
187293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad            mState.defaultOutgoing = accountHandle;
188293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        }
189293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad
190293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        write();
191b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        fireDefaultOutgoingChanged();
192293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad    }
193293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad
194293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad    public void setSimCallManager(PhoneAccountHandle callManager) {
195293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        if (callManager != null) {
196293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad            PhoneAccount callManagerAccount = getPhoneAccount(callManager);
197293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad            if (callManagerAccount == null) {
198293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad                Log.d(this, "setSimCallManager: Nonexistent call manager: %s", callManager);
199293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad                return;
2008e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn            } else if (!callManagerAccount.hasCapabilities(
2018e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn                    PhoneAccount.CAPABILITY_CONNECTION_MANAGER)) {
202293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad                Log.d(this, "setSimCallManager: Not a call manager: %s", callManagerAccount);
203293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad                return;
204293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad            }
2055e8836a73b8db1529308867d5a41145cb16cbfb0Yorke Lee        } else {
2065e8836a73b8db1529308867d5a41145cb16cbfb0Yorke Lee            callManager = NO_ACCOUNT_SELECTED;
207293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        }
208293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        mState.simCallManager = callManager;
2095e8836a73b8db1529308867d5a41145cb16cbfb0Yorke Lee
210293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        write();
211b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        fireSimCallManagerChanged();
212293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad    }
213293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad
214293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad    public PhoneAccountHandle getSimCallManager() {
215b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        if (mState.simCallManager != null) {
2165e8836a73b8db1529308867d5a41145cb16cbfb0Yorke Lee            if (NO_ACCOUNT_SELECTED.equals(mState.simCallManager)) {
2175e8836a73b8db1529308867d5a41145cb16cbfb0Yorke Lee                return null;
2185e8836a73b8db1529308867d5a41145cb16cbfb0Yorke Lee            }
219b78b27693afbe9736f0a54ec473328955251f885Ihab Awad            // Return the registered sim call manager iff it still exists (we keep a sticky
220b78b27693afbe9736f0a54ec473328955251f885Ihab Awad            // setting to survive account deletion and re-addition)
221b78b27693afbe9736f0a54ec473328955251f885Ihab Awad            for (int i = 0; i < mState.accounts.size(); i++) {
222b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                if (mState.accounts.get(i).getAccountHandle().equals(mState.simCallManager)) {
223b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                    return mState.simCallManager;
224b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                }
225b78b27693afbe9736f0a54ec473328955251f885Ihab Awad            }
226b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        }
227af51ceb458f94b9a179145f222ae4ea84951e8beEvan Charlton
228af51ceb458f94b9a179145f222ae4ea84951e8beEvan Charlton        // See if the OEM has specified a default one.
229af51ceb458f94b9a179145f222ae4ea84951e8beEvan Charlton        String defaultConnectionMgr =
230afe59e5194e394922819eacc1b2ee12754479bf4Santos Cordon                mContext.getResources().getString(R.string.default_connection_manager_component);
231af51ceb458f94b9a179145f222ae4ea84951e8beEvan Charlton        if (!TextUtils.isEmpty(defaultConnectionMgr)) {
232afe59e5194e394922819eacc1b2ee12754479bf4Santos Cordon            PackageManager pm = mContext.getPackageManager();
233af51ceb458f94b9a179145f222ae4ea84951e8beEvan Charlton
234af51ceb458f94b9a179145f222ae4ea84951e8beEvan Charlton            ComponentName componentName = ComponentName.unflattenFromString(defaultConnectionMgr);
235af51ceb458f94b9a179145f222ae4ea84951e8beEvan Charlton            Intent intent = new Intent(ConnectionService.SERVICE_INTERFACE);
236af51ceb458f94b9a179145f222ae4ea84951e8beEvan Charlton            intent.setComponent(componentName);
237af51ceb458f94b9a179145f222ae4ea84951e8beEvan Charlton
238af51ceb458f94b9a179145f222ae4ea84951e8beEvan Charlton            // Make sure that the component can be resolved.
239af51ceb458f94b9a179145f222ae4ea84951e8beEvan Charlton            List<ResolveInfo> resolveInfos = pm.queryIntentServices(intent, 0);
240af51ceb458f94b9a179145f222ae4ea84951e8beEvan Charlton            if (!resolveInfos.isEmpty()) {
241af51ceb458f94b9a179145f222ae4ea84951e8beEvan Charlton                // See if there is registered PhoneAccount by this component.
242af51ceb458f94b9a179145f222ae4ea84951e8beEvan Charlton                List<PhoneAccountHandle> handles = getAllPhoneAccountHandles();
243af51ceb458f94b9a179145f222ae4ea84951e8beEvan Charlton                for (PhoneAccountHandle handle : handles) {
244af51ceb458f94b9a179145f222ae4ea84951e8beEvan Charlton                    if (componentName.equals(handle.getComponentName())) {
245af51ceb458f94b9a179145f222ae4ea84951e8beEvan Charlton                        return handle;
246af51ceb458f94b9a179145f222ae4ea84951e8beEvan Charlton                    }
247af51ceb458f94b9a179145f222ae4ea84951e8beEvan Charlton                }
248af51ceb458f94b9a179145f222ae4ea84951e8beEvan Charlton                Log.d(this, "%s does not have a PhoneAccount; not using as default", componentName);
249af51ceb458f94b9a179145f222ae4ea84951e8beEvan Charlton            } else {
250af51ceb458f94b9a179145f222ae4ea84951e8beEvan Charlton                Log.d(this, "%s could not be resolved; not using as default", componentName);
251af51ceb458f94b9a179145f222ae4ea84951e8beEvan Charlton            }
252af51ceb458f94b9a179145f222ae4ea84951e8beEvan Charlton        } else {
253af51ceb458f94b9a179145f222ae4ea84951e8beEvan Charlton            Log.v(this, "No default connection manager specified");
254af51ceb458f94b9a179145f222ae4ea84951e8beEvan Charlton        }
255af51ceb458f94b9a179145f222ae4ea84951e8beEvan Charlton
256b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        return null;
257293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad    }
258293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad
2598e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn    /**
2608e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn     * Retrieves a list of all {@link PhoneAccountHandle}s registered.
2618e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn     *
2628e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn     * @return The list of {@link PhoneAccountHandle}s.
2638e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn     */
264293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad    public List<PhoneAccountHandle> getAllPhoneAccountHandles() {
265293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        List<PhoneAccountHandle> accountHandles = new ArrayList<>();
266293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        for (PhoneAccount m : mState.accounts) {
267293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad            accountHandles.add(m.getAccountHandle());
268176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon        }
269293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        return accountHandles;
270293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad    }
271104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad
272293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad    public List<PhoneAccount> getAllPhoneAccounts() {
273293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        return new ArrayList<>(mState.accounts);
274176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon    }
275176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon
2768e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn    /**
277309198ec4d8b2738cf955316ea7a2f9418929fd1Nancy Chen     * Determines the number of all {@link PhoneAccount}s.
2788e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn     *
279309198ec4d8b2738cf955316ea7a2f9418929fd1Nancy Chen     * @return The total number {@link PhoneAccount}s.
2808e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn     */
2818e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn    public int getAllPhoneAccountsCount() {
2828e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn        return mState.accounts.size();
2838e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn    }
2848e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn
2858e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn    /**
286309198ec4d8b2738cf955316ea7a2f9418929fd1Nancy Chen     * Retrieves a list of all call provider phone accounts.
2878e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn     *
2888e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn     * @return The phone account handles.
2898e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn     */
290309198ec4d8b2738cf955316ea7a2f9418929fd1Nancy Chen    public List<PhoneAccountHandle> getCallCapablePhoneAccounts() {
291afe59e5194e394922819eacc1b2ee12754479bf4Santos Cordon        return getPhoneAccountHandles(PhoneAccount.CAPABILITY_CALL_PROVIDER);
292afe59e5194e394922819eacc1b2ee12754479bf4Santos Cordon    }
293afe59e5194e394922819eacc1b2ee12754479bf4Santos Cordon
2948e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn    /**
295309198ec4d8b2738cf955316ea7a2f9418929fd1Nancy Chen     * Retrieves a list of all phone account call provider phone accounts supporting the
2968e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn     * specified URI scheme.
2978e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn     *
2988e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn     * @param uriScheme The URI scheme.
2998e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn     * @return The phone account handles.
3008e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn     */
301309198ec4d8b2738cf955316ea7a2f9418929fd1Nancy Chen    public List<PhoneAccountHandle> getCallCapablePhoneAccounts(String uriScheme) {
302309198ec4d8b2738cf955316ea7a2f9418929fd1Nancy Chen        return getPhoneAccountHandles(PhoneAccount.CAPABILITY_CALL_PROVIDER, uriScheme);
3038425357e131867f33587641f23a1d1a328acf139Tyler Gunn    }
3048425357e131867f33587641f23a1d1a328acf139Tyler Gunn
3058e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn    /**
3061c5926fc5f3c828c5b16c25a5154e5a0306ea3e7Nancy Chen     * Retrieves a list of all phone accounts registered by a specified package.
3071c5926fc5f3c828c5b16c25a5154e5a0306ea3e7Nancy Chen     *
3081c5926fc5f3c828c5b16c25a5154e5a0306ea3e7Nancy Chen     * @param packageName The name of the package that registered the phone accounts.
3091c5926fc5f3c828c5b16c25a5154e5a0306ea3e7Nancy Chen     * @return The phone account handles.
3101c5926fc5f3c828c5b16c25a5154e5a0306ea3e7Nancy Chen     */
3111c5926fc5f3c828c5b16c25a5154e5a0306ea3e7Nancy Chen    public List<PhoneAccountHandle> getPhoneAccountsForPackage(String packageName) {
3121c5926fc5f3c828c5b16c25a5154e5a0306ea3e7Nancy Chen        List<PhoneAccountHandle> accountHandles = new ArrayList<>();
3131c5926fc5f3c828c5b16c25a5154e5a0306ea3e7Nancy Chen        for (PhoneAccount m : mState.accounts) {
3141c5926fc5f3c828c5b16c25a5154e5a0306ea3e7Nancy Chen            if (Objects.equals(
3151c5926fc5f3c828c5b16c25a5154e5a0306ea3e7Nancy Chen                    packageName,
3161c5926fc5f3c828c5b16c25a5154e5a0306ea3e7Nancy Chen                    m.getAccountHandle().getComponentName().getPackageName())) {
3171c5926fc5f3c828c5b16c25a5154e5a0306ea3e7Nancy Chen                accountHandles.add(m.getAccountHandle());
3181c5926fc5f3c828c5b16c25a5154e5a0306ea3e7Nancy Chen            }
3191c5926fc5f3c828c5b16c25a5154e5a0306ea3e7Nancy Chen        }
3201c5926fc5f3c828c5b16c25a5154e5a0306ea3e7Nancy Chen        return accountHandles;
3211c5926fc5f3c828c5b16c25a5154e5a0306ea3e7Nancy Chen    }
3221c5926fc5f3c828c5b16c25a5154e5a0306ea3e7Nancy Chen
3231c5926fc5f3c828c5b16c25a5154e5a0306ea3e7Nancy Chen    /**
324309198ec4d8b2738cf955316ea7a2f9418929fd1Nancy Chen     * Retrieves a list of all phone account handles with the connection manager capability.
3258e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn     *
3268e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn     * @return The phone account handles.
3278e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn     */
3288e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn    public List<PhoneAccountHandle> getConnectionManagerPhoneAccounts() {
329e3d8245f09c9d5333ebc7e2d82e684ecfeb6040eSantos Cordon        return getPhoneAccountHandles(PhoneAccount.CAPABILITY_CONNECTION_MANAGER,
330309198ec4d8b2738cf955316ea7a2f9418929fd1Nancy Chen                null /* supportedUriScheme */);
331176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon    }
332176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon
333293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad    public PhoneAccount getPhoneAccount(PhoneAccountHandle handle) {
334293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        for (PhoneAccount m : mState.accounts) {
335293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad            if (Objects.equals(handle, m.getAccountHandle())) {
336104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad                return m;
337104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad            }
338104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad        }
339104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad        return null;
340104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad    }
341176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon
342104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad    // TODO: Should we implement an artificial limit for # of accounts associated with a single
343104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad    // ComponentName?
344293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad    public void registerPhoneAccount(PhoneAccount account) {
345cb59b679e98d346c9725697ce08b05dd4c2f0a69Tyler Gunn        // Enforce the requirement that a connection service for a phone account has the correct
346cb59b679e98d346c9725697ce08b05dd4c2f0a69Tyler Gunn        // permission.
347cb59b679e98d346c9725697ce08b05dd4c2f0a69Tyler Gunn        if (!phoneAccountHasPermission(account.getAccountHandle())) {
348cb59b679e98d346c9725697ce08b05dd4c2f0a69Tyler Gunn            Log.w(this, "Phone account %s does not have BIND_CONNECTION_SERVICE permission.",
349cb59b679e98d346c9725697ce08b05dd4c2f0a69Tyler Gunn                    account.getAccountHandle());
350cb59b679e98d346c9725697ce08b05dd4c2f0a69Tyler Gunn            throw new SecurityException(
351cb59b679e98d346c9725697ce08b05dd4c2f0a69Tyler Gunn                    "PhoneAccount connection service requires BIND_CONNECTION_SERVICE permission.");
352cb59b679e98d346c9725697ce08b05dd4c2f0a69Tyler Gunn        }
353cb59b679e98d346c9725697ce08b05dd4c2f0a69Tyler Gunn
3548e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn        addOrReplacePhoneAccount(account);
3558e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn    }
3568e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn
3578e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn    /**
3588e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn     * Adds a {@code PhoneAccount}, replacing an existing one if found.
3598e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn     *
3608e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn     * @param account The {@code PhoneAccount} to add or replace.
3618e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn     */
3628e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn    private void addOrReplacePhoneAccount(PhoneAccount account) {
363293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        mState.accounts.add(account);
364176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon        // Search for duplicates and remove any that are found.
365293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        for (int i = 0; i < mState.accounts.size() - 1; i++) {
366293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad            if (Objects.equals(
367293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad                    account.getAccountHandle(), mState.accounts.get(i).getAccountHandle())) {
368176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon                // replace existing entry.
369293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad                mState.accounts.remove(i);
370176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon                break;
371176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon            }
372176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon        }
373176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon
374293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        write();
375b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        fireAccountsChanged();
376176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon    }
377176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon
378293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad    public void unregisterPhoneAccount(PhoneAccountHandle accountHandle) {
379293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        for (int i = 0; i < mState.accounts.size(); i++) {
380293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad            if (Objects.equals(accountHandle, mState.accounts.get(i).getAccountHandle())) {
381293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad                mState.accounts.remove(i);
382104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad                break;
383176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon            }
384176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon        }
385176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon
386293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        write();
387b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        fireAccountsChanged();
388176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon    }
389176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon
390d900ce6021fe457c97f1e8d82374bf30b08f2ee5Tyler Gunn    /**
391d900ce6021fe457c97f1e8d82374bf30b08f2ee5Tyler Gunn     * Un-registers all phone accounts associated with a specified package.
392d900ce6021fe457c97f1e8d82374bf30b08f2ee5Tyler Gunn     *
393d900ce6021fe457c97f1e8d82374bf30b08f2ee5Tyler Gunn     * @param packageName The package for which phone accounts will be removed.
394d900ce6021fe457c97f1e8d82374bf30b08f2ee5Tyler Gunn     */
395104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad    public void clearAccounts(String packageName) {
396d900ce6021fe457c97f1e8d82374bf30b08f2ee5Tyler Gunn        boolean accountsRemoved = false;
397d900ce6021fe457c97f1e8d82374bf30b08f2ee5Tyler Gunn        Iterator<PhoneAccount> it = mState.accounts.iterator();
398d900ce6021fe457c97f1e8d82374bf30b08f2ee5Tyler Gunn        while (it.hasNext()) {
399d900ce6021fe457c97f1e8d82374bf30b08f2ee5Tyler Gunn            PhoneAccount phoneAccount = it.next();
400104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad            if (Objects.equals(
401104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad                    packageName,
402d900ce6021fe457c97f1e8d82374bf30b08f2ee5Tyler Gunn                    phoneAccount.getAccountHandle().getComponentName().getPackageName())) {
403d900ce6021fe457c97f1e8d82374bf30b08f2ee5Tyler Gunn                Log.i(this, "Removing phone account " + phoneAccount.getLabel());
404d900ce6021fe457c97f1e8d82374bf30b08f2ee5Tyler Gunn                it.remove();
405d900ce6021fe457c97f1e8d82374bf30b08f2ee5Tyler Gunn                accountsRemoved = true;
406176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon            }
407176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon        }
408176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon
409d900ce6021fe457c97f1e8d82374bf30b08f2ee5Tyler Gunn        if (accountsRemoved) {
410d900ce6021fe457c97f1e8d82374bf30b08f2ee5Tyler Gunn            write();
411d900ce6021fe457c97f1e8d82374bf30b08f2ee5Tyler Gunn            fireAccountsChanged();
412d900ce6021fe457c97f1e8d82374bf30b08f2ee5Tyler Gunn        }
413b78b27693afbe9736f0a54ec473328955251f885Ihab Awad    }
414b78b27693afbe9736f0a54ec473328955251f885Ihab Awad
415b78b27693afbe9736f0a54ec473328955251f885Ihab Awad    public void addListener(Listener l) {
416b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        mListeners.add(l);
417b78b27693afbe9736f0a54ec473328955251f885Ihab Awad    }
418b78b27693afbe9736f0a54ec473328955251f885Ihab Awad
419b78b27693afbe9736f0a54ec473328955251f885Ihab Awad    public void removeListener(Listener l) {
420a82c8f794a0a1a9eaa1329a6361abe28043d139aJay Shrauner        if (l != null) {
421a82c8f794a0a1a9eaa1329a6361abe28043d139aJay Shrauner            mListeners.remove(l);
422a82c8f794a0a1a9eaa1329a6361abe28043d139aJay Shrauner        }
423b78b27693afbe9736f0a54ec473328955251f885Ihab Awad    }
424b78b27693afbe9736f0a54ec473328955251f885Ihab Awad
425b78b27693afbe9736f0a54ec473328955251f885Ihab Awad    private void fireAccountsChanged() {
426b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        for (Listener l : mListeners) {
427b78b27693afbe9736f0a54ec473328955251f885Ihab Awad            l.onAccountsChanged(this);
428b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        }
429b78b27693afbe9736f0a54ec473328955251f885Ihab Awad    }
430b78b27693afbe9736f0a54ec473328955251f885Ihab Awad
431b78b27693afbe9736f0a54ec473328955251f885Ihab Awad    private void fireDefaultOutgoingChanged() {
432b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        for (Listener l : mListeners) {
433b78b27693afbe9736f0a54ec473328955251f885Ihab Awad            l.onDefaultOutgoingChanged(this);
434b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        }
435b78b27693afbe9736f0a54ec473328955251f885Ihab Awad    }
436b78b27693afbe9736f0a54ec473328955251f885Ihab Awad
437b78b27693afbe9736f0a54ec473328955251f885Ihab Awad    private void fireSimCallManagerChanged() {
438b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        for (Listener l : mListeners) {
439b78b27693afbe9736f0a54ec473328955251f885Ihab Awad            l.onSimCallManagerChanged(this);
440b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        }
441293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad    }
442293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad
443cb59b679e98d346c9725697ce08b05dd4c2f0a69Tyler Gunn    /**
444cb59b679e98d346c9725697ce08b05dd4c2f0a69Tyler Gunn     * Determines if the connection service specified by a {@link PhoneAccountHandle} has the
445cb59b679e98d346c9725697ce08b05dd4c2f0a69Tyler Gunn     * {@link Manifest.permission#BIND_CONNECTION_SERVICE} permission.
446cb59b679e98d346c9725697ce08b05dd4c2f0a69Tyler Gunn     *
447cb59b679e98d346c9725697ce08b05dd4c2f0a69Tyler Gunn     * @param phoneAccountHandle The phone account to check.
448cb59b679e98d346c9725697ce08b05dd4c2f0a69Tyler Gunn     * @return {@code True} if the phone account has permission.
449cb59b679e98d346c9725697ce08b05dd4c2f0a69Tyler Gunn     */
450cb59b679e98d346c9725697ce08b05dd4c2f0a69Tyler Gunn    public boolean phoneAccountHasPermission(PhoneAccountHandle phoneAccountHandle) {
45191d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunn        PackageManager packageManager = mContext.getPackageManager();
452cb59b679e98d346c9725697ce08b05dd4c2f0a69Tyler Gunn        try {
453cb59b679e98d346c9725697ce08b05dd4c2f0a69Tyler Gunn            ServiceInfo serviceInfo = packageManager.getServiceInfo(
454cb59b679e98d346c9725697ce08b05dd4c2f0a69Tyler Gunn                    phoneAccountHandle.getComponentName(), 0);
455cb59b679e98d346c9725697ce08b05dd4c2f0a69Tyler Gunn
456cb59b679e98d346c9725697ce08b05dd4c2f0a69Tyler Gunn            return serviceInfo.permission != null &&
457cb59b679e98d346c9725697ce08b05dd4c2f0a69Tyler Gunn                    serviceInfo.permission.equals(Manifest.permission.BIND_CONNECTION_SERVICE);
458cb59b679e98d346c9725697ce08b05dd4c2f0a69Tyler Gunn        } catch (PackageManager.NameNotFoundException e) {
459cb59b679e98d346c9725697ce08b05dd4c2f0a69Tyler Gunn            Log.w(this, "Name not found %s", e);
460cb59b679e98d346c9725697ce08b05dd4c2f0a69Tyler Gunn            return false;
461cb59b679e98d346c9725697ce08b05dd4c2f0a69Tyler Gunn        }
462cb59b679e98d346c9725697ce08b05dd4c2f0a69Tyler Gunn    }
463cb59b679e98d346c9725697ce08b05dd4c2f0a69Tyler Gunn
464293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad    ////////////////////////////////////////////////////////////////////////////////////////////////
465293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad
466afe59e5194e394922819eacc1b2ee12754479bf4Santos Cordon    /**
467afe59e5194e394922819eacc1b2ee12754479bf4Santos Cordon     * Returns a list of phone account handles with the specified flag.
4688425357e131867f33587641f23a1d1a328acf139Tyler Gunn     *
4698425357e131867f33587641f23a1d1a328acf139Tyler Gunn     * @param flags Flags which the {@code PhoneAccount} must have.
470afe59e5194e394922819eacc1b2ee12754479bf4Santos Cordon     */
471afe59e5194e394922819eacc1b2ee12754479bf4Santos Cordon    private List<PhoneAccountHandle> getPhoneAccountHandles(int flags) {
472309198ec4d8b2738cf955316ea7a2f9418929fd1Nancy Chen        return getPhoneAccountHandles(flags, null);
4738425357e131867f33587641f23a1d1a328acf139Tyler Gunn    }
4748425357e131867f33587641f23a1d1a328acf139Tyler Gunn
4758425357e131867f33587641f23a1d1a328acf139Tyler Gunn    /**
4768425357e131867f33587641f23a1d1a328acf139Tyler Gunn     * Returns a list of phone account handles with the specified flag, supporting the specified
477309198ec4d8b2738cf955316ea7a2f9418929fd1Nancy Chen     * URI scheme.
4788425357e131867f33587641f23a1d1a328acf139Tyler Gunn     *
4798425357e131867f33587641f23a1d1a328acf139Tyler Gunn     * @param flags Flags which the {@code PhoneAccount} must have.
4808425357e131867f33587641f23a1d1a328acf139Tyler Gunn     * @param uriScheme URI schemes the PhoneAccount must handle.  {@code Null} bypasses the
4818425357e131867f33587641f23a1d1a328acf139Tyler Gunn     *                  URI scheme check.
4828425357e131867f33587641f23a1d1a328acf139Tyler Gunn     */
483309198ec4d8b2738cf955316ea7a2f9418929fd1Nancy Chen    private List<PhoneAccountHandle> getPhoneAccountHandles(int flags, String uriScheme) {
48494d01629010a61f6112713f22330d5fd4baae851Evan Charlton        List<PhoneAccountHandle> accountHandles = new ArrayList<>();
485293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        for (PhoneAccount m : mState.accounts) {
486309198ec4d8b2738cf955316ea7a2f9418929fd1Nancy Chen            if (m.hasCapabilities(flags) && (uriScheme == null || m.supportsUriScheme(uriScheme))) {
487f2a8491d71915c621518ac8a40bed3c2a35272a9Ihab Awad                accountHandles.add(m.getAccountHandle());
488f2a8491d71915c621518ac8a40bed3c2a35272a9Ihab Awad            }
489104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad        }
49094d01629010a61f6112713f22330d5fd4baae851Evan Charlton        return accountHandles;
491104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad    }
492176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon
493293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad    /**
494293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad     * The state of this {@code PhoneAccountRegistrar}.
495293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad     */
496b78b27693afbe9736f0a54ec473328955251f885Ihab Awad    @VisibleForTesting
497b78b27693afbe9736f0a54ec473328955251f885Ihab Awad    public static class State {
498293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        /**
499293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad         * The account selected by the user to be employed by default for making outgoing calls.
500293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad         * If the user has not made such a selection, then this is null.
501293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad         */
502293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        public PhoneAccountHandle defaultOutgoing = null;
503293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad
504293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        /**
505b78b27693afbe9736f0a54ec473328955251f885Ihab Awad         * A {@code PhoneAccount} having {@link PhoneAccount#CAPABILITY_CONNECTION_MANAGER} which
506293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad         * manages and optimizes a user's PSTN SIM connections.
507293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad         */
508293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        public PhoneAccountHandle simCallManager;
509293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad
510293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        /**
5117cc70b4f0ad1064a4a0dce6056ad82b205887160Tyler Gunn         * The complete list of {@code PhoneAccount}s known to the Telecom subsystem.
512293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad         */
513293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        public final List<PhoneAccount> accounts = new ArrayList<>();
5148425357e131867f33587641f23a1d1a328acf139Tyler Gunn
5158425357e131867f33587641f23a1d1a328acf139Tyler Gunn        /**
5168425357e131867f33587641f23a1d1a328acf139Tyler Gunn         * The version number of the State data.
5178425357e131867f33587641f23a1d1a328acf139Tyler Gunn         */
5188425357e131867f33587641f23a1d1a328acf139Tyler Gunn        public int versionNumber;
519293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad    }
520293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad
521293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad    ////////////////////////////////////////////////////////////////////////////////////////////////
522293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad    //
523293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad    // State management
524293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad    //
525293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad
526293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad    private void write() {
527b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        final FileOutputStream os;
528104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad        try {
529b78b27693afbe9736f0a54ec473328955251f885Ihab Awad            os = mAtomicFile.startWrite();
530b78b27693afbe9736f0a54ec473328955251f885Ihab Awad            boolean success = false;
531b78b27693afbe9736f0a54ec473328955251f885Ihab Awad            try {
532b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                XmlSerializer serializer = new FastXmlSerializer();
533b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                serializer.setOutput(new BufferedOutputStream(os), "utf-8");
534b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                writeToXml(mState, serializer);
535b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                serializer.flush();
536b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                success = true;
537b78b27693afbe9736f0a54ec473328955251f885Ihab Awad            } finally {
538b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                if (success) {
539b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                    mAtomicFile.finishWrite(os);
540b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                } else {
541b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                    mAtomicFile.failWrite(os);
542b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                }
543b78b27693afbe9736f0a54ec473328955251f885Ihab Awad            }
544b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        } catch (IOException e) {
545b78b27693afbe9736f0a54ec473328955251f885Ihab Awad            Log.e(this, e, "Writing state to XML file");
546176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon        }
547104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad    }
548176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon
549b78b27693afbe9736f0a54ec473328955251f885Ihab Awad    private void read() {
550b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        final InputStream is;
551104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad        try {
552b78b27693afbe9736f0a54ec473328955251f885Ihab Awad            is = mAtomicFile.openRead();
553b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        } catch (FileNotFoundException ex) {
554b78b27693afbe9736f0a54ec473328955251f885Ihab Awad            return;
555104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad        }
556176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon
5578425357e131867f33587641f23a1d1a328acf139Tyler Gunn        boolean versionChanged = false;
5588425357e131867f33587641f23a1d1a328acf139Tyler Gunn
559b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        XmlPullParser parser;
560b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        try {
561b78b27693afbe9736f0a54ec473328955251f885Ihab Awad            parser = Xml.newPullParser();
562b78b27693afbe9736f0a54ec473328955251f885Ihab Awad            parser.setInput(new BufferedInputStream(is), null);
563b78b27693afbe9736f0a54ec473328955251f885Ihab Awad            parser.nextTag();
5648425357e131867f33587641f23a1d1a328acf139Tyler Gunn            mState = readFromXml(parser, mContext);
5658425357e131867f33587641f23a1d1a328acf139Tyler Gunn            versionChanged = mState.versionNumber < EXPECTED_STATE_VERSION;
5668425357e131867f33587641f23a1d1a328acf139Tyler Gunn
567b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        } catch (IOException | XmlPullParserException e) {
568b78b27693afbe9736f0a54ec473328955251f885Ihab Awad            Log.e(this, e, "Reading state from XML file");
569b78b27693afbe9736f0a54ec473328955251f885Ihab Awad            mState = new State();
570b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        } finally {
571b78b27693afbe9736f0a54ec473328955251f885Ihab Awad            try {
572b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                is.close();
573b78b27693afbe9736f0a54ec473328955251f885Ihab Awad            } catch (IOException e) {
574b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                Log.e(this, e, "Closing InputStream");
575b78b27693afbe9736f0a54ec473328955251f885Ihab Awad            }
576b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        }
5778425357e131867f33587641f23a1d1a328acf139Tyler Gunn
5788425357e131867f33587641f23a1d1a328acf139Tyler Gunn        // If an upgrade occurred, write out the changed data.
5798425357e131867f33587641f23a1d1a328acf139Tyler Gunn        if (versionChanged) {
5808425357e131867f33587641f23a1d1a328acf139Tyler Gunn            write();
5818425357e131867f33587641f23a1d1a328acf139Tyler Gunn        }
582176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon    }
583176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon
584b78b27693afbe9736f0a54ec473328955251f885Ihab Awad    private static void writeToXml(State state, XmlSerializer serializer)
585b78b27693afbe9736f0a54ec473328955251f885Ihab Awad            throws IOException {
586b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        sStateXml.writeToXml(state, serializer);
587176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon    }
588176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon
5898425357e131867f33587641f23a1d1a328acf139Tyler Gunn    private static State readFromXml(XmlPullParser parser, Context context)
590b78b27693afbe9736f0a54ec473328955251f885Ihab Awad            throws IOException, XmlPullParserException {
5918425357e131867f33587641f23a1d1a328acf139Tyler Gunn        State s = sStateXml.readFromXml(parser, 0, context);
592b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        return s != null ? s : new State();
593176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon    }
594176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon
595293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad    ////////////////////////////////////////////////////////////////////////////////////////////////
596104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad    //
597b78b27693afbe9736f0a54ec473328955251f885Ihab Awad    // XML serialization
598104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad    //
599104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad
600b78b27693afbe9736f0a54ec473328955251f885Ihab Awad    @VisibleForTesting
6012692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad    public abstract static class XmlSerialization<T> {
6028425357e131867f33587641f23a1d1a328acf139Tyler Gunn        private static final String LENGTH_ATTRIBUTE = "length";
6038425357e131867f33587641f23a1d1a328acf139Tyler Gunn        private static final String VALUE_TAG = "value";
6048425357e131867f33587641f23a1d1a328acf139Tyler Gunn
605b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        /**
606b78b27693afbe9736f0a54ec473328955251f885Ihab Awad         * Write the supplied object to XML
607b78b27693afbe9736f0a54ec473328955251f885Ihab Awad         */
6082692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad        public abstract void writeToXml(T o, XmlSerializer serializer)
6092692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad                throws IOException;
610b78b27693afbe9736f0a54ec473328955251f885Ihab Awad
611b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        /**
612b78b27693afbe9736f0a54ec473328955251f885Ihab Awad         * Read from the supplied XML into a new object, returning null in case of an
613b78b27693afbe9736f0a54ec473328955251f885Ihab Awad         * unrecoverable schema mismatch or other data error. 'parser' must be already
614b78b27693afbe9736f0a54ec473328955251f885Ihab Awad         * positioned at the first tag that is expected to have been emitted by this
615b78b27693afbe9736f0a54ec473328955251f885Ihab Awad         * object's writeToXml(). This object tries to fail early without modifying
616b78b27693afbe9736f0a54ec473328955251f885Ihab Awad         * 'parser' if it does not recognize the data it sees.
617b78b27693afbe9736f0a54ec473328955251f885Ihab Awad         */
6188425357e131867f33587641f23a1d1a328acf139Tyler Gunn        public abstract T readFromXml(XmlPullParser parser, int version, Context context)
6192692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad                throws IOException, XmlPullParserException;
6202692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad
6212692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad        protected void writeTextSafely(String tagName, Object value, XmlSerializer serializer)
6222692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad                throws IOException {
6232692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad            if (value != null) {
6242692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad                serializer.startTag(null, tagName);
6252692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad                serializer.text(Objects.toString(value));
6262692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad                serializer.endTag(null, tagName);
6272692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad            }
6282692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad        }
6298425357e131867f33587641f23a1d1a328acf139Tyler Gunn
6308425357e131867f33587641f23a1d1a328acf139Tyler Gunn        /**
6318425357e131867f33587641f23a1d1a328acf139Tyler Gunn         * Serializes a string array.
6328425357e131867f33587641f23a1d1a328acf139Tyler Gunn         *
6338425357e131867f33587641f23a1d1a328acf139Tyler Gunn         * @param tagName The tag name for the string array.
6348425357e131867f33587641f23a1d1a328acf139Tyler Gunn         * @param values The string values to serialize.
6358425357e131867f33587641f23a1d1a328acf139Tyler Gunn         * @param serializer The serializer.
6368425357e131867f33587641f23a1d1a328acf139Tyler Gunn         * @throws IOException
6378425357e131867f33587641f23a1d1a328acf139Tyler Gunn         */
6388425357e131867f33587641f23a1d1a328acf139Tyler Gunn        protected void writeStringList(String tagName, List<String> values,
6398425357e131867f33587641f23a1d1a328acf139Tyler Gunn                XmlSerializer serializer)
6408425357e131867f33587641f23a1d1a328acf139Tyler Gunn                throws IOException {
6418425357e131867f33587641f23a1d1a328acf139Tyler Gunn
6428425357e131867f33587641f23a1d1a328acf139Tyler Gunn            serializer.startTag(null, tagName);
6438425357e131867f33587641f23a1d1a328acf139Tyler Gunn            if (values != null) {
6448425357e131867f33587641f23a1d1a328acf139Tyler Gunn                serializer.attribute(null, LENGTH_ATTRIBUTE, Objects.toString(values.size()));
6458425357e131867f33587641f23a1d1a328acf139Tyler Gunn                for (String toSerialize : values) {
6468425357e131867f33587641f23a1d1a328acf139Tyler Gunn                    serializer.startTag(null, VALUE_TAG);
6478425357e131867f33587641f23a1d1a328acf139Tyler Gunn                    if (toSerialize != null ){
6488425357e131867f33587641f23a1d1a328acf139Tyler Gunn                        serializer.text(toSerialize);
6498425357e131867f33587641f23a1d1a328acf139Tyler Gunn                    }
6508425357e131867f33587641f23a1d1a328acf139Tyler Gunn                    serializer.endTag(null, VALUE_TAG);
6518425357e131867f33587641f23a1d1a328acf139Tyler Gunn                }
6528425357e131867f33587641f23a1d1a328acf139Tyler Gunn            } else {
6538425357e131867f33587641f23a1d1a328acf139Tyler Gunn                serializer.attribute(null, LENGTH_ATTRIBUTE, "0");
6548425357e131867f33587641f23a1d1a328acf139Tyler Gunn            }
6558425357e131867f33587641f23a1d1a328acf139Tyler Gunn            serializer.endTag(null, tagName);
6568425357e131867f33587641f23a1d1a328acf139Tyler Gunn
6578425357e131867f33587641f23a1d1a328acf139Tyler Gunn        }
6588425357e131867f33587641f23a1d1a328acf139Tyler Gunn
6598425357e131867f33587641f23a1d1a328acf139Tyler Gunn        /**
6608425357e131867f33587641f23a1d1a328acf139Tyler Gunn         * Reads a string array from the XML parser.
6618425357e131867f33587641f23a1d1a328acf139Tyler Gunn         *
6628425357e131867f33587641f23a1d1a328acf139Tyler Gunn         * @param parser The XML parser.
6638425357e131867f33587641f23a1d1a328acf139Tyler Gunn         * @return String array containing the parsed values.
6648425357e131867f33587641f23a1d1a328acf139Tyler Gunn         * @throws IOException Exception related to IO.
6658425357e131867f33587641f23a1d1a328acf139Tyler Gunn         * @throws XmlPullParserException Exception related to parsing.
6668425357e131867f33587641f23a1d1a328acf139Tyler Gunn         */
6678425357e131867f33587641f23a1d1a328acf139Tyler Gunn        protected List<String> readStringList(XmlPullParser parser)
6688425357e131867f33587641f23a1d1a328acf139Tyler Gunn                throws IOException, XmlPullParserException {
6698425357e131867f33587641f23a1d1a328acf139Tyler Gunn
6708425357e131867f33587641f23a1d1a328acf139Tyler Gunn            int length = Integer.parseInt(parser.getAttributeValue(null, LENGTH_ATTRIBUTE));
6718425357e131867f33587641f23a1d1a328acf139Tyler Gunn            List<String> arrayEntries = new ArrayList<String>(length);
6728425357e131867f33587641f23a1d1a328acf139Tyler Gunn            String value = null;
6738425357e131867f33587641f23a1d1a328acf139Tyler Gunn
6748425357e131867f33587641f23a1d1a328acf139Tyler Gunn            if (length == 0) {
6758425357e131867f33587641f23a1d1a328acf139Tyler Gunn                return arrayEntries;
6768425357e131867f33587641f23a1d1a328acf139Tyler Gunn            }
6778425357e131867f33587641f23a1d1a328acf139Tyler Gunn
6788425357e131867f33587641f23a1d1a328acf139Tyler Gunn            int outerDepth = parser.getDepth();
6798425357e131867f33587641f23a1d1a328acf139Tyler Gunn            while (XmlUtils.nextElementWithin(parser, outerDepth)) {
6808425357e131867f33587641f23a1d1a328acf139Tyler Gunn                if (parser.getName().equals(VALUE_TAG)) {
6818e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn                    parser.next();
6828425357e131867f33587641f23a1d1a328acf139Tyler Gunn                    value = parser.getText();
6838425357e131867f33587641f23a1d1a328acf139Tyler Gunn                    arrayEntries.add(value);
6848425357e131867f33587641f23a1d1a328acf139Tyler Gunn                }
6858425357e131867f33587641f23a1d1a328acf139Tyler Gunn            }
6868425357e131867f33587641f23a1d1a328acf139Tyler Gunn
6878425357e131867f33587641f23a1d1a328acf139Tyler Gunn            return arrayEntries;
6888425357e131867f33587641f23a1d1a328acf139Tyler Gunn        }
689176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon    }
690104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad
691b78b27693afbe9736f0a54ec473328955251f885Ihab Awad    @VisibleForTesting
692b78b27693afbe9736f0a54ec473328955251f885Ihab Awad    public static final XmlSerialization<State> sStateXml =
693b78b27693afbe9736f0a54ec473328955251f885Ihab Awad            new XmlSerialization<State>() {
694b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        private static final String CLASS_STATE = "phone_account_registrar_state";
695104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad        private static final String DEFAULT_OUTGOING = "default_outgoing";
696293edf245f3e37691073c8bf4a1fc271ecbc5370Ihab Awad        private static final String SIM_CALL_MANAGER = "sim_call_manager";
697104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad        private static final String ACCOUNTS = "accounts";
6988425357e131867f33587641f23a1d1a328acf139Tyler Gunn        private static final String VERSION = "version";
699104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad
700104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad        @Override
701b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        public void writeToXml(State o, XmlSerializer serializer)
702b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                throws IOException {
7032692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad            if (o != null) {
7042692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad                serializer.startTag(null, CLASS_STATE);
7058425357e131867f33587641f23a1d1a328acf139Tyler Gunn                serializer.attribute(null, VERSION, Objects.toString(EXPECTED_STATE_VERSION));
706b78b27693afbe9736f0a54ec473328955251f885Ihab Awad
7072692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad                if (o.defaultOutgoing != null) {
7082692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad                    serializer.startTag(null, DEFAULT_OUTGOING);
7092692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad                    sPhoneAccountHandleXml.writeToXml(o.defaultOutgoing, serializer);
7102692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad                    serializer.endTag(null, DEFAULT_OUTGOING);
7112692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad                }
712b78b27693afbe9736f0a54ec473328955251f885Ihab Awad
7132692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad                if (o.simCallManager != null) {
7142692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad                    serializer.startTag(null, SIM_CALL_MANAGER);
7152692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad                    sPhoneAccountHandleXml.writeToXml(o.simCallManager, serializer);
7162692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad                    serializer.endTag(null, SIM_CALL_MANAGER);
7172692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad                }
718b78b27693afbe9736f0a54ec473328955251f885Ihab Awad
7192692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad                serializer.startTag(null, ACCOUNTS);
7202692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad                for (PhoneAccount m : o.accounts) {
7212692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad                    sPhoneAccountXml.writeToXml(m, serializer);
7222692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad                }
7232692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad                serializer.endTag(null, ACCOUNTS);
724b78b27693afbe9736f0a54ec473328955251f885Ihab Awad
7252692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad                serializer.endTag(null, CLASS_STATE);
7262692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad            }
727104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad        }
728104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad
729104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad        @Override
7308425357e131867f33587641f23a1d1a328acf139Tyler Gunn        public State readFromXml(XmlPullParser parser, int version, Context context)
731b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                throws IOException, XmlPullParserException {
732b78b27693afbe9736f0a54ec473328955251f885Ihab Awad            if (parser.getName().equals(CLASS_STATE)) {
733b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                State s = new State();
7348425357e131867f33587641f23a1d1a328acf139Tyler Gunn
7358425357e131867f33587641f23a1d1a328acf139Tyler Gunn                String rawVersion = parser.getAttributeValue(null, VERSION);
7368425357e131867f33587641f23a1d1a328acf139Tyler Gunn                s.versionNumber = TextUtils.isEmpty(rawVersion) ? 1 :
7378425357e131867f33587641f23a1d1a328acf139Tyler Gunn                        Integer.parseInt(rawVersion);
7388425357e131867f33587641f23a1d1a328acf139Tyler Gunn
739b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                int outerDepth = parser.getDepth();
740b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                while (XmlUtils.nextElementWithin(parser, outerDepth)) {
741b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                    if (parser.getName().equals(DEFAULT_OUTGOING)) {
742b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                        parser.nextTag();
7438425357e131867f33587641f23a1d1a328acf139Tyler Gunn                        s.defaultOutgoing = sPhoneAccountHandleXml.readFromXml(parser,
7448425357e131867f33587641f23a1d1a328acf139Tyler Gunn                                s.versionNumber, context);
745b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                    } else if (parser.getName().equals(SIM_CALL_MANAGER)) {
746b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                        parser.nextTag();
7478425357e131867f33587641f23a1d1a328acf139Tyler Gunn                        s.simCallManager = sPhoneAccountHandleXml.readFromXml(parser,
7488425357e131867f33587641f23a1d1a328acf139Tyler Gunn                                s.versionNumber, context);
749b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                    } else if (parser.getName().equals(ACCOUNTS)) {
750b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                        int accountsDepth = parser.getDepth();
751b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                        while (XmlUtils.nextElementWithin(parser, accountsDepth)) {
7528425357e131867f33587641f23a1d1a328acf139Tyler Gunn                            PhoneAccount account = sPhoneAccountXml.readFromXml(parser,
7538425357e131867f33587641f23a1d1a328acf139Tyler Gunn                                    s.versionNumber, context);
7548425357e131867f33587641f23a1d1a328acf139Tyler Gunn
7558425357e131867f33587641f23a1d1a328acf139Tyler Gunn                            if (account != null && s.accounts != null) {
756b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                                s.accounts.add(account);
757b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                            }
758b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                        }
759104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad                    }
760104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad                }
761b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                return s;
762104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad            }
763b78b27693afbe9736f0a54ec473328955251f885Ihab Awad            return null;
764104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad        }
765104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad    };
766104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad
767b78b27693afbe9736f0a54ec473328955251f885Ihab Awad    @VisibleForTesting
768b78b27693afbe9736f0a54ec473328955251f885Ihab Awad    public static final XmlSerialization<PhoneAccount> sPhoneAccountXml =
769b78b27693afbe9736f0a54ec473328955251f885Ihab Awad            new XmlSerialization<PhoneAccount>() {
770b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        private static final String CLASS_PHONE_ACCOUNT = "phone_account";
771b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        private static final String ACCOUNT_HANDLE = "account_handle";
7727129f1c47945f9aca51858c04daef58ada6bcc39Andrew Lee        private static final String ADDRESS = "handle";
7737129f1c47945f9aca51858c04daef58ada6bcc39Andrew Lee        private static final String SUBSCRIPTION_ADDRESS = "subscription_number";
774104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad        private static final String CAPABILITIES = "capabilities";
775104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad        private static final String ICON_RES_ID = "icon_res_id";
776104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad        private static final String LABEL = "label";
777104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad        private static final String SHORT_DESCRIPTION = "short_description";
7788425357e131867f33587641f23a1d1a328acf139Tyler Gunn        private static final String SUPPORTED_URI_SCHEMES = "supported_uri_schemes";
7798e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn        private static final String TRUE = "true";
7808e0fef4e1fd09116e4df4ba2ecc18f06cebe71c2Tyler Gunn        private static final String FALSE = "false";
781104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad
782104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad        @Override
783b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        public void writeToXml(PhoneAccount o, XmlSerializer serializer)
784b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                throws IOException {
7852692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad            if (o != null) {
7862692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad                serializer.startTag(null, CLASS_PHONE_ACCOUNT);
787b78b27693afbe9736f0a54ec473328955251f885Ihab Awad
7882692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad                if (o.getAccountHandle() != null) {
7892692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad                    serializer.startTag(null, ACCOUNT_HANDLE);
7902692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad                    sPhoneAccountHandleXml.writeToXml(o.getAccountHandle(), serializer);
7912692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad                    serializer.endTag(null, ACCOUNT_HANDLE);
7922692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad                }
793b78b27693afbe9736f0a54ec473328955251f885Ihab Awad
7947129f1c47945f9aca51858c04daef58ada6bcc39Andrew Lee                writeTextSafely(ADDRESS, o.getAddress(), serializer);
7957129f1c47945f9aca51858c04daef58ada6bcc39Andrew Lee                writeTextSafely(SUBSCRIPTION_ADDRESS, o.getSubscriptionAddress(), serializer);
7962692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad                writeTextSafely(CAPABILITIES, Integer.toString(o.getCapabilities()), serializer);
7972692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad                writeTextSafely(ICON_RES_ID, Integer.toString(o.getIconResId()), serializer);
7982692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad                writeTextSafely(LABEL, o.getLabel(), serializer);
7992692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad                writeTextSafely(SHORT_DESCRIPTION, o.getShortDescription(), serializer);
8008425357e131867f33587641f23a1d1a328acf139Tyler Gunn                writeStringList(SUPPORTED_URI_SCHEMES, o.getSupportedUriSchemes(), serializer);
801b78b27693afbe9736f0a54ec473328955251f885Ihab Awad
8022692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad                serializer.endTag(null, CLASS_PHONE_ACCOUNT);
8032692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad            }
804104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad        }
805104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad
8068425357e131867f33587641f23a1d1a328acf139Tyler Gunn        public PhoneAccount readFromXml(XmlPullParser parser, int version, Context context)
807b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                throws IOException, XmlPullParserException {
808b78b27693afbe9736f0a54ec473328955251f885Ihab Awad            if (parser.getName().equals(CLASS_PHONE_ACCOUNT)) {
809b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                int outerDepth = parser.getDepth();
810b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                PhoneAccountHandle accountHandle = null;
8117129f1c47945f9aca51858c04daef58ada6bcc39Andrew Lee                Uri address = null;
8127129f1c47945f9aca51858c04daef58ada6bcc39Andrew Lee                Uri subscriptionAddress = null;
813b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                int capabilities = 0;
814b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                int iconResId = 0;
815b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                String label = null;
816b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                String shortDescription = null;
8178425357e131867f33587641f23a1d1a328acf139Tyler Gunn                List<String> supportedUriSchemes = null;
818b78b27693afbe9736f0a54ec473328955251f885Ihab Awad
819b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                while (XmlUtils.nextElementWithin(parser, outerDepth)) {
820b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                    if (parser.getName().equals(ACCOUNT_HANDLE)) {
821b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                        parser.nextTag();
8228425357e131867f33587641f23a1d1a328acf139Tyler Gunn                        accountHandle = sPhoneAccountHandleXml.readFromXml(parser, version,
8238425357e131867f33587641f23a1d1a328acf139Tyler Gunn                                context);
8247129f1c47945f9aca51858c04daef58ada6bcc39Andrew Lee                    } else if (parser.getName().equals(ADDRESS)) {
825b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                        parser.next();
8267129f1c47945f9aca51858c04daef58ada6bcc39Andrew Lee                        address = Uri.parse(parser.getText());
8277129f1c47945f9aca51858c04daef58ada6bcc39Andrew Lee                    } else if (parser.getName().equals(SUBSCRIPTION_ADDRESS)) {
828b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                        parser.next();
8297129f1c47945f9aca51858c04daef58ada6bcc39Andrew Lee                        String nextText = parser.getText();
8307129f1c47945f9aca51858c04daef58ada6bcc39Andrew Lee                        subscriptionAddress = nextText == null ? null : Uri.parse(nextText);
831b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                    } else if (parser.getName().equals(CAPABILITIES)) {
832b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                        parser.next();
833b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                        capabilities = Integer.parseInt(parser.getText());
834b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                    } else if (parser.getName().equals(ICON_RES_ID)) {
835b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                        parser.next();
836b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                        iconResId = Integer.parseInt(parser.getText());
837b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                    } else if (parser.getName().equals(LABEL)) {
838b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                        parser.next();
839b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                        label = parser.getText();
840b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                    } else if (parser.getName().equals(SHORT_DESCRIPTION)) {
841b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                        parser.next();
842b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                        shortDescription = parser.getText();
8438425357e131867f33587641f23a1d1a328acf139Tyler Gunn                    } else if (parser.getName().equals(SUPPORTED_URI_SCHEMES)) {
8448425357e131867f33587641f23a1d1a328acf139Tyler Gunn                        supportedUriSchemes = readStringList(parser);
845b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                    }
846b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                }
8478425357e131867f33587641f23a1d1a328acf139Tyler Gunn
8488425357e131867f33587641f23a1d1a328acf139Tyler Gunn                // Upgrade older phone accounts to specify the supported URI schemes.
8498425357e131867f33587641f23a1d1a328acf139Tyler Gunn                if (version < 2) {
8508425357e131867f33587641f23a1d1a328acf139Tyler Gunn                    ComponentName sipComponentName = new ComponentName("com.android.phone",
8518425357e131867f33587641f23a1d1a328acf139Tyler Gunn                            "com.android.services.telephony.sip.SipConnectionService");
8528425357e131867f33587641f23a1d1a328acf139Tyler Gunn
8538425357e131867f33587641f23a1d1a328acf139Tyler Gunn                    supportedUriSchemes = new ArrayList<>();
8548425357e131867f33587641f23a1d1a328acf139Tyler Gunn
8558425357e131867f33587641f23a1d1a328acf139Tyler Gunn                    // Handle the SIP connection service.
8568425357e131867f33587641f23a1d1a328acf139Tyler Gunn                    // Check the system settings to see if it also should handle "tel" calls.
8578425357e131867f33587641f23a1d1a328acf139Tyler Gunn                    if (accountHandle.getComponentName().equals(sipComponentName)) {
8588425357e131867f33587641f23a1d1a328acf139Tyler Gunn                        boolean useSipForPstn = useSipForPstnCalls(context);
8598425357e131867f33587641f23a1d1a328acf139Tyler Gunn                        supportedUriSchemes.add(PhoneAccount.SCHEME_SIP);
8608425357e131867f33587641f23a1d1a328acf139Tyler Gunn                        if (useSipForPstn) {
8618425357e131867f33587641f23a1d1a328acf139Tyler Gunn                            supportedUriSchemes.add(PhoneAccount.SCHEME_TEL);
8628425357e131867f33587641f23a1d1a328acf139Tyler Gunn                        }
8638425357e131867f33587641f23a1d1a328acf139Tyler Gunn                    } else {
8648425357e131867f33587641f23a1d1a328acf139Tyler Gunn                        supportedUriSchemes.add(PhoneAccount.SCHEME_TEL);
8658425357e131867f33587641f23a1d1a328acf139Tyler Gunn                        supportedUriSchemes.add(PhoneAccount.SCHEME_VOICEMAIL);
8668425357e131867f33587641f23a1d1a328acf139Tyler Gunn                    }
8678425357e131867f33587641f23a1d1a328acf139Tyler Gunn                }
8688425357e131867f33587641f23a1d1a328acf139Tyler Gunn
8697129f1c47945f9aca51858c04daef58ada6bcc39Andrew Lee                return PhoneAccount.builder(accountHandle, label)
8707129f1c47945f9aca51858c04daef58ada6bcc39Andrew Lee                        .setAddress(address)
8717129f1c47945f9aca51858c04daef58ada6bcc39Andrew Lee                        .setSubscriptionAddress(subscriptionAddress)
8727129f1c47945f9aca51858c04daef58ada6bcc39Andrew Lee                        .setCapabilities(capabilities)
8737129f1c47945f9aca51858c04daef58ada6bcc39Andrew Lee                        .setIconResId(iconResId)
8747129f1c47945f9aca51858c04daef58ada6bcc39Andrew Lee                        .setShortDescription(shortDescription)
8757129f1c47945f9aca51858c04daef58ada6bcc39Andrew Lee                        .setSupportedUriSchemes(supportedUriSchemes)
8766fb37c87836b5245046bd3b14320823ab839a10cIhab Awad                        .build();
877b78b27693afbe9736f0a54ec473328955251f885Ihab Awad            }
878b78b27693afbe9736f0a54ec473328955251f885Ihab Awad            return null;
879104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad        }
8808425357e131867f33587641f23a1d1a328acf139Tyler Gunn
8818425357e131867f33587641f23a1d1a328acf139Tyler Gunn        /**
8828425357e131867f33587641f23a1d1a328acf139Tyler Gunn         * Determines if the SIP call settings specify to use SIP for all calls, including PSTN calls.
8838425357e131867f33587641f23a1d1a328acf139Tyler Gunn         *
8848425357e131867f33587641f23a1d1a328acf139Tyler Gunn         * @param context The context.
8858425357e131867f33587641f23a1d1a328acf139Tyler Gunn         * @return {@code True} if SIP should be used for all calls.
8868425357e131867f33587641f23a1d1a328acf139Tyler Gunn         */
8878425357e131867f33587641f23a1d1a328acf139Tyler Gunn        private boolean useSipForPstnCalls(Context context) {
8888425357e131867f33587641f23a1d1a328acf139Tyler Gunn            String option = Settings.System.getString(context.getContentResolver(),
8898425357e131867f33587641f23a1d1a328acf139Tyler Gunn                    Settings.System.SIP_CALL_OPTIONS);
8908425357e131867f33587641f23a1d1a328acf139Tyler Gunn            option = (option != null) ? option : Settings.System.SIP_ADDRESS_ONLY;
8918425357e131867f33587641f23a1d1a328acf139Tyler Gunn            return option.equals(Settings.System.SIP_ALWAYS);
8928425357e131867f33587641f23a1d1a328acf139Tyler Gunn        }
893104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad    };
894104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad
895b78b27693afbe9736f0a54ec473328955251f885Ihab Awad    @VisibleForTesting
896b78b27693afbe9736f0a54ec473328955251f885Ihab Awad    public static final XmlSerialization<PhoneAccountHandle> sPhoneAccountHandleXml =
897b78b27693afbe9736f0a54ec473328955251f885Ihab Awad            new XmlSerialization<PhoneAccountHandle>() {
898b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        private static final String CLASS_PHONE_ACCOUNT_HANDLE = "phone_account_handle";
899104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad        private static final String COMPONENT_NAME = "component_name";
900104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad        private static final String ID = "id";
901104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad
902104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad        @Override
903b78b27693afbe9736f0a54ec473328955251f885Ihab Awad        public void writeToXml(PhoneAccountHandle o, XmlSerializer serializer)
904b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                throws IOException {
9052692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad            if (o != null) {
9062692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad                serializer.startTag(null, CLASS_PHONE_ACCOUNT_HANDLE);
907b78b27693afbe9736f0a54ec473328955251f885Ihab Awad
9082692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad                if (o.getComponentName() != null) {
9092692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad                    writeTextSafely(
9102692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad                            COMPONENT_NAME, o.getComponentName().flattenToString(), serializer);
9112692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad                }
912b78b27693afbe9736f0a54ec473328955251f885Ihab Awad
9132692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad                writeTextSafely(ID, o.getId(), serializer);
914b78b27693afbe9736f0a54ec473328955251f885Ihab Awad
9152692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad                serializer.endTag(null, CLASS_PHONE_ACCOUNT_HANDLE);
9162692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad            }
917104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad        }
918104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad
919104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad        @Override
9208425357e131867f33587641f23a1d1a328acf139Tyler Gunn        public PhoneAccountHandle readFromXml(XmlPullParser parser, int version, Context context)
921b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                throws IOException, XmlPullParserException {
922b78b27693afbe9736f0a54ec473328955251f885Ihab Awad            if (parser.getName().equals(CLASS_PHONE_ACCOUNT_HANDLE)) {
923b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                String componentNameString = null;
924b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                String idString = null;
925b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                int outerDepth = parser.getDepth();
926b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                while (XmlUtils.nextElementWithin(parser, outerDepth)) {
927b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                    if (parser.getName().equals(COMPONENT_NAME)) {
928b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                        parser.next();
929b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                        componentNameString = parser.getText();
930b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                    } else if (parser.getName().equals(ID)) {
931b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                        parser.next();
932b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                        idString = parser.getText();
933b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                    }
934b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                }
9352692322d55952a807c4fdad7048ca4b4051bf516Ihab Awad                if (componentNameString != null) {
936b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                    return new PhoneAccountHandle(
937b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                            ComponentName.unflattenFromString(componentNameString),
938b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                            idString);
939b78b27693afbe9736f0a54ec473328955251f885Ihab Awad                }
940b78b27693afbe9736f0a54ec473328955251f885Ihab Awad            }
941b78b27693afbe9736f0a54ec473328955251f885Ihab Awad            return null;
942104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad        }
943104f80654d9a0df493f1cf4b9f07b0c2d5d4436eIhab Awad    };
944176ae28ea91519a0b8d513abf3885535c7420d95Santos Cordon}
945