diff options
| author | Ihab Awad <ihab@google.com> | 2014-07-24 17:52:29 -0700 |
|---|---|---|
| committer | Ihab Awad <ihab@google.com> | 2014-07-25 11:38:04 -0700 |
| commit | 293edf245f3e37691073c8bf4a1fc271ecbc5370 (patch) | |
| tree | 227ddcdf3301875329de898eeba897912297be6a | |
| parent | 3bcf935b25470e94c8c6855862434d15b785c54a (diff) | |
| download | platform_packages_services_Telecomm-293edf245f3e37691073c8bf4a1fc271ecbc5370.tar.gz platform_packages_services_Telecomm-293edf245f3e37691073c8bf4a1fc271ecbc5370.tar.bz2 platform_packages_services_Telecomm-293edf245f3e37691073c8bf4a1fc271ecbc5370.zip | |
Improve Wi-Fi wiring
Bug: 16552606
Change-Id: Iddbde3d18e92ad1d40fb539d9177df582f317a7b
| -rw-r--r-- | res/values/strings.xml | 7 | ||||
| -rw-r--r-- | res/xml/phone_account_preferences.xml | 16 | ||||
| -rw-r--r-- | src/com/android/telecomm/AccountSelectionPreference.java | 94 | ||||
| -rw-r--r-- | src/com/android/telecomm/CreateConnectionProcessor.java | 84 | ||||
| -rw-r--r-- | src/com/android/telecomm/PhoneAccountPreferencesActivity.java | 87 | ||||
| -rw-r--r-- | src/com/android/telecomm/PhoneAccountRegistrar.java | 239 | ||||
| -rw-r--r-- | src/com/android/telecomm/TelecommServiceImpl.java | 3 |
7 files changed, 392 insertions, 138 deletions
diff --git a/res/values/strings.xml b/res/values/strings.xml index 4d19197ff..ad8829c60 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -82,12 +82,15 @@ <!-- Title for setting to select default outgoing phone account --> <string name="default_outgoing_account_title">Default outgoing account</string> - <!-- Summary for setting to select default outgoing phone account --> - <string name="default_outgoing_account_summary">Select a phone account to use by default for making outgoing calls</string> + <!-- Title for setting to select SIM call manager account --> + <string name="sim_call_manager_account">Wi-Fi calling account</string> <!-- Indication to "ask every time" for accounts when making a call --> <string name="account_ask_every_time">Ask every time</string> + <!-- Indication to not use a SIM call manager --> + <string name="do_not_use_sim_call_manager">Do not use Wi-Fi calling</string> + <!-- DO NOT TRANSLATE. Label for test Subscription 0. --> <string name="test_account_0_label">Q Mobile</string> <!-- DO NOT TRANSLATE. Label for test Subscription 1. --> diff --git a/res/xml/phone_account_preferences.xml b/res/xml/phone_account_preferences.xml index 716afb206..23313a16e 100644 --- a/res/xml/phone_account_preferences.xml +++ b/res/xml/phone_account_preferences.xml @@ -18,10 +18,14 @@ for making outgoing phone calls --> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" android:title="@string/phone_account_preferences_title"> - <ListPreference - android:key="default_outgoing_account" - android:title="@string/default_outgoing_account_title" - android:summary="@string/default_outgoing_account_summary" - android:defaultValue="" - android:persistent="false" /> + <com.android.telecomm.AccountSelectionPreference + android:key="default_outgoing_account" + android:title="@string/default_outgoing_account_title" + android:defaultValue="" + android:persistent="false" /> + <com.android.telecomm.AccountSelectionPreference + android:key="sim_call_manager_account" + android:title="@string/sim_call_manager_account" + android:defaultValue="" + android:persistent="false" /> </PreferenceScreen> diff --git a/src/com/android/telecomm/AccountSelectionPreference.java b/src/com/android/telecomm/AccountSelectionPreference.java new file mode 100644 index 000000000..e7c2bc081 --- /dev/null +++ b/src/com/android/telecomm/AccountSelectionPreference.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.telecomm; + +import android.content.Context; +import android.preference.ListPreference; +import android.preference.Preference; +import android.telecomm.PhoneAccountHandle; +import android.util.AttributeSet; + +import java.util.List; +import java.util.Objects; + +public class AccountSelectionPreference extends ListPreference implements + Preference.OnPreferenceChangeListener { + + public interface AccountSelectionListener { + boolean onAccountSelected(AccountSelectionPreference pref, PhoneAccountHandle account); + } + + private AccountSelectionListener mListener; + private PhoneAccountHandle[] mAccounts; + private String[] mEntryValues; + private CharSequence[] mEntries; + + public AccountSelectionPreference(Context context) { + super(context); + setOnPreferenceChangeListener(this); + } + + public AccountSelectionPreference(Context context, AttributeSet attrs) { + super(context, attrs); + setOnPreferenceChangeListener(this); + } + + public void setListener(AccountSelectionListener listener) { + mListener = listener; + } + + public void setModel( + PhoneAccountRegistrar registrar, + List<PhoneAccountHandle> accountsList, + PhoneAccountHandle currentSelection, + CharSequence nullSelectionString) { + mAccounts = accountsList.toArray(new PhoneAccountHandle[accountsList.size()]); + mEntryValues = new String[mAccounts.length + 1]; + mEntries = new CharSequence[mAccounts.length + 1]; + + int selectedIndex = mAccounts.length; // Points to nullSelectionString by default + int i = 0; + for ( ; i < mAccounts.length; i++) { + CharSequence label = registrar.getPhoneAccount(mAccounts[i]).getLabel(); + mEntries[i] = label == null ? null : label.toString(); + mEntryValues[i] = Integer.toString(i); + if (Objects.equals(currentSelection, mAccounts[i])) { + selectedIndex = i; + } + } + mEntryValues[i] = Integer.toString(i); + mEntries[i] = nullSelectionString; + + setEntryValues(mEntryValues); + setEntries(mEntries); + setValueIndex(selectedIndex); + setSummary(mEntries[selectedIndex]); + } + + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + if (mListener != null) { + int index = Integer.parseInt((String) newValue); + PhoneAccountHandle account = index < mAccounts.length ? mAccounts[index] : null; + if (mListener.onAccountSelected(this, account)) { + setSummary(mEntries[index]); + return true; + } + } + return false; + } +} diff --git a/src/com/android/telecomm/CreateConnectionProcessor.java b/src/com/android/telecomm/CreateConnectionProcessor.java index a0cb68850..0f289742e 100644 --- a/src/com/android/telecomm/CreateConnectionProcessor.java +++ b/src/com/android/telecomm/CreateConnectionProcessor.java @@ -24,6 +24,7 @@ import android.telephony.DisconnectCause; import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import java.util.Objects; /** * This class creates connections to place new outgoing calls to attached to an existing incoming @@ -33,10 +34,35 @@ import java.util.List; * - a connection service cancels the process, in which case the call is aborted */ final class CreateConnectionProcessor { + + // Describes information required to attempt to make a phone call + private static class CallAttemptRecord { + // The PhoneAccount describing the target connection service which we will + // contact in order to process an attempt + public final PhoneAccountHandle targetConnectionServiceAccount; + // The PhoneAccount which we will tell the target connection service to use + // for attempting to make the actual phone call + public final PhoneAccountHandle phoneAccount; + + public CallAttemptRecord( + PhoneAccountHandle targetConnectionServiceAccount, + PhoneAccountHandle phoneAccount) { + this.targetConnectionServiceAccount = targetConnectionServiceAccount; + this.phoneAccount = phoneAccount; + } + + @Override + public String toString() { + return "CallAttemptRecord(" + + Objects.toString(targetConnectionServiceAccount) + "," + + Objects.toString(phoneAccount) + ")"; + } + } + private final Call mCall; private final ConnectionServiceRepository mRepository; - private List<PhoneAccountHandle> mPhoneAccountHandles; - private Iterator<PhoneAccountHandle> mPhoneAccountHandleIterator; + private List<CallAttemptRecord> mAttemptRecords; + private Iterator<CallAttemptRecord> mAttemptRecordIterator; private CreateConnectionResponse mResponse; private int mLastErrorCode = DisconnectCause.OUTGOING_FAILURE; private String mLastErrorMsg; @@ -50,12 +76,14 @@ final class CreateConnectionProcessor { void process() { Log.v(this, "process"); - mPhoneAccountHandles = new ArrayList<>(); + mAttemptRecords = new ArrayList<>(); if (mCall.getPhoneAccount() != null) { - mPhoneAccountHandles.add(mCall.getPhoneAccount()); + mAttemptRecords.add( + new CallAttemptRecord(mCall.getPhoneAccount(), mCall.getPhoneAccount())); } - adjustPhoneAccountsForEmergency(); - mPhoneAccountHandleIterator = mPhoneAccountHandles.iterator(); + adjustAttemptsForWifi(); + adjustAttemptsForEmergency(); + mAttemptRecordIterator = mAttemptRecords.iterator(); attemptNextPhoneAccount(); } @@ -80,16 +108,16 @@ final class CreateConnectionProcessor { private void attemptNextPhoneAccount() { Log.v(this, "attemptNextPhoneAccount"); - if (mResponse != null && mPhoneAccountHandleIterator.hasNext()) { - PhoneAccountHandle accountHandle = mPhoneAccountHandleIterator.next(); - Log.i(this, "Trying accountHandle %s", accountHandle); + if (mResponse != null && mAttemptRecordIterator.hasNext()) { + CallAttemptRecord attempt = mAttemptRecordIterator.next(); + Log.i(this, "Trying attempt %s", attempt); ConnectionServiceWrapper service = - mRepository.getService(accountHandle.getComponentName()); + mRepository.getService(attempt.targetConnectionServiceAccount.getComponentName()); if (service == null) { - Log.i(this, "Found no connection service for accountHandle %s", accountHandle); + Log.i(this, "Found no connection service for attempt %s", attempt); attemptNextPhoneAccount(); } else { - mCall.setPhoneAccount(accountHandle); + mCall.setPhoneAccount(attempt.phoneAccount); mCall.setConnectionService(service); Log.i(this, "Attempting to call from %s", service.getComponentName()); service.createConnection(mCall, new Response(service)); @@ -104,19 +132,45 @@ final class CreateConnectionProcessor { } } + // If there exists a registered Wi-Fi calling service, use it. + private void adjustAttemptsForWifi() { + switch (mAttemptRecords.size()) { + case 0: + return; + case 1: + break; + default: + Log.d(this, "Unexpectedly have > 1 attempt: %s", mAttemptRecords); + return; + } + PhoneAccountHandle simCallManager = + TelecommApp.getInstance().getPhoneAccountRegistrar().getSimCallManager(); + if (simCallManager != null && + !Objects.equals(simCallManager, mAttemptRecords.get(0).phoneAccount)) { + mAttemptRecords.set( + 0, + new CallAttemptRecord( + simCallManager, + mAttemptRecords.get(0).phoneAccount)); + } + } + // If we are possibly attempting to call a local emergency number, ensure that the // plain PSTN connection services are listed, and nothing else. - private void adjustPhoneAccountsForEmergency() { + private void adjustAttemptsForEmergency() { if (TelephonyUtil.shouldProcessAsEmergency(TelecommApp.getInstance(), mCall.getHandle())) { Log.i(this, "Emergency number detected"); - mPhoneAccountHandles.clear(); + mAttemptRecords.clear(); List<PhoneAccountHandle> allAccountHandles = TelecommApp.getInstance() .getPhoneAccountRegistrar().getEnabledPhoneAccounts(); for (int i = 0; i < allAccountHandles.size(); i++) { if (TelephonyUtil.isPstnComponentName( allAccountHandles.get(i).getComponentName())) { Log.i(this, "Will try PSTN account %s for emergency", allAccountHandles.get(i)); - mPhoneAccountHandles.add(allAccountHandles.get(i)); + mAttemptRecords.add( + new CallAttemptRecord( + allAccountHandles.get(i), + allAccountHandles.get(i))); } } } diff --git a/src/com/android/telecomm/PhoneAccountPreferencesActivity.java b/src/com/android/telecomm/PhoneAccountPreferencesActivity.java index e4c62e7a5..2430f26fe 100644 --- a/src/com/android/telecomm/PhoneAccountPreferencesActivity.java +++ b/src/com/android/telecomm/PhoneAccountPreferencesActivity.java @@ -18,19 +18,17 @@ package com.android.telecomm; import android.app.Activity; import android.os.Bundle; -import android.preference.ListPreference; -import android.preference.Preference; import android.preference.PreferenceFragment; +import android.telecomm.PhoneAccount; import android.telecomm.PhoneAccountHandle; -import java.util.HashMap; +import java.util.ArrayList; import java.util.List; -import java.util.Map; -import java.util.Objects; public class PhoneAccountPreferencesActivity extends Activity { private static final String KEY_DEFAULT_OUTGOING_ACCOUNT = "default_outgoing_account"; + private static final String KEY_SIM_CALL_MANAGER_ACCOUNT = "sim_call_manager_account"; @Override public void onCreate(Bundle savedInstanceState) { @@ -39,54 +37,63 @@ public class PhoneAccountPreferencesActivity extends Activity { } public static class PreferencesFragment extends PreferenceFragment - implements ListPreference.OnPreferenceChangeListener { - private ListPreference mDefaultOutgoingAccount; - private PhoneAccountRegistrar mRegistrar; - private Map<String, PhoneAccountHandle> mAccountByValue = new HashMap<>(); + implements AccountSelectionPreference.AccountSelectionListener { + private AccountSelectionPreference mDefaultOutgoingAccount; + private AccountSelectionPreference mSimCallManagerAccount; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.phone_account_preferences); - mDefaultOutgoingAccount = (ListPreference) findPreference(KEY_DEFAULT_OUTGOING_ACCOUNT); - - mRegistrar = TelecommApp.getInstance().getPhoneAccountRegistrar(); - List<PhoneAccountHandle> accountHandles = mRegistrar.getEnabledPhoneAccounts(); - PhoneAccountHandle currentDefault = mRegistrar.getDefaultOutgoingPhoneAccount(); - - String[] entryValues = new String[accountHandles.size() + 1]; - String[] entries = new String[accountHandles.size() + 1]; - - int selectedIndex = accountHandles.size(); // Points to "ask every time" by default - int i = 0; - for ( ; i < accountHandles.size(); i++) { - CharSequence label = mRegistrar.getPhoneAccount(accountHandles.get(i)) - .getLabel(); - entries[i] = label == null ? null : label.toString(); - entryValues[i] = Integer.toString(i); - if (Objects.equals(currentDefault, accountHandles.get(i))) { - selectedIndex = i; - } - mAccountByValue.put(entryValues[i], accountHandles.get(i)); - } - entryValues[i] = Integer.toString(i); - entries[i] = getString(R.string.account_ask_every_time); - mAccountByValue.put(entryValues[i], null); - - mDefaultOutgoingAccount.setEntryValues(entryValues); - mDefaultOutgoingAccount.setEntries(entries); - mDefaultOutgoingAccount.setValueIndex(selectedIndex); - mDefaultOutgoingAccount.setOnPreferenceChangeListener(this); + + mDefaultOutgoingAccount = (AccountSelectionPreference) + findPreference(KEY_DEFAULT_OUTGOING_ACCOUNT); + mSimCallManagerAccount = (AccountSelectionPreference) + findPreference(KEY_SIM_CALL_MANAGER_ACCOUNT); + + PhoneAccountRegistrar registrar = TelecommApp.getInstance().getPhoneAccountRegistrar(); + + mDefaultOutgoingAccount.setModel( + registrar, + registrar.getEnabledPhoneAccounts(), + registrar.getDefaultOutgoingPhoneAccount(), + getString(R.string.account_ask_every_time)); + + mSimCallManagerAccount.setModel( + registrar, + getSimCallManagers(registrar), + registrar.getSimCallManager(), + getString(R.string.do_not_use_sim_call_manager)); + + mDefaultOutgoingAccount.setListener(this); + mSimCallManagerAccount.setListener(this); } @Override - public boolean onPreferenceChange(Preference p, Object o) { + public boolean onAccountSelected( + AccountSelectionPreference p, PhoneAccountHandle account) { + PhoneAccountRegistrar registrar = TelecommApp.getInstance().getPhoneAccountRegistrar(); if (p == mDefaultOutgoingAccount) { - mRegistrar.setDefaultOutgoingPhoneAccount(mAccountByValue.get(o)); + registrar.setDefaultOutgoingPhoneAccount(account); + return true; + } else if (p == mSimCallManagerAccount) { + registrar.setSimCallManager(account); return true; } return false; } + + private List<PhoneAccountHandle> getSimCallManagers(PhoneAccountRegistrar registrar) { + List<PhoneAccountHandle> simCallManagers = new ArrayList<>(); + List<PhoneAccountHandle> allAccounts = registrar.getAllPhoneAccountHandles(); + for (int i = 0; i < allAccounts.size(); i++) { + PhoneAccount account = registrar.getPhoneAccount(allAccounts.get(i)); + if ((account.getCapabilities() & PhoneAccount.CAPABILITY_SIM_CALL_MANAGER) != 0) { + simCallManagers.add(allAccounts.get(i)); + } + } + return simCallManagers; + } } } diff --git a/src/com/android/telecomm/PhoneAccountRegistrar.java b/src/com/android/telecomm/PhoneAccountRegistrar.java index 4c781dee4..f236f58f7 100644 --- a/src/com/android/telecomm/PhoneAccountRegistrar.java +++ b/src/com/android/telecomm/PhoneAccountRegistrar.java @@ -49,50 +49,47 @@ final class PhoneAccountRegistrar { private static final String PREFERENCE_PHONE_ACCOUNTS = "phone_accounts"; private final Context mContext; + private final State mState; PhoneAccountRegistrar(Context context) { mContext = context; + mState = readState(); } public PhoneAccountHandle getDefaultOutgoingPhoneAccount() { - State s = read(); - - if (s.defaultOutgoingHandle != null) { + if (mState.defaultOutgoing != null) { // Return the registered outgoing default iff it still exists (we keep a sticky // default to survive account deletion and re-addition) - for (int i = 0; i < s.accounts.size(); i++) { - if (s.accounts.get(i).getAccountHandle().equals(s.defaultOutgoingHandle)) { - return s.defaultOutgoingHandle; + for (int i = 0; i < mState.accounts.size(); i++) { + if (mState.accounts.get(i).getAccountHandle().equals(mState.defaultOutgoing)) { + return mState.defaultOutgoing; } } - // At this point, there was a registered default but it has been deleted; remember - // it for the future, but return null from this method - return null; - } else { - List<PhoneAccountHandle> enabled = getEnabledPhoneAccounts(); - switch (enabled.size()) { - case 0: - // There are no accounts, so there can be no default - return null; - case 1: - // There is only one account, which is by definition the default - return enabled.get(0); - default: - // There are multiple accounts with no selected default - return null; - } + // At this point, there was a registered default but it has been deleted; proceed + // as though there were no default + } + + List<PhoneAccountHandle> enabled = getEnabledPhoneAccounts(); + switch (enabled.size()) { + case 0: + // There are no accounts, so there can be no default + return null; + case 1: + // There is only one account, which is by definition the default + return enabled.get(0); + default: + // There are multiple accounts with no selected default + return null; } } public void setDefaultOutgoingPhoneAccount(PhoneAccountHandle accountHandle) { - State s = read(); - if (accountHandle == null) { // Asking to clear the default outgoing is a valid request - s.defaultOutgoingHandle = null; + mState.defaultOutgoing = null; } else { boolean found = false; - for (PhoneAccount m : s.accounts) { + for (PhoneAccount m : mState.accounts) { if (Objects.equals(accountHandle, m.getAccountHandle())) { found = true; break; @@ -105,21 +102,51 @@ final class PhoneAccountRegistrar { return; } - s.defaultOutgoingHandle = accountHandle; + mState.defaultOutgoing = accountHandle; + } + + write(); + } + + public void setSimCallManager(PhoneAccountHandle callManager) { + if (callManager != null) { + PhoneAccount callManagerAccount = getPhoneAccount(callManager); + if (callManagerAccount == null) { + Log.d(this, "setSimCallManager: Nonexistent call manager: %s", callManager); + return; + } else if (!has(callManagerAccount, PhoneAccount.CAPABILITY_SIM_CALL_MANAGER)) { + Log.d(this, "setSimCallManager: Not a call manager: %s", callManagerAccount); + return; + } + } + mState.simCallManager = callManager; + write(); + } + + public PhoneAccountHandle getSimCallManager() { + return mState.simCallManager; + } + + public List<PhoneAccountHandle> getAllPhoneAccountHandles() { + List<PhoneAccountHandle> accountHandles = new ArrayList<>(); + for (PhoneAccount m : mState.accounts) { + accountHandles.add(m.getAccountHandle()); } + return accountHandles; + } - write(s); + public List<PhoneAccount> getAllPhoneAccounts() { + return new ArrayList<>(mState.accounts); } + // TODO: Rename systemwide to "getCallProviderPhoneAccounts"? public List<PhoneAccountHandle> getEnabledPhoneAccounts() { - State s = read(); - return simSubscriptionAccountHandles(s); + return getCallProviderAccountHandles(); } - public PhoneAccount getPhoneAccount(PhoneAccountHandle accountHandle) { - State s = read(); - for (PhoneAccount m : s.accounts) { - if (Objects.equals(accountHandle, m.getAccountHandle())) { + public PhoneAccount getPhoneAccount(PhoneAccountHandle handle) { + for (PhoneAccount m : mState.accounts) { + if (Objects.equals(handle, m.getAccountHandle())) { return m; } } @@ -128,60 +155,112 @@ final class PhoneAccountRegistrar { // TODO: Should we implement an artificial limit for # of accounts associated with a single // ComponentName? - public void registerPhoneAccount(PhoneAccount metadata) { - State s = read(); - - s.accounts.add(metadata); + public void registerPhoneAccount(PhoneAccount account) { + account = hackFixBabelAccount(account); + mState.accounts.add(account); // Search for duplicates and remove any that are found. - for (int i = 0; i < s.accounts.size() - 1; i++) { - if (Objects.equals(metadata.getAccountHandle(), s.accounts.get(i).getAccountHandle())) { + for (int i = 0; i < mState.accounts.size() - 1; i++) { + if (Objects.equals( + account.getAccountHandle(), mState.accounts.get(i).getAccountHandle())) { // replace existing entry. - s.accounts.remove(i); + mState.accounts.remove(i); break; } } - write(s); + write(); } - public void unregisterPhoneAccount(PhoneAccountHandle accountHandle) { - State s = read(); + // STOPSHIP: Hack to edit the account registered by Babel so it shows up properly + private PhoneAccount hackFixBabelAccount(PhoneAccount account) { + String pkg = account.getAccountHandle().getComponentName().getPackageName(); + return "com.google.android.talk".equals(pkg) + ? new PhoneAccount( + account.getAccountHandle(), + account.getHandle(), + account.getSubscriptionNumber(), + PhoneAccount.CAPABILITY_SIM_CALL_MANAGER, + account.getIconResId(), + account.getLabel(), + account.getShortDescription(), + account.isVideoCallingSupported()) + : account; + } - for (int i = 0; i < s.accounts.size(); i++) { - if (Objects.equals(accountHandle, s.accounts.get(i).getAccountHandle())) { - s.accounts.remove(i); + public void unregisterPhoneAccount(PhoneAccountHandle accountHandle) { + for (int i = 0; i < mState.accounts.size(); i++) { + if (Objects.equals(accountHandle, mState.accounts.get(i).getAccountHandle())) { + mState.accounts.remove(i); break; } } - write(s); + write(); } public void clearAccounts(String packageName) { - State s = read(); - - for (int i = 0; i < s.accounts.size(); i++) { + for (int i = 0; i < mState.accounts.size(); i++) { if (Objects.equals( packageName, - s.accounts.get(i).getAccountHandle().getComponentName().getPackageName())) { - s.accounts.remove(i); + mState.accounts.get(i).getAccountHandle() + .getComponentName().getPackageName())) { + mState.accounts.remove(i); } } - write(s); + write(); + } + + //////////////////////////////////////////////////////////////////////////////////////////////// + + // TODO: Add a corresponding has(...) method to class PhoneAccount itself and remove this one + // Return true iff the given account has all the specified capability flags + static boolean has(PhoneAccount account, int capability) { + return (account.getCapabilities() & capability) == capability; } - private List<PhoneAccountHandle> simSubscriptionAccountHandles(State s) { + private List<PhoneAccountHandle> getCallProviderAccountHandles() { List<PhoneAccountHandle> accountHandles = new ArrayList<>(); - for (PhoneAccount m : s.accounts) { - if ((m.getCapabilities() & PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION) != 0) { + for (PhoneAccount m : mState.accounts) { + if (has(m, PhoneAccount.CAPABILITY_CALL_PROVIDER)) { accountHandles.add(m.getAccountHandle()); } } return accountHandles; } - private State read() { + /** + * The state of this {@code PhoneAccountRegistrar}. + */ + private static class State { + /** + * The account selected by the user to be employed by default for making outgoing calls. + * If the user has not made such a selection, then this is null. + */ + public PhoneAccountHandle defaultOutgoing = null; + + /** + * A {@code PhoneAccount} having {@link PhoneAccount#CAPABILITY_SIM_CALL_MANAGER} which + * manages and optimizes a user's PSTN SIM connections. + */ + public PhoneAccountHandle simCallManager; + + /** + * The complete list of {@code PhoneAccount}s known to the Telecomm subsystem. + */ + public final List<PhoneAccount> accounts = new ArrayList<>(); + } + + //////////////////////////////////////////////////////////////////////////////////////////////// + // + // State management + // + + private void write() { + writeState(mState); + } + + private State readState() { try { String serialized = getPreferences().getString(PREFERENCE_PHONE_ACCOUNTS, null); Log.v(this, "read() obtained serialized state: %s", serialized); @@ -196,7 +275,7 @@ final class PhoneAccountRegistrar { } } - private boolean write(State state) { + private boolean writeState(State state) { try { Log.v(this, "write() writing state: %s", state); String serialized = serializeState(state); @@ -226,11 +305,7 @@ final class PhoneAccountRegistrar { return sStateJson.fromJson(new JSONObject(new JSONTokener(s))); } - private static class State { - public PhoneAccountHandle defaultOutgoingHandle = null; - public final List<PhoneAccount> accounts = new ArrayList<>(); - } - + //////////////////////////////////////////////////////////////////////////////////////////////// // // JSON serialization // @@ -243,17 +318,21 @@ final class PhoneAccountRegistrar { private static final Json<State> sStateJson = new Json<State>() { private static final String DEFAULT_OUTGOING = "default_outgoing"; + private static final String SIM_CALL_MANAGER = "sim_call_manager"; private static final String ACCOUNTS = "accounts"; @Override public JSONObject toJson(State o) throws JSONException { JSONObject json = new JSONObject(); - if (o.defaultOutgoingHandle != null) { - json.put(DEFAULT_OUTGOING, sPhoneAccountJson.toJson(o.defaultOutgoingHandle)); + if (o.defaultOutgoing != null) { + json.put(DEFAULT_OUTGOING, sPhoneAccountHandleJson.toJson(o.defaultOutgoing)); + } + if (o.simCallManager != null) { + json.put(SIM_CALL_MANAGER, sPhoneAccountHandleJson.toJson(o.simCallManager)); } JSONArray accounts = new JSONArray(); for (PhoneAccount m : o.accounts) { - accounts.put(sPhoneAccountMetadataJson.toJson(m)); + accounts.put(sPhoneAccountJson.toJson(m)); } json.put(ACCOUNTS, accounts); return json; @@ -263,14 +342,26 @@ final class PhoneAccountRegistrar { public State fromJson(JSONObject json) throws JSONException { State s = new State(); if (json.has(DEFAULT_OUTGOING)) { - s.defaultOutgoingHandle = sPhoneAccountJson.fromJson( - (JSONObject) json.get(DEFAULT_OUTGOING)); + try { + s.defaultOutgoing = sPhoneAccountHandleJson.fromJson( + (JSONObject) json.get(DEFAULT_OUTGOING)); + } catch (Exception e) { + Log.e(this, e, "Extracting PhoneAccountHandle"); + } + } + if (json.has(SIM_CALL_MANAGER)) { + try { + s.simCallManager = sPhoneAccountHandleJson.fromJson( + (JSONObject) json.get(SIM_CALL_MANAGER)); + } catch (Exception e) { + Log.e(this, e, "Extracting PhoneAccountHandle"); + } } if (json.has(ACCOUNTS)) { JSONArray accounts = (JSONArray) json.get(ACCOUNTS); for (int i = 0; i < accounts.length(); i++) { try { - s.accounts.add(sPhoneAccountMetadataJson.fromJson( + s.accounts.add(sPhoneAccountJson.fromJson( (JSONObject) accounts.get(i))); } catch (Exception e) { Log.e(this, e, "Extracting phone account"); @@ -281,7 +372,7 @@ final class PhoneAccountRegistrar { } }; - private static final Json<PhoneAccount> sPhoneAccountMetadataJson = + private static final Json<PhoneAccount> sPhoneAccountJson = new Json<PhoneAccount>() { private static final String ACCOUNT = "account"; private static final String HANDLE = "handle"; @@ -295,7 +386,7 @@ final class PhoneAccountRegistrar { @Override public JSONObject toJson(PhoneAccount o) throws JSONException { return new JSONObject() - .put(ACCOUNT, sPhoneAccountJson.toJson(o.getAccountHandle())) + .put(ACCOUNT, sPhoneAccountHandleJson.toJson(o.getAccountHandle())) .put(HANDLE, o.getHandle().toString()) .put(SUBSCRIPTION_NUMBER, o.getSubscriptionNumber()) .put(CAPABILITIES, o.getCapabilities()) @@ -308,7 +399,7 @@ final class PhoneAccountRegistrar { @Override public PhoneAccount fromJson(JSONObject json) throws JSONException { return new PhoneAccount( - sPhoneAccountJson.fromJson((JSONObject) json.get(ACCOUNT)), + sPhoneAccountHandleJson.fromJson((JSONObject) json.get(ACCOUNT)), Uri.parse((String) json.get(HANDLE)), (String) json.get(SUBSCRIPTION_NUMBER), (int) json.get(CAPABILITIES), @@ -319,7 +410,7 @@ final class PhoneAccountRegistrar { } }; - private static final Json<PhoneAccountHandle> sPhoneAccountJson = + private static final Json<PhoneAccountHandle> sPhoneAccountHandleJson = new Json<PhoneAccountHandle>() { private static final String COMPONENT_NAME = "component_name"; private static final String ID = "id"; diff --git a/src/com/android/telecomm/TelecommServiceImpl.java b/src/com/android/telecomm/TelecommServiceImpl.java index b0fc709eb..359842236 100644 --- a/src/com/android/telecomm/TelecommServiceImpl.java +++ b/src/com/android/telecomm/TelecommServiceImpl.java @@ -193,7 +193,8 @@ public class TelecommServiceImpl extends ITelecommService.Stub { try { enforceModifyPermissionOrCallingPackage( account.getAccountHandle().getComponentName().getPackageName()); - if ((account.getCapabilities() & PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION) != 0) { + if (PhoneAccountRegistrar.has(account, PhoneAccount.CAPABILITY_CALL_PROVIDER) || + PhoneAccountRegistrar.has(account, PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) { enforceModifyPermissionOrCallingPackage(TELEPHONY_PACKAGE_NAME); } mPhoneAccountRegistrar.registerPhoneAccount(account); |
