am baee2955: Allowing enable/disable of phone accounts. (3/3)
* commit 'baee2955f596f7b79971feb12fa21031a069677d':
Allowing enable/disable of phone accounts. (3/3)
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index f668255..dd9b06d 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -436,6 +436,14 @@
</intent-filter>
</activity>
+ <activity android:name=".settings.PhoneAccountSelectionPreferenceActivity"
+ android:label="@string/phone_accounts"
+ android:theme="@style/DialerSettingsLight">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ </intent-filter>
+ </activity>
+
<!-- bluetooth phone service -->
<service android:name="BluetoothPhoneService">
<intent-filter>
@@ -489,7 +497,6 @@
<intent-filter>
<action android:name="android.net.sip.SIP_SERVICE_UP" />
<action android:name="com.android.phone.SIP_INCOMING_CALL" />
- <action android:name="com.android.phone.SIP_ADD_PHONE" />
<action android:name="com.android.phone.SIP_REMOVE_PHONE" />
<action android:name="com.android.phone.SIP_CALL_OPTION_CHANGED" />
</intent-filter>
diff --git a/res/xml/phone_account_selection.xml b/res/xml/phone_account_selection.xml
new file mode 100644
index 0000000..9c5995c
--- /dev/null
+++ b/res/xml/phone_account_selection.xml
@@ -0,0 +1,24 @@
+<?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
+ -->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+ <PreferenceCategory
+ android:key="phone_accounts_list"
+ android:title="@string/phone_accounts_selection_header"
+ android:persistent="true" />
+</PreferenceScreen>
\ No newline at end of file
diff --git a/res/xml/phone_account_selection_activity.xml b/res/xml/phone_account_selection_activity.xml
new file mode 100644
index 0000000..9425297
--- /dev/null
+++ b/res/xml/phone_account_selection_activity.xml
@@ -0,0 +1,23 @@
+<?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
+ -->
+
+<preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
+ <header
+ android:fragment="com.android.phone.settings.PhoneAccountSelectionPreferenceActivity$PhoneAccountSelectionPreferenceFragment"
+ android:title="@string/phone_accounts" />
+</preference-headers>
\ No newline at end of file
diff --git a/sip/res/values/strings.xml b/sip/res/values/strings.xml
index 8b85ff4..0163a31 100644
--- a/sip/res/values/strings.xml
+++ b/sip/res/values/strings.xml
@@ -86,8 +86,6 @@
<!-- Title of the button to show in a alert dialog. [CHAR LIMIT=NONE] -->
<string name="close_profile">Close</string>
- <!-- Summary of a SIP account in the list of SIP accounts, consists of primary account status and registration status. This string indicates that this SIP account is a primary account and the string placeholder is the registration status, which will be one of the strings with name starting with "registration_status_" below. [CHAR LIMIT=NONE] -->
- <string name="primary_account_summary_with">Primary account. <xliff:g id="registration_status" example="Registering...">%s</xliff:g></string>
<!-- Text of SIP-call registration status, checking current registration status with SIP service [CHAR LIMIT=NONE] -->
<string name="registration_status_checking_status">Checking status...</string>
<!-- Text of SIP-call registration status, registering with SIP server in order to receive calls on this account [CHAR LIMIT=NONE] -->
@@ -135,10 +133,6 @@
<string name="transport_title">Transport type</string>
<!-- Text of the keepalive preference. [CHAR LIMIT=NONE] -->
<string name="send_keepalive_title">Send keep-alive</string>
- <!-- Text of the set-primary preference. Simplified from "Make this my primary account". [CHAR LIMIT=NONE] -->
- <string name="set_primary_title">Set as primary account</string>
- <!-- Text of the set-primary preference summary. [CHAR LIMIT=NONE] -->
- <string name="set_primary_summary">Used for outbound calls</string>
<!-- Text of the advanced settings section. [CHAR LIMIT=NONE] -->
<string name="advanced_settings">Optional settings</string>
<!-- Text of the username used in authentication. [CHAR LIMIT=NONE] -->
@@ -198,7 +192,6 @@
<string translatable="false" name="port">Port</string>
<string translatable="false" name="transport">Protocol</string>
<string translatable="false" name="send_keepalive">SendKeepAlive</string>
- <string translatable="false" name="set_primary">SetPrimary</string>
<string translatable="false" name="advanced_settings_container">advanced settings container</string>
<string translatable="false" name="auth_username">AuthUserName</string>
diff --git a/sip/res/xml/sip_edit.xml b/sip/res/xml/sip_edit.xml
index f091fc1..15e5ce1 100644
--- a/sip/res/xml/sip_edit.xml
+++ b/sip/res/xml/sip_edit.xml
@@ -45,12 +45,6 @@
android:singleLine="true"
android:inputType="textNoSuggestions"/>
- <CheckBoxPreference
- android:key="@string/set_primary"
- android:title="@string/set_primary_title"
- android:persistent="false"
- android:summary="@string/set_primary_summary"/>
-
<PreferenceScreen
android:key="@string/advanced_settings"
android:title="@string/advanced_settings"
diff --git a/sip/src/com/android/services/telephony/sip/SipAccountRegistry.java b/sip/src/com/android/services/telephony/sip/SipAccountRegistry.java
index 6149231..b00acba 100644
--- a/sip/src/com/android/services/telephony/sip/SipAccountRegistry.java
+++ b/sip/src/com/android/services/telephony/sip/SipAccountRegistry.java
@@ -16,21 +16,15 @@
package com.android.services.telephony.sip;
-import android.content.ComponentName;
import android.content.Context;
-import android.net.Uri;
import android.net.sip.SipException;
import android.net.sip.SipManager;
import android.net.sip.SipProfile;
-import android.provider.Settings;
import android.telecomm.PhoneAccount;
import android.telecomm.PhoneAccountHandle;
import android.telecomm.TelecommManager;
import android.util.Log;
-import com.android.phone.R;
-
-import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -50,41 +44,58 @@
return mProfile;
}
- boolean register(SipManager sipManager, Context context) {
- if (VERBOSE) log("register, profile: " + mProfile);
+ /**
+ * Starts the SIP service associated with the SIP profile.
+ *
+ * @param sipManager The SIP manager.
+ * @param context The context.
+ * @param isReceivingCalls {@code True} if the sip service is being started to make and
+ * receive calls. {@code False} if the sip service is being started only for
+ * outgoing calls.
+ * @return {@code True} if the service started successfully.
+ */
+ boolean startSipService(SipManager sipManager, Context context, boolean isReceivingCalls) {
+ if (VERBOSE) log("startSipService, profile: " + mProfile);
try {
- sipManager.open(
- mProfile,
- SipUtil.createIncomingCallPendingIntent(context, mProfile.getUriString()),
- null);
- TelecommManager.from(context).registerPhoneAccount(createPhoneAccount(context));
+ // Stop the Sip service for the profile if it is already running. This is important
+ // if we are changing the state of the "receive calls" option.
+ sipManager.close(mProfile.getUriString());
+
+ // Start the sip service for the profile.
+ if (isReceivingCalls) {
+ sipManager.open(
+ mProfile,
+ SipUtil.createIncomingCallPendingIntent(context,
+ mProfile.getUriString()),
+ null);
+ } else {
+ sipManager.open(mProfile);
+ }
return true;
} catch (SipException e) {
- log("register, profile: " + mProfile.getProfileName() +
+ log("startSipService, profile: " + mProfile.getProfileName() +
", exception: " + e);
}
return false;
}
- private PhoneAccount createPhoneAccount(Context context) {
- boolean useSipForPstnCalls = useSipForPstnCalls(context);
-
- PhoneAccountHandle accountHandle =
- SipUtil.createAccountHandle(context, mProfile.getUriString());
- List supportedUriSchemes = Arrays.asList(PhoneAccount.SCHEME_SIP);
- if (useSipForPstnCalls) {
- supportedUriSchemes.add(PhoneAccount.SCHEME_TEL);
+ /**
+ * Stops the SIP service associated with the SIP profile. The {@code SipAccountRegistry} is
+ * informed when the service has been stopped via an intent which triggers
+ * {@link SipAccountRegistry#removeSipProfile(String)}.
+ *
+ * @param sipManager The SIP manager.
+ * @return {@code True} if stop was successful.
+ */
+ boolean stopSipService(SipManager sipManager) {
+ try {
+ sipManager.close(mProfile.getUriString());
+ return true;
+ } catch (Exception e) {
+ log("stopSipService, stop failed for profile: " + mProfile.getUriString() +
+ ", exception: " + e);
}
-
- PhoneAccount.Builder builder = PhoneAccount.builder(
- accountHandle, mProfile.getDisplayName())
- .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
- .setAddress(Uri.parse(mProfile.getUriString()))
- .setShortDescription(mProfile.getDisplayName())
- .setIconResId(R.drawable.ic_dialer_sip_black_24dp)
- .setSupportedUriSchemes(supportedUriSchemes);
-
- return builder.build();
+ return false;
}
}
@@ -101,84 +112,174 @@
}
void setup(Context context) {
- clearCurrentSipAccounts(context);
- registerProfiles(context, null);
+ startSipProfilesAsync((Context) context, (String) null);
}
- void addPhone(Context context, String sipUri) {
- registerProfiles(context, sipUri);
+ /**
+ * Starts the SIP service for the specified SIP profile and ensures it has a valid registered
+ * {@link PhoneAccount}.
+ *
+ * @param context The context.
+ * @param sipUri The Uri of the {@link SipProfile} to start, or {@code null} for all.
+ */
+ void startSipService(Context context, String sipUri) {
+ startSipProfilesAsync((Context) context, (String) sipUri);
}
- void removePhone(Context context, String sipUri) {
- for (AccountEntry entry : mAccounts) {
- if (Objects.equals(sipUri, entry.getProfile().getUriString())) {
- TelecommManager.from(context).unregisterPhoneAccount(
- SipUtil.createAccountHandle(context, sipUri));
- mAccounts.remove(entry);
- break;
- }
+ /**
+ * Removes a {@link SipProfile} from the account registry. Does not stop/close the associated
+ * SIP service (this method is invoked via an intent from the SipService once a profile has
+ * been stopped/closed).
+ *
+ * @param sipUri The Uri of the {@link SipProfile} to remove from the registry.
+ */
+ void removeSipProfile(String sipUri) {
+ AccountEntry accountEntry = getAccountEntry(sipUri);
+
+ if (accountEntry != null) {
+ mAccounts.remove(accountEntry);
}
}
/**
+ * Stops a SIP profile and un-registers its associated {@link android.telecomm.PhoneAccount}.
+ * Called after a SIP profile is deleted. The {@link AccountEntry} will be removed when the
+ * service has been stopped. The {@code SipService} fires the {@code ACTION_SIP_REMOVE_PHONE}
+ * intent, which triggers {@link SipAccountRegistry#removeSipProfile(String)} to perform the
+ * removal.
+ *
+ * @param context The context.
+ * @param sipUri The {@code Uri} of the sip profile.
+ */
+ void stopSipService(Context context, String sipUri) {
+ // Stop the sip service for the profile.
+ AccountEntry accountEntry = getAccountEntry(sipUri);
+ if (accountEntry != null ) {
+ SipManager sipManager = SipManager.newInstance(context);
+ accountEntry.stopSipService(sipManager);
+ }
+
+ // Un-register its PhoneAccount.
+ PhoneAccountHandle handle = SipUtil.createAccountHandle(context, sipUri);
+ TelecommManager.from(context).unregisterPhoneAccount(handle);
+ }
+
+ /**
+ * Causes the SIP service to be restarted for all {@link SipProfile}s. For example, if the user
+ * toggles the "receive calls" option for SIP, this method handles restarting the SIP services
+ * in the new mode.
+ *
+ * @param context The context.
+ */
+ void restartSipService(Context context) {
+ startSipProfiles(context, null);
+ }
+
+ /**
+ * Performs an asynchronous call to
+ * {@link SipAccountRegistry#startSipProfiles(android.content.Context, String)}, starting the
+ * specified SIP profile and registering its {@link android.telecomm.PhoneAccount}.
+ *
+ * @param context The context.
+ * @param sipUri A specific SIP uri to start.
+ */
+ private void startSipProfilesAsync(final Context context, final String sipUri) {
+ if (VERBOSE) log("startSipProfiles, start auto registration");
+
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ startSipProfiles(context, sipUri);
+ }}
+ ).start();
+ }
+
+ /**
* Loops through all SIP accounts from the SIP database, starts each service and registers
* each with the telecomm framework. If a specific sipUri is specified, this will only register
* the associated SIP account.
*
+ * Also handles migration from using the primary account shared preference to indicate the
+ * {@link SipProfile} to be used for outgoing Sip connections to using the enabled flag on
+ * {@link android.telecomm.PhoneAccount}s to indicate which profiles can be used for outgoing
+ * or ingoing calls.
+ *
* @param context The context.
- * @param sipUri A specific SIP uri to register.
+ * @param sipUri A specific SIP uri to start, or {@code null} to start all.
*/
- private void registerProfiles(final Context context, final String sipUri) {
- if (VERBOSE) log("registerProfiles, start auto registration");
+ private void startSipProfiles(Context context, String sipUri) {
final SipSharedPreferences sipSharedPreferences = new SipSharedPreferences(context);
- new Thread(new Runnable() {
- @Override
- public void run() {
- SipManager sipManager = SipManager.newInstance(context);
- SipProfileDb profileDb = new SipProfileDb(context);
- String primaryProfile = sipSharedPreferences.getPrimaryAccount();
- List<SipProfile> sipProfileList = profileDb.retrieveSipProfileList();
-
- for (SipProfile profile : sipProfileList) {
- boolean isPrimaryProfile = profile.getUriString().equals(primaryProfile);
- if (profile.getAutoRegistration() || isPrimaryProfile) {
- if (sipUri == null || Objects.equals(sipUri, profile.getUriString())) {
- registerAccountForProfile(profile, sipManager, context);
- }
- }
- }
- }}
- ).start();
- }
-
- private void registerAccountForProfile(
- SipProfile profile, SipManager sipManager, Context context) {
- AccountEntry entry = new AccountEntry(profile);
-
- if (entry.register(sipManager, context)) {
- mAccounts.add(entry);
- }
- }
-
- private void clearCurrentSipAccounts(Context context) {
- ComponentName sipComponentName = new ComponentName(context, SipConnectionService.class);
+ boolean isReceivingCalls = sipSharedPreferences.isReceivingCallsEnabled();
+ String primaryProfile = sipSharedPreferences.getPrimaryAccount();
TelecommManager telecommManager = TelecommManager.from(context);
- List<PhoneAccountHandle> accountHandles = telecommManager.getEnabledPhoneAccounts();
- for (PhoneAccountHandle handle : accountHandles) {
- if (sipComponentName.equals(handle.getComponentName())) {
- telecommManager.unregisterPhoneAccount(handle);
+ SipManager sipManager = SipManager.newInstance(context);
+ SipProfileDb profileDb = new SipProfileDb(context);
+ List<SipProfile> sipProfileList = profileDb.retrieveSipProfileList();
+
+ for (SipProfile profile : sipProfileList) {
+ // Register a PhoneAccount for the profile and optionally enable the primary
+ // profile.
+ if (sipUri == null || Objects.equals(sipUri, profile.getUriString())) {
+ PhoneAccount phoneAccount = SipUtil.createPhoneAccount(context, profile);
+ telecommManager.registerPhoneAccount(phoneAccount);
+
+ // If this profile was the primary profile in the past, mark it as enabled.
+ boolean isPrimaryProfile = primaryProfile != null &&
+ profile.getUriString().equals(primaryProfile);
+ if (isPrimaryProfile) {
+ telecommManager.setPhoneAccountEnabled(
+ phoneAccount.getAccountHandle(), true);
+ }
}
+
+ // Start the SIP service for the profile.
+ if (SipUtil.isPhoneAccountEnabled(context, profile)) {
+ if (sipUri == null || Objects.equals(sipUri, profile.getUriString())) {
+ startSipServiceForProfile(profile, sipManager, context, isReceivingCalls);
+ }
+ }
+ }
+
+ if (primaryProfile != null) {
+ // Remove the primary account shared preference, ensuring the migration does not
+ // occur again in the future.
+ sipSharedPreferences.cleanupPrimaryAccountSetting();
}
}
/**
- * Determines if the user has chosen to use SIP for PSTN calls as well as SIP calls.
+ * Starts the SIP service for a sip profile and saves a new {@code AccountEntry} in the
+ * registry.
+ *
+ * @param profile The {@link SipProfile} to start.
+ * @param sipManager The SIP manager.
* @param context The context.
- * @return {@code True} if SIP should be used for PSTN calls.
+ * @param isReceivingCalls {@code True} if the profile should be started such that it can
+ * receive incoming calls.
*/
- private boolean useSipForPstnCalls(Context context) {
- final SipSharedPreferences sipSharedPreferences = new SipSharedPreferences(context);
- return sipSharedPreferences.getSipCallOption().equals(Settings.System.SIP_ALWAYS);
+ private void startSipServiceForProfile(SipProfile profile, SipManager sipManager,
+ Context context, boolean isReceivingCalls) {
+ removeSipProfile(profile.getUriString());
+
+ AccountEntry entry = new AccountEntry(profile);
+ if (entry.startSipService(sipManager, context, isReceivingCalls)) {
+ mAccounts.add(entry);
+ }
+ }
+
+ /**
+ * Retrieves the {@link AccountEntry} from the registry with the specified Uri.
+ *
+ * @param sipUri The Uri of the profile to retrieve.
+ * @return The {@link AccountEntry}, or {@code null} is it was not found.
+ */
+ private AccountEntry getAccountEntry(String sipUri) {
+ for (AccountEntry entry : mAccounts) {
+ if (Objects.equals(sipUri, entry.getProfile().getUriString())) {
+ return entry;
+ }
+ }
+ return null;
}
private void log(String message) {
diff --git a/sip/src/com/android/services/telephony/sip/SipBroadcastReceiver.java b/sip/src/com/android/services/telephony/sip/SipBroadcastReceiver.java
index a113805..35c07a1 100644
--- a/sip/src/com/android/services/telephony/sip/SipBroadcastReceiver.java
+++ b/sip/src/com/android/services/telephony/sip/SipBroadcastReceiver.java
@@ -47,14 +47,10 @@
} else if (action.equals(SipManager.ACTION_SIP_SERVICE_UP) ||
action.equals(SipManager.ACTION_SIP_CALL_OPTION_CHANGED)) {
sipAccountRegistry.setup(context);
- } else if (action.equals(SipManager.ACTION_SIP_ADD_PHONE)) {
- if (VERBOSE) log("SIP_ADD_PHONE " + intent.getStringExtra(SipManager.EXTRA_LOCAL_URI));
- sipAccountRegistry.addPhone(context, intent.getStringExtra(SipManager.EXTRA_LOCAL_URI));
} else if (action.equals(SipManager.ACTION_SIP_REMOVE_PHONE)) {
if (VERBOSE) log("SIP_REMOVE_PHONE " +
- intent.getStringExtra(SipManager.EXTRA_LOCAL_URI));
- sipAccountRegistry.removePhone(
- context, intent.getStringExtra(SipManager.EXTRA_LOCAL_URI));
+ intent.getStringExtra(SipManager.EXTRA_LOCAL_URI));
+ sipAccountRegistry.removeSipProfile(intent.getStringExtra(SipManager.EXTRA_LOCAL_URI));
} else {
if (VERBOSE) log("onReceive, action not processed: " + action);
}
diff --git a/sip/src/com/android/services/telephony/sip/SipConnectionService.java b/sip/src/com/android/services/telephony/sip/SipConnectionService.java
index 8956454..16efc4d 100644
--- a/sip/src/com/android/services/telephony/sip/SipConnectionService.java
+++ b/sip/src/com/android/services/telephony/sip/SipConnectionService.java
@@ -61,12 +61,6 @@
super.onCreate();
}
- static PhoneAccountHandle getPhoneAccountHandle(Context context) {
- return new PhoneAccountHandle(
- new ComponentName(context, SipConnectionService.class),
- null /* id */);
- }
-
@Override
public Connection onCreateOutgoingConnection(
PhoneAccountHandle connectionManagerAccount,
@@ -86,7 +80,6 @@
DisconnectCause.OUTGOING_FAILURE, "Did not match service connection");
}
-
final SipConnection connection = new SipConnection();
connection.setHandle(request.getAddress(), TelecommManager.PRESENTATION_ALLOWED);
connection.setInitializing();
diff --git a/sip/src/com/android/services/telephony/sip/SipEditor.java b/sip/src/com/android/services/telephony/sip/SipEditor.java
index b35f28c..fbf3bd1 100644
--- a/sip/src/com/android/services/telephony/sip/SipEditor.java
+++ b/sip/src/com/android/services/telephony/sip/SipEditor.java
@@ -16,11 +16,6 @@
package com.android.services.telephony.sip;
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.PhoneConstants;
-import com.android.services.telephony.sip.SipUtil;
-
-import android.app.ActionBar;
import android.app.AlertDialog;
import android.content.Intent;
import android.net.sip.SipManager;
@@ -38,7 +33,6 @@
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
-import android.view.View;
import android.widget.Button;
import android.widget.Toast;
@@ -63,18 +57,16 @@
private static final char SCRAMBLED = '*';
private static final int NA = 0;
- private PrimaryAccountSelector mPrimaryAccountSelector;
private AdvancedSettings mAdvancedSettings;
private SipSharedPreferences mSharedPreferences;
private boolean mDisplayNameSet;
private boolean mHomeButtonClicked;
private boolean mUpdateRequired;
- private boolean mUpdatedFieldIsEmpty;
- private SipManager mSipManager;
private SipProfileDb mProfileDb;
private SipProfile mOldProfile;
private Button mRemoveButton;
+ private SipAccountRegistry mSipAccountRegistry;
enum PreferenceKey {
Username(R.string.username, 0, R.string.default_preference_summary),
@@ -159,9 +151,9 @@
if (VERBOSE) log("onCreate, start profile editor");
super.onCreate(savedInstanceState);
- mSipManager = SipManager.newInstance(this);
mSharedPreferences = new SipSharedPreferences(this);
mProfileDb = new SipProfileDb(this);
+ mSipAccountRegistry = SipAccountRegistry.getInstance();
setContentView(R.layout.sip_settings_ui);
addPreferencesFromResource(R.xml.sip_edit);
@@ -180,7 +172,6 @@
}
mAdvancedSettings = new AdvancedSettings();
- mPrimaryAccountSelector = new PrimaryAccountSelector(p);
loadPreferencesFromProfile(p);
}
@@ -244,32 +235,29 @@
return super.onKeyDown(keyCode, event);
}
+ /**
+ * Saves a {@link SipProfile} and registers the associated
+ * {@link android.telecomm.PhoneAccount}.
+ *
+ * @param p The {@link SipProfile} to register.
+ * @throws IOException Exception resulting from profile save.
+ */
private void saveAndRegisterProfile(SipProfile p) throws IOException {
if (p == null) return;
mProfileDb.saveProfile(p);
- if (p.getAutoRegistration() || mSharedPreferences.isPrimaryAccount(p.getUriString())) {
- try {
- mSipManager.open(
- p, SipUtil.createIncomingCallPendingIntent(this, p.getUriString()), null);
- } catch (Exception e) {
- log("saveAndRegisterProfile, register failed for profile: " + p.getUriString() +
- ", exception: " + e);
- }
- }
+ mSipAccountRegistry.startSipService(this, p.getUriString());
}
+ /**
+ * Deletes a {@link SipProfile} and un-registers the associated
+ * {@link android.telecomm.PhoneAccount}.
+ *
+ * @param p The {@link SipProfile} to delete.
+ */
private void deleteAndUnregisterProfile(SipProfile p) {
if (p == null) return;
mProfileDb.deleteProfile(p);
- unregisterProfile(p.getUriString());
- }
-
- private void unregisterProfile(String uri) {
- try {
- mSipManager.close(uri);
- } catch (Exception e) {
- log("unregisterProfile, unregister failed for profile: " + uri + ", exception: " + e);
- }
+ mSipAccountRegistry.stopSipService(this, p.getUriString());
}
private void setRemovedProfileAndFinish() {
@@ -371,15 +359,6 @@
}
}
- private void unregisterOldPrimaryAccount() {
- String primaryAccountUri = mSharedPreferences.getPrimaryAccount();
- if (VERBOSE) log("unregisterOldPrimaryAccount, old primary: " + primaryAccountUri);
- if ((primaryAccountUri != null) && !mSharedPreferences.isReceivingCallsEnabled()) {
- if (VERBOSE) log("unregisterOldPrimaryAccount, calling unregister");
- unregisterProfile(primaryAccountUri);
- }
- }
-
private void replaceProfile(final SipProfile oldProfile, final SipProfile newProfile) {
// Replace profile in a background thread as it takes time to access the
// storage; do finish() once everything goes fine.
@@ -388,12 +367,6 @@
new Thread(new Runnable() {
public void run() {
try {
- // if new profile is primary, unregister the old primary account
- if ((newProfile != null) && mPrimaryAccountSelector.isSelected()) {
- unregisterOldPrimaryAccount();
- }
-
- mPrimaryAccountSelector.commit(newProfile);
deleteAndUnregisterProfile(oldProfile);
saveAndRegisterProfile(newProfile);
finish();
@@ -430,10 +403,8 @@
public boolean onPreferenceChange(Preference pref, Object newValue) {
if (!mUpdateRequired) {
mUpdateRequired = true;
- if (mOldProfile != null) {
- unregisterProfile(mOldProfile.getUriString());
- }
}
+
if (pref instanceof CheckBoxPreference) {
invalidateOptionsMenu();
return true;
@@ -547,47 +518,6 @@
return new String(cc);
}
- // only takes care of the primary account setting in SipSharedSettings
- private class PrimaryAccountSelector {
- private CheckBoxPreference mCheckbox;
- private final boolean mWasPrimaryAccount;
-
- // @param profile profile to be edited; null if adding new profile
- PrimaryAccountSelector(SipProfile profile) {
- mCheckbox = (CheckBoxPreference) getPreferenceScreen()
- .findPreference(getString(R.string.set_primary));
- boolean noPrimaryAccountSet = !mSharedPreferences.hasPrimaryAccount();
- boolean editNewProfile = (profile == null);
- mWasPrimaryAccount = !editNewProfile && mSharedPreferences.isPrimaryAccount(
- profile.getUriString());
-
- if (VERBOSE) {
- log(" noPrimaryAccountSet: " + noPrimaryAccountSet);
- log(" editNewProfile: " + editNewProfile);
- log(" mWasPrimaryAccount: " + mWasPrimaryAccount);
- }
-
- mCheckbox.setChecked(mWasPrimaryAccount || (editNewProfile && noPrimaryAccountSet));
- }
-
- boolean isSelected() {
- return mCheckbox.isChecked();
- }
-
- // profile is null if the user removes it
- void commit(SipProfile profile) {
- if ((profile != null) && mCheckbox.isChecked()) {
- mSharedPreferences.setPrimaryAccount(profile.getUriString());
- } else if (mWasPrimaryAccount) {
- mSharedPreferences.unsetPrimaryAccount();
- }
- if (VERBOSE) {
- log("PrimaryAccountSelector.commit, new primary account: " +
- mSharedPreferences.getPrimaryAccount());
- }
- }
- }
-
private class AdvancedSettings implements Preference.OnPreferenceClickListener {
private Preference mAdvancedSettingsTrigger;
private Preference[] mPreferences;
diff --git a/sip/src/com/android/services/telephony/sip/SipSettings.java b/sip/src/com/android/services/telephony/sip/SipSettings.java
index f6e6101..1dca310 100644
--- a/sip/src/com/android/services/telephony/sip/SipSettings.java
+++ b/sip/src/com/android/services/telephony/sip/SipSettings.java
@@ -39,6 +39,8 @@
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceActivity;
import android.preference.PreferenceCategory;
+import android.telecomm.PhoneAccount;
+import android.telecomm.TelecommManager;
import android.text.TextUtils;
import android.util.Log;
import android.view.Menu;
@@ -104,13 +106,9 @@
void updateSummary(String registrationStatus) {
int profileUid = mProfile.getCallingUid();
- boolean isPrimary = mProfile.getUriString().equals(
- mSipSharedPreferences.getPrimaryAccount());
if (VERBOSE) {
log("SipPreference.updateSummary, profile uid: " + profileUid +
- " isPrimary: " + isPrimary +
" registration: " + registrationStatus +
- " Primary: " + mSipSharedPreferences.getPrimaryAccount() +
" status: " + registrationStatus);
}
String summary = "";
@@ -118,9 +116,6 @@
// from third party apps
summary = getString(R.string.third_party_account_summary,
getPackageNameFromUid(profileUid));
- } else if (isPrimary) {
- summary = getString(R.string.primary_account_summary_with,
- registrationStatus);
} else {
summary = registrationStatus;
}
@@ -219,36 +214,35 @@
});
}
- private synchronized void handleSipReceiveCallsOption(boolean enabled) {
- mSipSharedPreferences.setReceivingCallsEnabled(enabled);
+ /**
+ * Handles changes to the "receive calls" option.
+ *
+ * @param isReceivingCalls {@code True} if receiving incoming SIP calls.
+ */
+ private synchronized void handleSipReceiveCallsOption(boolean isReceivingCalls) {
+ mSipSharedPreferences.setReceivingCallsEnabled(isReceivingCalls);
+
+ // Mark all profiles as auto-register if we are now receiving calls.
List<SipProfile> sipProfileList = mProfileDb.retrieveSipProfileList();
for (SipProfile p : sipProfileList) {
- String sipUri = p.getUriString();
- p = updateAutoRegistrationFlag(p, enabled);
- try {
- if (enabled) {
- mSipManager.open(
- p, SipUtil.createIncomingCallPendingIntent(this, sipUri), null);
- } else {
- mSipManager.close(sipUri);
- if (mSipSharedPreferences.isPrimaryAccount(sipUri)) {
- // re-open in order to make calls
- mSipManager.open(p);
- }
- }
- } catch (Exception e) {
- log("handleSipReceiveCallsOption, register failed: " + e);
- }
+ p = updateAutoRegistrationFlag(p, isReceivingCalls);
}
+
+ // Restart all Sip services to ensure we reflect whether we are receiving calls.
+ SipAccountRegistry sipAccountRegistry = SipAccountRegistry.getInstance();
+ sipAccountRegistry.restartSipService(this);
+
updateProfilesStatus();
}
- private SipProfile updateAutoRegistrationFlag(
- SipProfile p, boolean enabled) {
+ private SipProfile updateAutoRegistrationFlag(SipProfile p, boolean enabled) {
SipProfile newProfile = new SipProfile.Builder(p)
.setAutoRegistration(enabled)
.build();
try {
+ // Note: The profile is updated, but the associated PhoneAccount is left alone since
+ // the only thing that changed is the auto-registration flag, which is not part of the
+ // PhoneAccount.
mProfileDb.deleteProfile(p);
mProfileDb.saveProfile(newProfile);
} catch (Exception e) {
diff --git a/sip/src/com/android/services/telephony/sip/SipSharedPreferences.java b/sip/src/com/android/services/telephony/sip/SipSharedPreferences.java
index b5d1fc2..bad7dd5 100644
--- a/sip/src/com/android/services/telephony/sip/SipSharedPreferences.java
+++ b/sip/src/com/android/services/telephony/sip/SipSharedPreferences.java
@@ -16,14 +16,12 @@
package com.android.services.telephony.sip;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.sip.SipManager;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
-import android.text.TextUtils;
import android.util.Log;
/**
@@ -34,7 +32,13 @@
private static final boolean VERBOSE = false; /* STOP SHIP if true */
private static final String SIP_SHARED_PREFERENCES = "SIP_PREFERENCES";
+
+ /**
+ * @deprecated Primary account selection for SIP accounts is no longer relevant.
+ */
+ @Deprecated
private static final String KEY_PRIMARY_ACCOUNT = "primary";
+
private static final String KEY_NUMBER_OF_PROFILES = "profiles";
private SharedPreferences mPreferences;
@@ -46,31 +50,15 @@
mContext = context;
}
- public void setPrimaryAccount(String accountUri) {
- SharedPreferences.Editor editor = mPreferences.edit();
- editor.putString(KEY_PRIMARY_ACCOUNT, accountUri);
- editor.apply();
- }
-
- public void unsetPrimaryAccount() {
- setPrimaryAccount(null);
- }
-
- /** Returns the primary account URI or null if it does not exist. */
+ /**
+ * Returns the primary account URI or null if it does not exist.
+ * @deprecated The primary account setting is no longer used.
+ */
+ @Deprecated
public String getPrimaryAccount() {
return mPreferences.getString(KEY_PRIMARY_ACCOUNT, null);
}
- public boolean isPrimaryAccount(String accountUri) {
- return accountUri.equals(
- mPreferences.getString(KEY_PRIMARY_ACCOUNT, null));
- }
-
- public boolean hasPrimaryAccount() {
- return !TextUtils.isEmpty(
- mPreferences.getString(KEY_PRIMARY_ACCOUNT, null));
- }
-
public void setProfilesCount(int number) {
SharedPreferences.Editor editor = mPreferences.edit();
editor.putInt(KEY_NUMBER_OF_PROFILES, number);
@@ -114,6 +102,18 @@
}
}
+ /**
+ * Performs cleanup of the shared preferences, removing the deprecated primary account key if
+ * it exists.
+ */
+ public void cleanupPrimaryAccountSetting() {
+ if (mPreferences.contains(KEY_PRIMARY_ACCOUNT)) {
+ SharedPreferences.Editor editor = mPreferences.edit();
+ editor.remove(KEY_PRIMARY_ACCOUNT);
+ editor.apply();
+ }
+ }
+
// TODO: back up to Android Backup
private static void log(String msg) {
diff --git a/sip/src/com/android/services/telephony/sip/SipUtil.java b/sip/src/com/android/services/telephony/sip/SipUtil.java
index e926fa1..340ebda 100644
--- a/sip/src/com/android/services/telephony/sip/SipUtil.java
+++ b/sip/src/com/android/services/telephony/sip/SipUtil.java
@@ -16,14 +16,23 @@
package com.android.services.telephony.sip;
+import com.android.phone.R;
+
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.net.Uri;
import android.net.sip.SipManager;
+import android.net.sip.SipProfile;
+import android.provider.Settings;
+import android.telecomm.PhoneAccount;
import android.telecomm.PhoneAccountHandle;
import android.telecomm.TelecommManager;
+import java.util.Arrays;
+import java.util.List;
+
public class SipUtil {
static final String LOG_TAG = "SIP";
static final String EXTRA_INCOMING_CALL_INTENT =
@@ -33,21 +42,15 @@
static final String GATEWAY_PROVIDER_PACKAGE =
"com.android.phone.extra.GATEWAY_PROVIDER_PACKAGE";
- private static boolean sIsVoipSupported;
- private static boolean sIsVoipSupportedInitialized;
-
private SipUtil() {
}
public static boolean isVoipSupported(Context context) {
- if (!sIsVoipSupportedInitialized) {
- sIsVoipSupported = SipManager.isVoipSupported(context) &&
- context.getResources().getBoolean(
- com.android.internal.R.bool.config_built_in_sip_phone) &&
- context.getResources().getBoolean(
- com.android.internal.R.bool.config_voice_capable);
- }
- return sIsVoipSupported;
+ return SipManager.isVoipSupported(context) &&
+ context.getResources().getBoolean(
+ com.android.internal.R.bool.config_built_in_sip_phone) &&
+ context.getResources().getBoolean(
+ com.android.internal.R.bool.config_voice_capable);
}
static PendingIntent createIncomingCallPendingIntent(
@@ -74,4 +77,55 @@
return new PhoneAccountHandle(
new ComponentName(context, SipConnectionService.class), sipUri);
}
+
+ /**
+ * Determines if the {@link android.telecomm.PhoneAccount} associated with a {@link SipProfile}
+ * is enabled.
+ *
+ * @param context The {@link Context}.
+ * @param profile The {@link SipProfile}.
+ * @return {@code True} if the {@code PhoneAccount} is enabled.
+ */
+ static boolean isPhoneAccountEnabled(Context context, SipProfile profile) {
+ PhoneAccount phoneAccount = TelecommManager.from(context)
+ .getPhoneAccount(SipUtil.createAccountHandle(context, profile.getUriString()));
+ return phoneAccount != null && phoneAccount.isEnabled();
+ }
+
+ /**
+ * Creates a PhoneAccount for a SipProfile.
+ *
+ * @param context The context
+ * @param profile The SipProfile.
+ * @return The PhoneAccount.
+ */
+ static PhoneAccount createPhoneAccount(Context context, SipProfile profile) {
+
+ PhoneAccountHandle accountHandle =
+ SipUtil.createAccountHandle(context, profile.getUriString());
+
+ List supportedUriSchemes = Arrays.asList(PhoneAccount.SCHEME_SIP);
+ if (useSipForPstnCalls(context)) {
+ supportedUriSchemes.add(PhoneAccount.SCHEME_TEL);
+ }
+
+ PhoneAccount.Builder builder = PhoneAccount.builder(accountHandle, profile.getDisplayName())
+ .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+ .setAddress(Uri.parse(profile.getUriString()))
+ .setShortDescription(profile.getDisplayName())
+ .setIconResId(R.drawable.ic_dialer_sip_black_24dp)
+ .setSupportedUriSchemes(supportedUriSchemes);
+
+ return builder.build();
+ }
+
+ /**
+ * Determines if the user has chosen to use SIP for PSTN calls as well as SIP calls.
+ * @param context The context.
+ * @return {@code True} if SIP should be used for PSTN calls.
+ */
+ private static boolean useSipForPstnCalls(Context context) {
+ final SipSharedPreferences sipSharedPreferences = new SipSharedPreferences(context);
+ return sipSharedPreferences.getSipCallOption().equals(Settings.System.SIP_ALWAYS);
+ }
}
diff --git a/src/com/android/phone/CallFeaturesSetting.java b/src/com/android/phone/CallFeaturesSetting.java
index 88de152..bb23292 100644
--- a/src/com/android/phone/CallFeaturesSetting.java
+++ b/src/com/android/phone/CallFeaturesSetting.java
@@ -465,6 +465,11 @@
*/
private boolean mReadingSettingsForDefaultProvider = false;
+ /**
+ * Used to indicate that the voicemail preference should be shown.
+ */
+ private boolean mShowVoicemailPreference = false;
+
/*
* Click Listeners, handle click based on objects attached to UI.
*/
@@ -603,6 +608,22 @@
return false;
}
+ /**
+ * Called just prior to showing an AccountSelection dialog to re-populate the model of the
+ * AccountSelection dialog. Important to ensure changes to the enabled state of
+ * {@code PhoneAccount}s are reflected in the dialog.
+ *
+ * @param pref The account selection preference dialog being shown.
+ */
+ @Override
+ public void onAccountSelectionDialogShow(AccountSelectionPreference pref) {
+ if (pref == mDefaultOutgoingAccount) {
+ populateDefaultOutgoingAccountsModel();
+ } else if (pref == mSimCallManagerAccount) {
+ populateSimCallManagerAccountsModel();
+ }
+ }
+
@Override
public void onDialogClosed(EditPhoneNumberPreference preference, int buttonClicked) {
if (DBG) log("onPreferenceClick: request preference click on dialog close: " +
@@ -1509,13 +1530,121 @@
super.onCreate(icicle);
if (DBG) log("onCreate(). Intent: " + getIntent());
mPhone = PhoneGlobals.getPhone();
+ mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+
+ // create intent to bring up contact list
+ mContactListIntent = new Intent(Intent.ACTION_GET_CONTENT);
+ mContactListIntent.setType(android.provider.Contacts.Phones.CONTENT_ITEM_TYPE);
+
+ mVoicemailRingtoneLookupRunnable = new Runnable() {
+ @Override
+ public void run() {
+ if (mVoicemailNotificationRingtone != null) {
+ SettingsUtil.updateRingtoneName(
+ mPhone.getContext(),
+ mVoicemailRingtoneLookupComplete,
+ RingtoneManager.TYPE_NOTIFICATION,
+ mVoicemailNotificationRingtone,
+ MSG_UPDATE_VOICEMAIL_RINGTONE_SUMMARY);
+ }
+ }
+ };
+
+ ActionBar actionBar = getActionBar();
+ if (actionBar != null) {
+ // android.R.id.home will be triggered in onOptionsItemSelected()
+ actionBar.setDisplayShowHomeEnabled(true);
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ actionBar.setDisplayShowTitleEnabled(true);
+ }
+
+ // Show the voicemail preference in onResume if the calling intent specifies the
+ // ACTION_ADD_VOICEMAIL action.
+ mShowVoicemailPreference = (icicle == null) &&
+ getIntent().getAction().equals(ACTION_ADD_VOICEMAIL);
+ }
+
+ private void initPhoneAccountPreferences() {
+ mDefaultOutgoingAccount = (AccountSelectionPreference)
+ findPreference(DEFAULT_OUTGOING_ACCOUNT_KEY);
+ mSimCallManagerAccount = (AccountSelectionPreference)
+ findPreference(WIFI_CALL_MANAGER_ACCOUNT_KEY);
+
+ TelecommManager telecommManager = TelecommManager.from(this);
+
+ int allPhoneAccountsCount = telecommManager.getAllPhoneAccountsCount();
+ // Show the phone accounts preference if there are is more than one phone account (this
+ // includes disabled phone accounts). The default selection, however, only includes those
+ // PhoneAccounts which are enabled.
+ if (allPhoneAccountsCount > 1) {
+ populateDefaultOutgoingAccountsModel();
+
+ mDefaultOutgoingAccount.setListener(this);
+ } else {
+ getPreferenceScreen().removePreference(mDefaultOutgoingAccount);
+ }
+
+ List<PhoneAccountHandle> simCallManagers = telecommManager.getSimCallManagers();
+ if (!simCallManagers.isEmpty()) {
+ populateSimCallManagerAccountsModel();
+ mSimCallManagerAccount.setListener(this);
+ } else {
+ getPreferenceScreen().removePreference(mSimCallManagerAccount);
+ }
+ }
+
+ private void createSipCallSettings() {
+ // Add Internet call settings.
+ if (SipUtil.isVoipSupported(this)) {
+ mSipManager = SipManager.newInstance(this);
+ mSipSharedPreferences = new SipSharedPreferences(this);
+ addPreferencesFromResource(
+ com.android.services.telephony.sip.R.xml.sip_settings_category);
+ mButtonSipCallOptions = getSipCallOptionPreference();
+ mButtonSipCallOptions.setOnPreferenceChangeListener(this);
+ mButtonSipCallOptions.setValueIndex(
+ mButtonSipCallOptions.findIndexOfValue(
+ mSipSharedPreferences.getSipCallOption()));
+ mButtonSipCallOptions.setSummary(mButtonSipCallOptions.getEntry());
+ }
+ }
+
+ private boolean canLaunchIntent(Intent intent) {
+ PackageManager pm = getPackageManager();
+ return pm.resolveActivity(intent, PackageManager.GET_ACTIVITIES) != null;
+ }
+
+ // Gets the call options for SIP depending on whether SIP is allowed only
+ // on Wi-Fi only; also make the other options preference invisible.
+ private ListPreference getSipCallOptionPreference() {
+ ListPreference wifiAnd3G = (ListPreference)
+ findPreference(BUTTON_SIP_CALL_OPTIONS);
+ ListPreference wifiOnly = (ListPreference)
+ findPreference(BUTTON_SIP_CALL_OPTIONS_WIFI_ONLY);
+ PreferenceScreen sipSettings = (PreferenceScreen)
+ getPreferenceScreen().findPreference(SIP_SETTINGS_PREFERENCE_SCREEN_KEY);
+ if (SipManager.isSipWifiOnly(this)) {
+ sipSettings.removePreference(wifiAnd3G);
+ return wifiOnly;
+ } else {
+ sipSettings.removePreference(wifiOnly);
+ return wifiAnd3G;
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mForeground = true;
+
+ PreferenceScreen preferenceScreen = getPreferenceScreen();
+ if (preferenceScreen != null) {
+ preferenceScreen.removeAll();
+ }
addPreferencesFromResource(R.xml.call_feature_setting);
-
initPhoneAccountPreferences();
- mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
-
// get buttons
PreferenceScreen prefSet = getPreferenceScreen();
mSubMenuVoicemailSettings = (EditPhoneNumberPreference)findPreference(BUTTON_VOICEMAIL_KEY);
@@ -1541,7 +1670,6 @@
initVoiceMailProviders();
}
- final ContentResolver contentResolver = getContentResolver();
if (mButtonDTMF != null) {
if (getResources().getBoolean(R.bool.dtmf_type_enabled)) {
@@ -1609,134 +1737,29 @@
}
}
- // create intent to bring up contact list
- mContactListIntent = new Intent(Intent.ACTION_GET_CONTENT);
- mContactListIntent.setType(android.provider.Contacts.Phones.CONTENT_ITEM_TYPE);
-
// check the intent that started this activity and pop up the voicemail
// dialog if we've been asked to.
// If we have at least one non default VM provider registered then bring up
// the selection for the VM provider, otherwise bring up a VM number dialog.
// We only bring up the dialog the first time we are called (not after orientation change)
- if (icicle == null) {
- if (getIntent().getAction().equals(ACTION_ADD_VOICEMAIL) &&
- mVoicemailProviders != null) {
- if (DBG) {
- log("ACTION_ADD_VOICEMAIL Intent is thrown. current VM data size: "
- + mVMProvidersData.size());
- }
- if (mVMProvidersData.size() > 1) {
- simulatePreferenceClick(mVoicemailProviders);
- } else {
- onPreferenceChange(mVoicemailProviders, DEFAULT_VM_PROVIDER_KEY);
- mVoicemailProviders.setValue(DEFAULT_VM_PROVIDER_KEY);
- }
+ if (mShowVoicemailPreference && mVoicemailProviders != null) {
+ if (DBG) {
+ log("ACTION_ADD_VOICEMAIL Intent is thrown. current VM data size: "
+ + mVMProvidersData.size());
}
+ if (mVMProvidersData.size() > 1) {
+ simulatePreferenceClick(mVoicemailProviders);
+ } else {
+ onPreferenceChange(mVoicemailProviders, DEFAULT_VM_PROVIDER_KEY);
+ mVoicemailProviders.setValue(DEFAULT_VM_PROVIDER_KEY);
+ }
+ mShowVoicemailPreference = false;
}
+
updateVoiceNumberField();
mVMProviderSettingsForced = false;
createSipCallSettings();
- mVoicemailRingtoneLookupRunnable = new Runnable() {
- @Override
- public void run() {
- if (mVoicemailNotificationRingtone != null) {
- SettingsUtil.updateRingtoneName(
- mPhone.getContext(),
- mVoicemailRingtoneLookupComplete,
- RingtoneManager.TYPE_NOTIFICATION,
- mVoicemailNotificationRingtone,
- MSG_UPDATE_VOICEMAIL_RINGTONE_SUMMARY);
- }
- }
- };
-
- ActionBar actionBar = getActionBar();
- if (actionBar != null) {
- // android.R.id.home will be triggered in onOptionsItemSelected()
- actionBar.setDisplayShowHomeEnabled(true);
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowTitleEnabled(true);
- }
- }
-
- private void initPhoneAccountPreferences() {
- mDefaultOutgoingAccount = (AccountSelectionPreference)
- findPreference(DEFAULT_OUTGOING_ACCOUNT_KEY);
- mSimCallManagerAccount = (AccountSelectionPreference)
- findPreference(WIFI_CALL_MANAGER_ACCOUNT_KEY);
-
- TelecommManager telecommManager = TelecommManager.from(this);
-
- List<PhoneAccountHandle> enabledPhoneAccounts = telecommManager.getEnabledPhoneAccounts();
- if (enabledPhoneAccounts.size() > 1) {
- mDefaultOutgoingAccount.setModel(
- telecommManager,
- enabledPhoneAccounts,
- telecommManager.getUserSelectedOutgoingPhoneAccount(),
- getString(R.string.phone_accounts_ask_every_time));
- mDefaultOutgoingAccount.setListener(this);
- } else {
- getPreferenceScreen().removePreference(mDefaultOutgoingAccount);
- }
-
- List<PhoneAccountHandle> simCallManagers = telecommManager.getSimCallManagers();
- if (!simCallManagers.isEmpty()) {
- mSimCallManagerAccount.setModel(
- telecommManager,
- simCallManagers,
- telecommManager.getSimCallManager(),
- getString(R.string.wifi_calling_do_not_use));
- mSimCallManagerAccount.setListener(this);
- } else {
- getPreferenceScreen().removePreference(mSimCallManagerAccount);
- }
- }
-
- private void createSipCallSettings() {
- // Add Internet call settings.
- if (SipUtil.isVoipSupported(this)) {
- mSipManager = SipManager.newInstance(this);
- mSipSharedPreferences = new SipSharedPreferences(this);
- addPreferencesFromResource(
- com.android.services.telephony.sip.R.xml.sip_settings_category);
- mButtonSipCallOptions = getSipCallOptionPreference();
- mButtonSipCallOptions.setOnPreferenceChangeListener(this);
- mButtonSipCallOptions.setValueIndex(
- mButtonSipCallOptions.findIndexOfValue(
- mSipSharedPreferences.getSipCallOption()));
- mButtonSipCallOptions.setSummary(mButtonSipCallOptions.getEntry());
- }
- }
-
- private boolean canLaunchIntent(Intent intent) {
- PackageManager pm = getPackageManager();
- return pm.resolveActivity(intent, PackageManager.GET_ACTIVITIES) != null;
- }
-
- // Gets the call options for SIP depending on whether SIP is allowed only
- // on Wi-Fi only; also make the other options preference invisible.
- private ListPreference getSipCallOptionPreference() {
- ListPreference wifiAnd3G = (ListPreference)
- findPreference(BUTTON_SIP_CALL_OPTIONS);
- ListPreference wifiOnly = (ListPreference)
- findPreference(BUTTON_SIP_CALL_OPTIONS_WIFI_ONLY);
- PreferenceScreen sipSettings = (PreferenceScreen)
- getPreferenceScreen().findPreference(SIP_SETTINGS_PREFERENCE_SCREEN_KEY);
- if (SipManager.isSipWifiOnly(this)) {
- sipSettings.removePreference(wifiAnd3G);
- return wifiOnly;
- } else {
- sipSettings.removePreference(wifiOnly);
- return wifiAnd3G;
- }
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- mForeground = true;
-
if (isAirplaneModeOn()) {
Preference sipSettings = findPreference(SIP_SETTINGS_PREFERENCE_SCREEN_KEY);
PreferenceScreen screen = getPreferenceScreen();
@@ -2117,6 +2140,41 @@
}
/**
+ * Populates the phone accounts which could potentially be selected as the default.
+ */
+ private void populateDefaultOutgoingAccountsModel() {
+ if (mDefaultOutgoingAccount == null ) {
+ return;
+ }
+
+ TelecommManager telecommManager = TelecommManager.from(this);
+ List<PhoneAccountHandle> enabledPhoneAccounts = telecommManager.getEnabledPhoneAccounts();
+ mDefaultOutgoingAccount.setModel(
+ telecommManager,
+ enabledPhoneAccounts,
+ telecommManager.getUserSelectedOutgoingPhoneAccount(),
+ getString(R.string.phone_accounts_ask_every_time));
+ }
+
+ /**
+ * Populates the phone accounts which could potentially be selected as the default sim call
+ * manager.
+ */
+ private void populateSimCallManagerAccountsModel() {
+ if (mSimCallManagerAccount == null) {
+ return;
+ }
+
+ TelecommManager telecommManager = TelecommManager.from(this);
+ List<PhoneAccountHandle> simCallManagers = telecommManager.getSimCallManagers();
+ mSimCallManagerAccount.setModel(
+ telecommManager,
+ simCallManagers,
+ telecommManager.getSimCallManager(),
+ getString(R.string.wifi_calling_do_not_use));
+ }
+
+ /**
* Deletes settings for the specified provider.
*/
private void deleteSettingsForVoicemailProvider(String key) {
diff --git a/src/com/android/phone/settings/AccountSelectionPreference.java b/src/com/android/phone/settings/AccountSelectionPreference.java
index 32149ae..8469a18 100644
--- a/src/com/android/phone/settings/AccountSelectionPreference.java
+++ b/src/com/android/phone/settings/AccountSelectionPreference.java
@@ -16,7 +16,13 @@
package com.android.phone.settings;
+import com.android.phone.R;
+
+import android.app.AlertDialog;
import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.UserHandle;
import android.preference.ListPreference;
import android.preference.Preference;
import android.telecomm.PhoneAccountHandle;
@@ -31,8 +37,10 @@
public interface AccountSelectionListener {
boolean onAccountSelected(AccountSelectionPreference pref, PhoneAccountHandle account);
+ void onAccountSelectionDialogShow(AccountSelectionPreference pref);
}
+ private final Context mContext;
private AccountSelectionListener mListener;
private PhoneAccountHandle[] mAccounts;
private String[] mEntryValues;
@@ -40,11 +48,13 @@
public AccountSelectionPreference(Context context) {
super(context);
+ mContext = context;
setOnPreferenceChangeListener(this);
}
public AccountSelectionPreference(Context context, AttributeSet attrs) {
super(context, attrs);
+ mContext = context;
setOnPreferenceChangeListener(this);
}
@@ -93,4 +103,39 @@
}
return false;
}
+
+ /**
+ * Modifies the dialog to change the default "Cancel" button to "Choose Accounts", which
+ * triggers the {@link PhoneAccountSelectionPreferenceActivity} to be shown.
+ *
+ * @param builder The {@code AlertDialog.Builder}.
+ */
+ @Override
+ protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
+ // Notify the listener that the dialog is about to be built. This is important so that the
+ // list of enabled accounts can be updated prior to showing the dialog.
+ mListener.onAccountSelectionDialogShow(this);
+
+ final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int whichButton) {
+ showSelectPhoneAccounts();
+ }
+ };
+ builder.setNegativeButton(R.string.phone_accounts_choose_accounts, listener);
+ super.onPrepareDialogBuilder(builder);
+ }
+
+ /**
+ * Displays the {@link PhoneAccountSelectionPreferenceActivity} where the user is able to
+ * enable and disable phone accounts.
+ */
+ private void showSelectPhoneAccounts() {
+ Intent intent = new Intent(mContext, PhoneAccountSelectionPreferenceActivity.class);
+ intent.setAction(Intent.ACTION_MAIN);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
+ | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ mContext.startActivityAsUser(intent, null, UserHandle.CURRENT);
+ }
}
diff --git a/src/com/android/phone/settings/PhoneAccountSelectionPreferenceActivity.java b/src/com/android/phone/settings/PhoneAccountSelectionPreferenceActivity.java
new file mode 100644
index 0000000..7dd1190
--- /dev/null
+++ b/src/com/android/phone/settings/PhoneAccountSelectionPreferenceActivity.java
@@ -0,0 +1,171 @@
+/*
+ * 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.phone.settings;
+
+import android.app.ActionBar;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceCategory;
+import android.preference.PreferenceFragment;
+import android.preference.SwitchPreference;
+import android.telecomm.PhoneAccount;
+import android.telecomm.PhoneAccountHandle;
+import android.telecomm.TelecommManager;
+
+import com.android.internal.util.CharSequences;
+import com.android.phone.R;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * Preference activity used to facilitate enabling and disabling phone accounts by the user.
+ */
+public class PhoneAccountSelectionPreferenceActivity extends PreferenceActivity {
+
+ /**
+ * Preference fragment containing a list of all {@link PhoneAccount}s in the form of switches
+ * the user can use to enable or disable accounts.
+ */
+ public static class PhoneAccountSelectionPreferenceFragment extends PreferenceFragment
+ implements Preference.OnPreferenceChangeListener {
+ private static final String CATEGORY_PHONE_ACCOUNTS_KEY = "phone_accounts_list";
+
+ private TelecommManager mTelecommManager;
+ private PreferenceCategory mPhoneAccountsCategory;
+
+ /**
+ * Represents a single {@link PhoneAccount} for the purpose enabling and disabling.
+ */
+ static class PhoneAccountPreference extends SwitchPreference {
+ private PhoneAccountHandle mPhoneAccountHandle;
+ private boolean mPreviousState;
+
+ public PhoneAccountPreference(Context context, PhoneAccount phoneAccount) {
+ super(context);
+
+ setPhoneAccount(phoneAccount);
+ }
+
+ /**
+ * Configures the {@code PhoneAccountPreference} for the passed in {@link PhoneAccount}.
+ *
+ * @param phoneAccount The phone account.
+ */
+ private void setPhoneAccount(PhoneAccount phoneAccount) {
+ mPhoneAccountHandle = phoneAccount.getAccountHandle();
+ mPreviousState = phoneAccount.isEnabled();
+ this.setTitle(phoneAccount.getLabel());
+ this.setChecked(mPreviousState);
+ }
+
+ public boolean getPreviousState() {
+ return mPreviousState;
+ }
+
+ public PhoneAccountHandle getPhoneAccountHandle() {
+ return mPhoneAccountHandle;
+ }
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ addPreferencesFromResource(R.xml.phone_account_selection);
+ mPhoneAccountsCategory = (PreferenceCategory) findPreference(
+ CATEGORY_PHONE_ACCOUNTS_KEY);
+ mTelecommManager = TelecommManager.from(this.getActivity());
+
+ List<PhoneAccount> phoneAccounts = mTelecommManager.getAllPhoneAccounts();
+ Collections.sort(phoneAccounts, new Comparator<PhoneAccount>() {
+ @Override
+ public int compare(PhoneAccount o1, PhoneAccount o2) {
+ return CharSequences.compareToIgnoreCase(o1.getLabel(), o2.getLabel());
+ }
+ });
+
+ for (PhoneAccount phoneAccount : phoneAccounts) {
+ // Do not add Sim PhoneAccounts.
+ if (phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
+ continue;
+ }
+
+ PhoneAccountPreference phoneAccountPreference = new PhoneAccountPreference(
+ getActivity(), phoneAccount);
+ phoneAccountPreference.setOnPreferenceChangeListener(this);
+ phoneAccountPreference.setEnabled(!phoneAccount.hasCapabilities(
+ PhoneAccount.CAPABILITY_ALWAYS_ENABLED));
+ mPhoneAccountsCategory.addPreference(phoneAccountPreference);
+ }
+ }
+
+ /**
+ * Handles changes to preferences
+ * @param preference The preference which changed.
+ * @param newValue The new value of the preference.
+ * @return
+ */
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ if (preference instanceof PhoneAccountPreference) {
+ PhoneAccountPreference phoneAccountPreference = (PhoneAccountPreference) preference;
+ boolean newState = Boolean.valueOf(newValue.toString()).booleanValue();
+
+ if (newState != phoneAccountPreference.getPreviousState()) {
+ mTelecommManager.setPhoneAccountEnabled(
+ phoneAccountPreference.getPhoneAccountHandle(), newState);
+ }
+ return true;
+ }
+ return false;
+ }
+ }
+
+ @Override
+ public void onBuildHeaders(List<Header> target) {
+ loadHeadersFromResource(R.xml.phone_account_selection_activity, target);
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ setTitle(getResources().getString(R.string.call_settings));
+ ActionBar actionBar = getActionBar();
+ if (actionBar != null) {
+ actionBar.setDisplayShowHomeEnabled(false);
+ actionBar.setDisplayHomeAsUpEnabled(false);
+ }
+
+ // By default, show the main fragment.
+ Intent intent = getIntent();
+ if (intent.getStringArrayExtra(EXTRA_SHOW_FRAGMENT) == null) {
+ getIntent().putExtra(EXTRA_SHOW_FRAGMENT,
+ PhoneAccountSelectionPreferenceFragment.class.getName());
+ }
+
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ public boolean isValidFragment(String fragmentName) {
+ return true;
+ }
+}
diff --git a/src/com/android/services/telephony/TelecommAccountRegistry.java b/src/com/android/services/telephony/TelecommAccountRegistry.java
index 749739a..7ec2c4e 100644
--- a/src/com/android/services/telephony/TelecommAccountRegistry.java
+++ b/src/com/android/services/telephony/TelecommAccountRegistry.java
@@ -45,6 +45,8 @@
* removal of SIMs and SIP accounts.
*/
final class TelecommAccountRegistry {
+ private static final boolean DBG = false; /* STOP SHIP if true */
+
private final static int[] phoneAccountIcons = {
R.drawable.ic_multi_sim,
R.drawable.ic_multi_sim1,
@@ -67,7 +69,6 @@
}
void teardown() {
- mTelecommManager.unregisterPhoneAccount(mAccount.getAccountHandle());
mIncomingCallNotifier.teardown();
}
@@ -117,22 +118,37 @@
dummyPrefix + mContext.getResources().getString(
R.string.sim_description_default, slotId);
+ // By default all SIM phone accounts can place emergency calls.
+ int capabilities = PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION |
+ PhoneAccount.CAPABILITY_CALL_PROVIDER |
+ PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS;
+
+ // Indicate the emergency calling PhoneAccount is ALWAYS enabled. This capability is
+ // important to ensure the emergency-only PhoneAccount cannot be disabled.
+ if (isEmergency) {
+ capabilities |= PhoneAccount.CAPABILITY_ALWAYS_ENABLED;
+ }
+
PhoneAccount account = PhoneAccount.builder(phoneAccountHandle, label)
.setAddress(Uri.fromParts(PhoneAccount.SCHEME_TEL, line1Number, null))
.setSubscriptionAddress(
Uri.fromParts(PhoneAccount.SCHEME_TEL, subNumber, null))
- .setCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION |
- PhoneAccount.CAPABILITY_CALL_PROVIDER)
+ .setCapabilities(capabilities)
.setIconResId(getPhoneAccountIcon(slotId))
.setShortDescription(description)
.setSupportedUriSchemes(Arrays.asList(
PhoneAccount.SCHEME_TEL, PhoneAccount.SCHEME_VOICEMAIL))
+ .setEnabled(true)
.build();
// Register with Telecomm and put into the account entry.
mTelecommManager.registerPhoneAccount(account);
return account;
}
+
+ public PhoneAccountHandle getPhoneAccountHandle() {
+ return mAccount != null ? mAccount.getAccountHandle() : null;
+ }
}
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@@ -190,7 +206,6 @@
intentFilter.addAction(TelephonyIntents.ACTION_SUBINFO_RECORD_UPDATED);
intentFilter.addAction(TelephonyIntents.ACTION_SUBINFO_CONTENT_CHANGE);
mContext.registerReceiver(mReceiver, intentFilter);
- setupAccounts();
}
static PhoneAccountHandle makePstnPhoneAccountHandle(Phone phone) {
@@ -207,22 +222,43 @@
return new PhoneAccountHandle(pstnConnectionServiceName, id);
}
- private void clearCurrentTelephonyAccounts() {
+ /**
+ * Determines if the list of {@link AccountEntry}(s) contains an {@link AccountEntry} with a
+ * specified {@link PhoneAccountHandle}.
+ *
+ * @param handle The {@link PhoneAccountHandle}.
+ * @return {@code True} if an entry exists.
+ */
+ private boolean hasAccountEntryForPhoneAccount(PhoneAccountHandle handle) {
+ for (AccountEntry entry : mAccounts) {
+ if (entry.getPhoneAccountHandle().equals(handle)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Un-registers any {@link PhoneAccount}s which are no longer present in the list
+ * {@code AccountEntry}(s).
+ */
+ private void cleanupPhoneAccounts() {
ComponentName telephonyComponentName =
new ComponentName(mContext, TelephonyConnectionService.class);
- List<PhoneAccountHandle> accountHandles = mTelecommManager.getEnabledPhoneAccounts();
+
+ List<PhoneAccountHandle> accountHandles = mTelecommManager.getAllPhoneAccountHandles();
for (PhoneAccountHandle handle : accountHandles) {
- if (telephonyComponentName.equals(handle.getComponentName())) {
+ if (telephonyComponentName.equals(handle.getComponentName()) &&
+ !hasAccountEntryForPhoneAccount(handle)) {
+ Log.d(this, "Unregistering phone account %s.", handle);
mTelecommManager.unregisterPhoneAccount(handle);
}
}
}
private void setupAccounts() {
- // Before we do anything, we need to clear whatever entries we registered at boot.
- clearCurrentTelephonyAccounts();
-
- // Go through SIM-based phones and register ourselves
+ // Go through SIM-based phones and register ourselves -- registering an existing account
+ // will cause the existing entry to be replaced.
Phone[] phones = PhoneFactory.getPhones();
Log.d(this, "Found %d phones. Attempting to register.", phones.length);
for (Phone phone : phones) {
@@ -242,9 +278,12 @@
}
// Add a fake account entry.
- if (phones.length > 0 && "TRUE".equals(System.getProperty("dummy_sim"))) {
+ if ( DBG && phones.length > 0 && "TRUE".equals(System.getProperty("dummy_sim"))) {
mAccounts.add(new AccountEntry(phones[0], false /* emergency */, true /* isDummy */));
}
+
+ // Clean up any PhoneAccounts that are no longer relevant
+ cleanupPhoneAccounts();
}
private int getPhoneAccountIcon(int index) {