Wire up multi-SIM experience (3/4)
Change-Id: Ic8fe987951f57d362b0c2d4e342bddffa506b58f
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 2f8fc6f..c80a2d3 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -181,5 +181,13 @@
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
+
+ <activity android:name=".PhoneAccountPreferencesActivity"
+ android:exported="true" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ </intent-filter>
+ </activity>
+
</application>
</manifest>
diff --git a/res/layout/phone_account_preferences.xml b/res/layout/phone_account_preferences.xml
new file mode 100644
index 0000000..caf2a47
--- /dev/null
+++ b/res/layout/phone_account_preferences.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <fragment
+ android:id="@+id/preferences_fragment"
+ class="com.android.telecomm.PhoneAccountPreferencesActivity$PreferencesFragment"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+</LinearLayout>
\ No newline at end of file
diff --git a/res/values/strings.xml b/res/values/strings.xml
index eddeec5..4d19197 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -76,6 +76,17 @@
a text response. [CHAR LIMIT=40] -->
<string name="respond_via_sms_confirmation_format">Message sent to <xliff:g id="phone_number">%s</xliff:g>.</string>
+ <!-- Title for phone accounts settings screen -->
+ <string name="phone_account_preferences_title">Phone account preferences</string>
+
+ <!-- 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>
+
+ <!-- Indication to "ask every time" for accounts when making a call -->
+ <string name="account_ask_every_time">Ask every time</string>
<!-- DO NOT TRANSLATE. Label for test Subscription 0. -->
<string name="test_account_0_label">Q Mobile</string>
diff --git a/res/xml/phone_account_preferences.xml b/res/xml/phone_account_preferences.xml
new file mode 100644
index 0000000..7f12306
--- /dev/null
+++ b/res/xml/phone_account_preferences.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- Settings screen for selecting which PhoneAccount to use by default
+ 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" />
+</PreferenceScreen>
diff --git a/src/com/android/telecomm/CallsManager.java b/src/com/android/telecomm/CallsManager.java
index 9dbcf18..b8733c5 100644
--- a/src/com/android/telecomm/CallsManager.java
+++ b/src/com/android/telecomm/CallsManager.java
@@ -62,9 +62,6 @@
private static final CallsManager INSTANCE = new CallsManager();
- /** Temporary flag for disabling account selection menu */
- public static final boolean ENABLE_ACCOUNT_SELECT = false;
-
/**
* The main call repository. Keeps an instance of all live calls. New incoming and outgoing
* calls are added to the map and removed when the calls move to the disconnected state.
@@ -314,13 +311,16 @@
call.addListener(this);
addCall(call);
- // TODO: check for default account
- if (account == null && ENABLE_ACCOUNT_SELECT) {
- call.setState(CallState.PRE_DIAL_WAIT);
- return;
+ if (account == null) {
+ PhoneAccount defaultAccount = TelecommApp.getInstance().getPhoneAccountRegistrar()
+ .getDefaultOutgoingPhoneAccount();
+ if (defaultAccount != null) {
+ call.setPhoneAccount(defaultAccount);
+ call.startCreateConnection();
+ } else {
+ call.setState(CallState.PRE_DIAL_WAIT);
+ }
}
-
- call.startCreateConnection();
}
/**
diff --git a/src/com/android/telecomm/CreateConnectionProcessor.java b/src/com/android/telecomm/CreateConnectionProcessor.java
index 631d6fe..5d1f308 100644
--- a/src/com/android/telecomm/CreateConnectionProcessor.java
+++ b/src/com/android/telecomm/CreateConnectionProcessor.java
@@ -25,7 +25,6 @@
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
-import java.util.Map;
/**
* This class creates connections to place new outgoing calls to attached to an existing incoming
@@ -57,8 +56,6 @@
// TODO(sail): Remove once there's a way to pick the service.
ArrayList<ComponentName> priorityComponents = new ArrayList<>();
- priorityComponents.add(new ComponentName("com.android.phone",
- "com.android.services.telephony.sip.SipConnectionService"));
priorityComponents.add(new ComponentName("com.google.android.talk",
"com.google.android.apps.babel.telephony.TeleConnectionService"));
priorityComponents.add(new ComponentName("com.android.telecomm.tests",
diff --git a/src/com/android/telecomm/Log.java b/src/com/android/telecomm/Log.java
index ebcc175..23bf534 100644
--- a/src/com/android/telecomm/Log.java
+++ b/src/com/android/telecomm/Log.java
@@ -32,7 +32,7 @@
// Generic tag for all In Call logging
private static final String TAG = "Telecomm";
- public static final boolean FORCE_LOGGING = false; /* STOP SHIP if true */
+ public static final boolean FORCE_LOGGING = true; /* STOP SHIP if true */
public static final boolean DEBUG = isLoggable(android.util.Log.DEBUG);
public static final boolean INFO = isLoggable(android.util.Log.INFO);
public static final boolean VERBOSE = isLoggable(android.util.Log.VERBOSE);
diff --git a/src/com/android/telecomm/PhoneAccountPreferencesActivity.java b/src/com/android/telecomm/PhoneAccountPreferencesActivity.java
new file mode 100644
index 0000000..2988a9c
--- /dev/null
+++ b/src/com/android/telecomm/PhoneAccountPreferencesActivity.java
@@ -0,0 +1,92 @@
+/*
+ * 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.app.Activity;
+import android.os.Bundle;
+import android.preference.ListPreference;
+import android.preference.Preference;
+import android.preference.PreferenceFragment;
+import android.telecomm.PhoneAccount;
+
+import java.util.HashMap;
+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";
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.phone_account_preferences);
+ }
+
+ public static class PreferencesFragment extends PreferenceFragment
+ implements ListPreference.OnPreferenceChangeListener {
+ private ListPreference mDefaultOutgoingAccount;
+ private PhoneAccountRegistrar mRegistrar;
+ private Map<String, PhoneAccount> mAccountByValue = new HashMap<>();
+
+ @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<PhoneAccount> accounts = mRegistrar.getEnabledPhoneAccounts();
+ PhoneAccount currentDefault = mRegistrar.getDefaultOutgoingPhoneAccount();
+
+ String[] entryValues = new String[accounts.size() + 1];
+ String[] entries = new String[accounts.size() + 1];
+
+ int selectedIndex = accounts.size(); // Points to "ask every time" by default
+ int i = 0;
+ for ( ; i < accounts.size(); i++) {
+ entryValues[i] = Integer.toString(i);
+ entries[i] = mRegistrar
+ .getPhoneAccountMetadata(accounts.get(i))
+ .getLabel();
+ if (Objects.equals(currentDefault, accounts.get(i))) {
+ selectedIndex = i;
+ }
+ mAccountByValue.put(entryValues[i], accounts.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);
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference p, Object o) {
+ if (p == mDefaultOutgoingAccount) {
+ mRegistrar.setDefaultOutgoingPhoneAccount(mAccountByValue.get(o));
+ return true;
+ }
+ return false;
+ }
+ }
+}
diff --git a/src/com/android/telecomm/PhoneAccountRegistrar.java b/src/com/android/telecomm/PhoneAccountRegistrar.java
index e8abb8a..4b6feca 100644
--- a/src/com/android/telecomm/PhoneAccountRegistrar.java
+++ b/src/com/android/telecomm/PhoneAccountRegistrar.java
@@ -16,209 +16,310 @@
package com.android.telecomm;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.json.JSONTokener;
+
import android.content.ComponentName;
import android.content.Context;
import android.content.SharedPreferences;
-import android.content.SharedPreferences.Editor;
import android.net.Uri;
-import android.provider.Settings;
import android.telecomm.PhoneAccount;
+import android.telecomm.PhoneAccountMetadata;
+import android.telecomm.TelecommManager;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
- * Handles writing and reading PhoneAccount registration entries.
+ * Handles writing and reading PhoneAccount registration entries. This is a simple verbatim
+ * delegate for all the account handling methods on {@link TelecommManager} as implemented in
+ * {@link TelecommServiceImpl}, with the notable exception that {@link TelecommServiceImpl} is
+ * responsible for security checking to make sure that the caller has proper authority over
+ * the {@code ComponentName}s they are declaring in their {@code PhoneAccount}s.
+ *
* TODO(santoscordon): Replace this implementation with a proper database stored in a Telecomm
* provider.
*/
final class PhoneAccountRegistrar {
- private static final int VERSION = 1;
private static final String TELECOMM_PREFERENCES = "telecomm_prefs";
private static final String PREFERENCE_PHONE_ACCOUNTS = "phone_accounts";
private final Context mContext;
- private final class DeserializationToken {
- int currentIndex = 0;
- final String source;
-
- DeserializationToken(String source) {
- this.source = source;
- }
- }
-
PhoneAccountRegistrar(Context context) {
mContext = context;
}
- /**
- * Adds a new phone account entry or updates an existing one.
- */
- boolean addAccount(PhoneAccount account) {
- List<PhoneAccount> allAccounts = getAllAccounts();
- // Should we implement an artificial limit for # of accounts associated with a single
- // ComponentName?
- allAccounts.add(account);
+ public PhoneAccount getDefaultOutgoingPhoneAccount() {
+ State s = read();
+ return s.mDefaultOutgoing;
+ }
- // Search for duplicates and remove any that are found.
- for (int i = 0; i < allAccounts.size() - 1; i++) {
- if (account.equalsComponentAndId(allAccounts.get(i))) {
- // replace existing entry.
- allAccounts.remove(i);
- break;
+ public void setDefaultOutgoingPhoneAccount(PhoneAccount account) {
+ State s = read();
+
+ if (account == null) {
+ // Asking to clear the default outgoing is a valid request
+ s.mDefaultOutgoing = null;
+ } else {
+ boolean found = false;
+ for (PhoneAccountMetadata m : s.mAccounts) {
+ if (Objects.equals(account, m.getAccount())) {
+ found = true;
+ break;
+ }
}
+
+ if (!found) {
+ Log.d(this, "Trying to set nonexistent default outgoing phone account %s", account);
+ return;
+ }
+
+ s.mDefaultOutgoing = account;
}
- return writeAllAccounts(allAccounts);
+ write(s);
}
- /**
- * Removes an existing phone account entry.
- */
- boolean removeAccount(PhoneAccount account) {
- List<PhoneAccount> allAccounts = getAllAccounts();
-
- for (int i = 0; i < allAccounts.size(); i++) {
- if (account.equalsComponentAndId(allAccounts.get(i))) {
- allAccounts.remove(i);
- return writeAllAccounts(allAccounts);
- }
- }
-
- return false;
+ public List<PhoneAccount> getEnabledPhoneAccounts() {
+ State s = read();
+ return accountsOnly(s);
}
- /**
- * Returns a list of all accounts which the user has enabled.
- */
- List<PhoneAccount> getEnabledAccounts() {
- List<PhoneAccount> allAccounts = getAllAccounts();
- // TODO: filter list
- return allAccounts;
- }
-
- /**
- * Returns the list of all accounts registered with the system, whether or not the user
- * has explicitly enabled them.
- */
- List<PhoneAccount> getAllAccounts() {
- String value = getPreferences().getString(PREFERENCE_PHONE_ACCOUNTS, null);
- return deserializeAllAccounts(value);
- }
-
- /**
- * Returns the registered version of the account matching the component name and ID of the
- * specified account.
- */
- PhoneAccount getRegisteredAccount(PhoneAccount account) {
- for (PhoneAccount registeredAccount : getAllAccounts()) {
- if (registeredAccount.equalsComponentAndId(account)) {
- return registeredAccount;
+ public PhoneAccountMetadata getPhoneAccountMetadata(PhoneAccount account) {
+ State s = read();
+ for (PhoneAccountMetadata m : s.mAccounts) {
+ if (Objects.equals(account, m.getAccount())) {
+ return m;
}
}
return null;
}
- /**
- * Replaces the contents of our list of accounts with this new list.
- */
- private boolean writeAllAccounts(List<PhoneAccount> allAccounts) {
- Editor editor = getPreferences().edit();
- editor.putString(PREFERENCE_PHONE_ACCOUNTS, serializeAllAccounts(allAccounts));
- return editor.commit();
- }
+ // TODO: Should we implement an artificial limit for # of accounts associated with a single
+ // ComponentName?
+ public void registerPhoneAccount(PhoneAccountMetadata metadata) {
+ State s = read();
- // Serialization implementation
- // Serializes all strings into the format "len:string-value"
- // Example, we will serialize the following PhoneAccount.
- // PhoneAccount
- // ComponentName: "abc"
- // Id: "def"
- // Handle: "555"
- // Capabilities: 1
- //
- // Each value serializes into (spaces added for readability)
- // 3:abc 3:def 3:555 1:1
- //
- // Two identical accounts would likewise be serialized as a list of strings with a prepended
- // size of 2.
- // 1:2 3:abc 3:def 3:555 1:1 3:abc 3:def 3:555 1:1
- //
- // The final result with a prepended version ("1:1") would be:
- // "1:11:23:abc3:def3:5551:13:abc3:def3:5551:1"
-
- private String serializeAllAccounts(List<PhoneAccount> allAccounts) {
- StringBuilder buffer = new StringBuilder();
-
- // Version
- serializeIntValue(VERSION, buffer);
-
- // Number of accounts
- serializeIntValue(allAccounts.size(), buffer);
-
- // The actual accounts
- for (int i = 0; i < allAccounts.size(); i++) {
- PhoneAccount account = allAccounts.get(i);
- serializeStringValue(account.getComponentName().flattenToShortString(), buffer);
- serializeStringValue(account.getId(), buffer);
- serializeStringValue(account.getHandle().toString(), buffer);
- serializeIntValue(account.getCapabilities(), buffer);
- }
-
- return buffer.toString();
- }
-
- private List<PhoneAccount> deserializeAllAccounts(String source) {
- List<PhoneAccount> accounts = new ArrayList<PhoneAccount>();
-
- if (source != null) {
- DeserializationToken token = new DeserializationToken(source);
- int version = deserializeIntValue(token);
- if (version == 1) {
- int size = deserializeIntValue(token);
-
- for (int i = 0; i < size; i++) {
- String strComponentName = deserializeStringValue(token);
- String strId = deserializeStringValue(token);
- String strHandle = deserializeStringValue(token);
- int capabilities = deserializeIntValue(token);
-
- accounts.add(new PhoneAccount(
- ComponentName.unflattenFromString(strComponentName),
- strId,
- Uri.parse(strHandle),
- capabilities));
- }
+ s.mAccounts.add(metadata);
+ // Search for duplicates and remove any that are found.
+ for (int i = 0; i < s.mAccounts.size() - 1; i++) {
+ if (Objects.equals(metadata.getAccount(), s.mAccounts.get(i).getAccount())) {
+ // replace existing entry.
+ s.mAccounts.remove(i);
+ break;
}
}
- return accounts;
+ write(s);
}
- private void serializeIntValue(int value, StringBuilder buffer) {
- serializeStringValue(String.valueOf(value), buffer);
+ public void unregisterPhoneAccount(PhoneAccount account) {
+ State s = read();
+
+ for (int i = 0; i < s.mAccounts.size(); i++) {
+ if (Objects.equals(account, s.mAccounts.get(i).getAccount())) {
+ s.mAccounts.remove(i);
+ break;
+ }
+ }
+
+ checkDefaultOutgoing(s);
+
+ write(s);
}
- private void serializeStringValue(String value, StringBuilder buffer) {
- buffer.append(value.length()).append(":").append(value);
+ public void clearAccounts(String packageName) {
+ State s = read();
+
+ for (int i = 0; i < s.mAccounts.size(); i++) {
+ if (Objects.equals(
+ packageName,
+ s.mAccounts.get(i).getAccount().getComponentName().getPackageName())) {
+ s.mAccounts.remove(i);
+ }
+ }
+
+ checkDefaultOutgoing(s);
+
+ write(s);
}
- private int deserializeIntValue(DeserializationToken token) {
- return Integer.parseInt(deserializeStringValue(token));
+ private void checkDefaultOutgoing(State s) {
+ // Check that, after an operation that removes accounts, the account set up as the "default
+ // outgoing" has not been deleted. If it has, then clear out the setting.
+ for (PhoneAccountMetadata m : s.mAccounts) {
+ if (Objects.equals(s.mDefaultOutgoing, m.getAccount())) {
+ return;
+ }
+ }
+ s.mDefaultOutgoing = null;
}
- private String deserializeStringValue(DeserializationToken token) {
- int colonIndex = token.source.indexOf(':', token.currentIndex);
- int valueLength = Integer.parseInt(token.source.substring(token.currentIndex, colonIndex));
- int endIndex = colonIndex + 1 + valueLength;
- token.currentIndex = endIndex;
- return token.source.substring(colonIndex + 1, endIndex);
+ private List<PhoneAccount> accountsOnly(State s) {
+ List<PhoneAccount> result = new ArrayList<>();
+ for (PhoneAccountMetadata m : s.mAccounts) {
+ result.add(m.getAccount());
+ }
+ return result;
+ }
+
+ private State read() {
+ try {
+ String serialized = getPreferences().getString(PREFERENCE_PHONE_ACCOUNTS, null);
+ Log.d(this, "read() obtained serialized state: %s", serialized);
+ State state = serialized == null
+ ? new State()
+ : deserializeState(serialized);
+ Log.d(this, "read() obtained state: %s", state);
+ return state;
+ } catch (Exception e) {
+ Log.e(this, e, "read");
+ throw new RuntimeException(e);
+ }
+ }
+
+ private boolean write(State state) {
+ try {
+ Log.d(this, "write() writing state: %s", state);
+ String serialized = serializeState(state);
+ Log.d(this, "write() writing serialized state: %s", serialized);
+ boolean success = getPreferences()
+ .edit()
+ .putString(PREFERENCE_PHONE_ACCOUNTS, serialized)
+ .commit();
+ Log.d(this, "serialized state was written with succcess = %b", success);
+ return success;
+ } catch (Exception e) {
+ Log.e(this, e, "write");
+ throw new RuntimeException(e);
+ }
}
private SharedPreferences getPreferences() {
return mContext.getSharedPreferences(TELECOMM_PREFERENCES, Context.MODE_PRIVATE);
}
+
+ private String serializeState(State s) throws JSONException {
+ // TODO: If this is used in production, remove the indent (=> do not pretty print)
+ return sStateJson.toJson(s).toString(2);
+ }
+
+ private State deserializeState(String s) throws JSONException {
+ return sStateJson.fromJson(new JSONObject(new JSONTokener(s)));
+ }
+
+ private static class State {
+ PhoneAccount mDefaultOutgoing = null;
+ final List<PhoneAccountMetadata> mAccounts = new ArrayList<>();
+ }
+
+ //
+ // JSON serialization
+ //
+
+ private interface Json<T> {
+ JSONObject toJson(T o) throws JSONException;
+ T fromJson(JSONObject json) throws JSONException;
+ }
+
+ private static final Json<State> sStateJson =
+ new Json<State>() {
+ private static final String DEFAULT_OUTGOING = "default_outgoing";
+ private static final String ACCOUNTS = "accounts";
+
+ @Override
+ public JSONObject toJson(State o) throws JSONException {
+ JSONObject json = new JSONObject();
+ if (o.mDefaultOutgoing != null) {
+ json.put(DEFAULT_OUTGOING, sPhoneAccountJson.toJson(o.mDefaultOutgoing));
+ }
+ JSONArray accounts = new JSONArray();
+ for (PhoneAccountMetadata m : o.mAccounts) {
+ accounts.put(sPhoneAccountMetadataJson.toJson(m));
+ }
+ json.put(ACCOUNTS, accounts);
+ return json;
+ }
+
+ @Override
+ public State fromJson(JSONObject json) throws JSONException {
+ State s = new State();
+ if (json.has(DEFAULT_OUTGOING)) {
+ s.mDefaultOutgoing = sPhoneAccountJson.fromJson(
+ (JSONObject) json.get(DEFAULT_OUTGOING));
+ }
+ if (json.has(ACCOUNTS)) {
+ JSONArray accounts = (JSONArray) json.get(ACCOUNTS);
+ for (int i = 0; i < accounts.length(); i++) {
+ try {
+ s.mAccounts.add(sPhoneAccountMetadataJson.fromJson(
+ (JSONObject) accounts.get(i)));
+ } catch (Exception e) {
+ Log.e(this, e, "Extracting phone account");
+ }
+ }
+ }
+ return s;
+ }
+ };
+
+ private static final Json<PhoneAccountMetadata> sPhoneAccountMetadataJson =
+ new Json<PhoneAccountMetadata>() {
+ private static final String ACCOUNT = "account";
+ private static final String HANDLE = "handle";
+ private static final String CAPABILITIES = "capabilities";
+ private static final String ICON_RES_ID = "icon_res_id";
+ private static final String LABEL = "label";
+ private static final String SHORT_DESCRIPTION = "short_description";
+ private static final String VIDEO_CALLING_SUPPORTED = "video_calling_supported";
+
+ @Override
+ public JSONObject toJson(PhoneAccountMetadata o) throws JSONException {
+ return new JSONObject()
+ .put(ACCOUNT, sPhoneAccountJson.toJson(o.getAccount()))
+ .put(HANDLE, o.getHandle().toString())
+ .put(CAPABILITIES, o.getCapabilities())
+ .put(ICON_RES_ID, o.getIconResId())
+ .put(LABEL, o.getLabel())
+ .put(SHORT_DESCRIPTION, o.getShortDescription())
+ .put(VIDEO_CALLING_SUPPORTED, (Boolean) o.isVideoCallingSupported());
+ }
+
+ @Override
+ public PhoneAccountMetadata fromJson(JSONObject json) throws JSONException {
+ return new PhoneAccountMetadata(
+ sPhoneAccountJson.fromJson((JSONObject) json.get(ACCOUNT)),
+ Uri.parse((String) json.get(HANDLE)),
+ (int) json.get(CAPABILITIES),
+ (int) json.get(ICON_RES_ID),
+ (String) json.get(LABEL),
+ (String) json.get(SHORT_DESCRIPTION),
+ (Boolean) json.get(VIDEO_CALLING_SUPPORTED));
+ }
+ };
+
+ private static final Json<PhoneAccount> sPhoneAccountJson =
+ new Json<PhoneAccount>() {
+ private static final String COMPONENT_NAME = "component_name";
+ private static final String ID = "id";
+
+ @Override
+ public JSONObject toJson(PhoneAccount o) throws JSONException {
+ return new JSONObject()
+ .put(COMPONENT_NAME, o.getComponentName().flattenToString())
+ .put(ID, o.getId());
+ }
+
+ @Override
+ public PhoneAccount fromJson(JSONObject json) throws JSONException {
+ return new PhoneAccount(
+ ComponentName.unflattenFromString((String) json.get(COMPONENT_NAME)),
+ (String) json.get(ID));
+ }
+ };
}
diff --git a/src/com/android/telecomm/TelecommApp.java b/src/com/android/telecomm/TelecommApp.java
index 2b2f160..b02a8f8 100644
--- a/src/com/android/telecomm/TelecommApp.java
+++ b/src/com/android/telecomm/TelecommApp.java
@@ -34,7 +34,7 @@
private MissedCallNotifier mMissedCallNotifier;
/**
- * Maintains the list of registered {@link PhoneAccount}s.
+ * Maintains the list of registered {@link android.telecomm.PhoneAccount}s.
*/
private PhoneAccountRegistrar mPhoneAccountRegistrar;
@@ -61,4 +61,8 @@
MissedCallNotifier getMissedCallNotifier() {
return mMissedCallNotifier;
}
+
+ PhoneAccountRegistrar getPhoneAccountRegistrar() {
+ return mPhoneAccountRegistrar;
+ }
}
diff --git a/src/com/android/telecomm/TelecommServiceImpl.java b/src/com/android/telecomm/TelecommServiceImpl.java
index fce9c04..a9bbf8e 100644
--- a/src/com/android/telecomm/TelecommServiceImpl.java
+++ b/src/com/android/telecomm/TelecommServiceImpl.java
@@ -147,38 +147,67 @@
//
@Override
+ public PhoneAccount getDefaultOutgoingPhoneAccount() {
+ try {
+ return mPhoneAccountRegistrar.getDefaultOutgoingPhoneAccount();
+ } catch (Exception e) {
+ Log.e(this, e, "getDefaultOutgoingPhoneAccount");
+ throw e;
+ }
+ }
+
+ @Override
public List<PhoneAccount> getEnabledPhoneAccounts() {
- return mPhoneAccountRegistrar.getEnabledAccounts();
+ try {
+ return mPhoneAccountRegistrar.getEnabledPhoneAccounts();
+ } catch (Exception e) {
+ Log.e(this, e, "getEnabledPhoneAccounts");
+ throw e;
+ }
}
@Override
public PhoneAccountMetadata getPhoneAccountMetadata(PhoneAccount account) {
- PhoneAccount registeredAccount = mPhoneAccountRegistrar.getRegisteredAccount(account);
- if (registeredAccount != null) {
- return new PhoneAccountMetadata(
- registeredAccount, 0, account.getComponentName().getPackageName(), null, false);
+ try {
+ return mPhoneAccountRegistrar.getPhoneAccountMetadata(account);
+ } catch (Exception e) {
+ Log.e(this, e, "getPhoneAccountMetadata %s", account);
+ throw e;
}
- return null;
}
@Override
- public void registerPhoneAccount(PhoneAccount account, PhoneAccountMetadata metadata) {
- enforceModifyPermissionOrCallingPackage(account.getComponentName().getPackageName());
- mPhoneAccountRegistrar.addAccount(account);
- // TODO(santoscordon): Implement metadata
+ public void registerPhoneAccount(PhoneAccountMetadata metadata) {
+ try {
+ enforceModifyPermissionOrCallingPackage(
+ metadata.getAccount().getComponentName().getPackageName());
+ mPhoneAccountRegistrar.registerPhoneAccount(metadata);
+ } catch (Exception e) {
+ Log.e(this, e, "registerPhoneAccount %s", metadata);
+ throw e;
+ }
}
@Override
public void unregisterPhoneAccount(PhoneAccount account) {
- enforceModifyPermissionOrCallingPackage(account.getComponentName().getPackageName());
- mPhoneAccountRegistrar.removeAccount(account);
+ try {
+ enforceModifyPermissionOrCallingPackage(account.getComponentName().getPackageName());
+ mPhoneAccountRegistrar.unregisterPhoneAccount(account);
+ } catch (Exception e) {
+ Log.e(this, e, "unregisterPhoneAccount %s", account);
+ throw e;
+ }
}
@Override
public void clearAccounts(String packageName) {
- enforceModifyPermissionOrCallingPackage(packageName);
- // TODO(santoscordon): Is this needed?
- Log.e(TAG, null, "Unexpected method call: clearAccounts()");
+ try {
+ enforceModifyPermissionOrCallingPackage(packageName);
+ mPhoneAccountRegistrar.clearAccounts(packageName);
+ } catch (Exception e) {
+ Log.e(this, e, "clearAccounts %s", packageName);
+ throw e;
+ }
}
/**
diff --git a/tests/src/com/android/telecomm/testapps/CallNotificationReceiver.java b/tests/src/com/android/telecomm/testapps/CallNotificationReceiver.java
index 098b065..7002354 100644
--- a/tests/src/com/android/telecomm/testapps/CallNotificationReceiver.java
+++ b/tests/src/com/android/telecomm/testapps/CallNotificationReceiver.java
@@ -22,6 +22,7 @@
import android.content.Intent;
import android.os.Bundle;
import android.telecomm.PhoneAccount;
+import android.telecomm.PhoneAccountMetadata;
import android.telecomm.TelecommConstants;
/**
@@ -76,9 +77,7 @@
PhoneAccount phoneAccount = new PhoneAccount(
new ComponentName(context, TestConnectionService.class),
- null /* id */,
- null /* handle */,
- PhoneAccount.CAPABILITY_CALL_PROVIDER);
+ null /* id */);
intent.putExtra(TelecommConstants.EXTRA_PHONE_ACCOUNT, phoneAccount);
// For the purposes of testing, indicate whether the incoming call is a video call by
diff --git a/tests/src/com/android/telecomm/testapps/CallServiceNotifier.java b/tests/src/com/android/telecomm/testapps/CallServiceNotifier.java
index c08f6eb..9724ef8 100644
--- a/tests/src/com/android/telecomm/testapps/CallServiceNotifier.java
+++ b/tests/src/com/android/telecomm/testapps/CallServiceNotifier.java
@@ -23,10 +23,8 @@
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
-import android.os.Bundle;
import android.telecomm.PhoneAccount;
import android.telecomm.PhoneAccountMetadata;
-import android.telecomm.TelecommConstants;
import android.telecomm.TelecommManager;
import android.util.Log;
import android.widget.Toast;
@@ -88,17 +86,19 @@
* Registers a phone account with telecomm.
*/
public void registerPhoneAccount(Context context) {
- PhoneAccount phoneAccount = new PhoneAccount(
- new ComponentName(context, TestConnectionService.class),
- "testapps_TestConnectionService_Account_ID",
+ PhoneAccountMetadata metadata = new PhoneAccountMetadata(
+ new PhoneAccount(
+ new ComponentName(context, TestConnectionService.class),
+ "testapps_TestConnectionService_Account_ID"),
Uri.parse("tel:555-TEST"),
- PhoneAccount.CAPABILITY_CALL_PROVIDER);
- PhoneAccountMetadata metadata = new PhoneAccountMetadata(phoneAccount, 0, null, null,
+ PhoneAccountMetadata.CAPABILITY_CALL_PROVIDER,
+ 0, // iconResId
+ "a label",
+ "a short description",
false);
-
TelecommManager telecommManager =
(TelecommManager) context.getSystemService(Context.TELECOMM_SERVICE);
- telecommManager.registerPhoneAccount(phoneAccount, metadata);
+ telecommManager.registerPhoneAccount(metadata);
}
/**