Merge "Implement the short-burst DTMF tones for CDMA calls." into lmp-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index f668255..9bc9a58 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,9 +497,10 @@
<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" />
+ <action android:name="android.telecom.action.PHONE_ACCOUNT_ENABLED" />
+ <action android:name="android.telecom.action.PHONE_ACCOUNT_DISABLED" />
</intent-filter>
</receiver>
diff --git a/res/drawable-hdpi/fab_teal_background.png b/res/drawable-hdpi/fab_teal_background.png
deleted file mode 100644
index e2f01e8..0000000
--- a/res/drawable-hdpi/fab_teal_background.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/fab_teal_background.png b/res/drawable-mdpi/fab_teal_background.png
deleted file mode 100644
index c95d124..0000000
--- a/res/drawable-mdpi/fab_teal_background.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/fab_teal_background.png b/res/drawable-xhdpi/fab_teal_background.png
deleted file mode 100644
index f94f759..0000000
--- a/res/drawable-xhdpi/fab_teal_background.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/fab_teal_background.png b/res/drawable-xxhdpi/fab_teal_background.png
deleted file mode 100644
index cc0ba27..0000000
--- a/res/drawable-xxhdpi/fab_teal_background.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable/floating_action_button.xml b/res/drawable/floating_action_button.xml
index d518ddd..52799e4 100644
--- a/res/drawable/floating_action_button.xml
+++ b/res/drawable/floating_action_button.xml
@@ -16,6 +16,6 @@
-->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="@color/dialer_accent_color">
- <item android:drawable="@drawable/fab_teal_background" />
+ android:color="@color/floating_action_button_touch_tint">
+ <item android:drawable="@drawable/fab_green" />
</ripple>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index f629da0..c7701fc 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -45,12 +45,14 @@
<color name="actionbar_background_color_dark">@color/dialer_theme_color_dark</color>
<!-- Color for icons in the actionbar. Ensure this stays in sync with Dialer version. -->
<color name="actionbar_icon_color">#ffffff</color>
+ <!-- Color of title text in actionbar. Ensure this stays in sync with Dialer version. -->
+ <color name="actionbar_text_color">#ffffff</color>
<!-- Color for the setting text. -->
<color name="setting_primary_color">#4d4c4c</color>
<!-- Color for the setting description text. -->
<color name="setting_secondary_color">#989898</color>
- <color name="dialer_dialpad_touch_tint">#331dc7db</color>
- <color name="dialer_accent_color">#eeff41</color>
+ <color name="dialer_dialpad_touch_tint">#330288d1</color>
+ <color name="floating_action_button_touch_tint">#80ffffff</color>
<color name="dialer_theme_color">#0288d1</color>
</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index ae0a7c1..267f142 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -69,6 +69,8 @@
<dimen name="dialpad_horizontal_margin">4dp</dimen>
<dimen name="dialpad_vertical_margin">2dp</dimen>
<dimen name="dialpad_digits_text_size">35sp</dimen>
+ <dimen name="dialpad_space_above_keys">29dp</dimen>
+ <dimen name="dialpad_bottom_key_height">113dp</dimen>
<!-- Just used in landscape mode -->
<dimen name="emergency_dialer_digits_height">0px</dimen>
@@ -95,6 +97,15 @@
So, (94 - 38)/2 ==> 28dp -->
<dimen name="incoming_call_widget_asset_margin">28dp</dimen>
<!-- Action bar dimensions. Keep in sync with same value in Dialer. -->
- <dimen name="action_bar_height">64dp</dimen>
+ <dimen name="action_bar_height">56dp</dimen>
+ <dimen name="action_bar_elevation">2dp</dimen>
<dimen name="actionbar_contentInsetStart">72dp</dimen>
+
+ <!-- Width, height and bottom margin for the floating action button. These values are
+ intentionally larger than the values used inside Dialer, since the dialpad is larger
+ inside the Emergency Dialer than the regular Dialer. -->
+ <dimen name="floating_action_button_width">67dp</dimen>
+ <dimen name="floating_action_button_height">67dp</dimen>
+ <dimen name="floating_action_button_margin_bottom">26dp</dimen>
+
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 0282c76..4ef5c12 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1218,4 +1218,8 @@
<!-- Label for close button in dialog, for video calling setting. -->
<string name="enable_video_calling_dialog_close">Close</string>
+ <!-- Strings used in Settings->Sim cards for each installed Sim. -->
+ <string name="sim_label_emergency_calls">Emergency calls</string>
+ <string name="sim_description_emergency_calls">Emergency calling only</string>
+ <string name="sim_description_default">SIM card, slot: <xliff:g id="slot_id">%s</xliff:g></string>
</resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 76b100a..d886dab 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -234,23 +234,27 @@
<style name="ContactsActionBarStyle"
parent="@android:style/Widget.Holo.Light.ActionBar.Solid.Inverse">
<item name="android:background">@color/people_app_theme_color</item>
- <item name="android:backgroundStacked">@color/people_app_theme_color</item>
+ <item name="android:backgroundStacked">@color/people_app_theme_color</item>gs
</style>
<!-- Style for the call settings action bar. Should be kept in sync with Dialer. -->
- <style name="DialtactsActionBarStyle" parent="android:Widget.Material.ActionBar">
- <item name="android:background">@color/actionbar_background_color</item>
- <item name="android:titleTextStyle">@style/DialtactsActionBarTitleText</item>
- <item name="android:height">@dimen/action_bar_height</item>
- <!-- Empty icon -->
- <item name="android:icon">@android:color/transparent</item>
+ <style name="DialtactsActionBarStyle" parent="@style/TelephonyActionBarStyle">
<!-- Shift the title text to the right -->
<item name="android:contentInsetStart">@dimen/actionbar_contentInsetStart</item>
</style>
+ <style name="TelephonyActionBarStyle" parent="android:Widget.Material.ActionBar">
+ <item name="android:background">@color/actionbar_background_color</item>
+ <item name="android:titleTextStyle">@style/DialtactsActionBarTitleText</item>
+ <item name="android:height">@dimen/action_bar_height</item>
+ <item name="android:elevation">@dimen/action_bar_elevation</item>
+ <!-- Empty icon -->
+ <item name="android:icon">@android:color/transparent</item>
+ </style>
+
<!-- Text in the action bar at the top of the screen. Should be kept in sync with Dialer. -->
<style name="DialtactsActionBarTitleText"
- parent="@android:style/TextAppearance.Holo.Widget.ActionBar.Title">
+ parent="@android:style/TextAppearance.Material.Widget.ActionBar.Title">
<item name="android:textColor">@color/phone_settings_actionbar_text_color</item>
</style>
@@ -262,6 +266,9 @@
<style name="EmergencyDialerTheme" parent="@android:style/Theme.Material.Light">
<item name="dialpad_key_button_touch_tint">@color/dialer_dialpad_touch_tint</item>
+ <item name="android:actionBarStyle">@style/TelephonyActionBarStyle</item>
+ <item name="android:colorPrimary">@color/dialer_theme_color</item>
+ <item name="android:colorPrimaryDark">@color/dialer_theme_color_dark</item>
</style>
<style name="SimImportTheme"
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 f830f67..09708b7 100644
--- a/sip/src/com/android/services/telephony/sip/SipAccountRegistry.java
+++ b/sip/src/com/android/services/telephony/sip/SipAccountRegistry.java
@@ -16,20 +16,16 @@
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.text.TextUtils;
import android.util.Log;
-import com.android.phone.R;
-
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -49,42 +45,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());
-
- PhoneAccount.Builder builder = PhoneAccount.builder()
- .withAccountHandle(accountHandle)
- .withCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
- .withHandle(Uri.parse(mProfile.getUriString()))
- .withLabel(mProfile.getDisplayName())
- .withShortDescription(mProfile.getDisplayName())
- .withIconResId(R.drawable.ic_dialer_sip_black_24dp)
- .withSupportedUriScheme(PhoneAccount.SCHEME_SIP);
-
- if (useSipForPstnCalls) {
- builder.withSupportedUriScheme(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);
}
-
- return builder.build();
+ return false;
}
}
@@ -101,84 +113,206 @@
}
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);
+ }
+
+ /**
+ * Handles a {@link PhoneAccount} becoming enabled by starting the SIP service for the
+ * {@link SipProfile} associated with that {@linke PhoneAccount}.
+ *
+ * @param context The context.
+ * @param phoneAccountHandle The handle for the {@link PhoneAccount} which is enabled.
+ */
+ void setPhoneAccountEnabled(Context context, PhoneAccountHandle phoneAccountHandle) {
+ String sipUri = SipUtil.getSipUriFromPhoneAccount(phoneAccountHandle);
+ if (sipUri == null) {
+ return;
+ }
+
+ startSipService(context, sipUri);
+ }
+
+ /**
+ * Handles a {@link PhoneAccount} becoming disabled by stopping the SIP service for the
+ * {@link SipProfile} associated with that {@linke PhoneAccount}.
+ *
+ * @param context The context.
+ * @param phoneAccountHandle The handle for the {@link PhoneAccount} which is disabled.
+ */
+ void setPhoneAccountDisabled(Context context, PhoneAccountHandle phoneAccountHandle) {
+ String sipUri = SipUtil.getSipUriFromPhoneAccount(phoneAccountHandle);
+ if (sipUri == null) {
+ return;
+ }
+
+ stopSipService(context, sipUri);
+ }
+
+ /**
+ * 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..37ab30c 100644
--- a/sip/src/com/android/services/telephony/sip/SipBroadcastReceiver.java
+++ b/sip/src/com/android/services/telephony/sip/SipBroadcastReceiver.java
@@ -47,14 +47,24 @@
} 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 (action.equals(TelecommManager.ACTION_PHONE_ACCOUNT_ENABLED)) {
+ PhoneAccountHandle phoneAccountHandle = intent.getParcelableExtra(
+ TelecommManager.EXTRA_PHONE_ACCOUNT_HANDLE);
+ if (phoneAccountHandle == null) {
+ return;
+ }
+ sipAccountRegistry.setPhoneAccountEnabled(context, phoneAccountHandle);
+ } else if (action.equals(TelecommManager.ACTION_PHONE_ACCOUNT_DISABLED)) {
+ PhoneAccountHandle phoneAccountHandle = intent.getParcelableExtra(
+ TelecommManager.EXTRA_PHONE_ACCOUNT_HANDLE);
+ if (phoneAccountHandle == null) {
+ return;
+ }
+ sipAccountRegistry.setPhoneAccountDisabled(context, phoneAccountHandle);
} else {
if (VERBOSE) log("onReceive, action not processed: " + action);
}
diff --git a/sip/src/com/android/services/telephony/sip/SipConnection.java b/sip/src/com/android/services/telephony/sip/SipConnection.java
index 583fa0e..dc7f720 100644
--- a/sip/src/com/android/services/telephony/sip/SipConnection.java
+++ b/sip/src/com/android/services/telephony/sip/SipConnection.java
@@ -64,21 +64,21 @@
getPhone().registerForPreciseCallStateChanged(mHandler, MSG_PRECISE_CALL_STATE_CHANGED,
null);
}
- updateHandle();
+ updateAddress();
setInitialized();
}
@Override
- public void onSetAudioState(AudioState state) {
- if (VERBOSE) log("onSetAudioState: " + state);
+ public void onAudioStateChanged(AudioState state) {
+ if (VERBOSE) log("onAudioStateChanged: " + state);
if (getPhone() != null) {
getPhone().setEchoSuppressionEnabled();
}
}
@Override
- public void onSetState(int state) {
- if (VERBOSE) log("onSetState, state: " + Connection.stateToString(state));
+ public void onStateChanged(int state) {
+ if (VERBOSE) log("onStateChanged, state: " + Connection.stateToString(state));
}
@Override
@@ -183,11 +183,6 @@
// SIP doesn't have post dial support.
}
- @Override
- public void onPhoneAccountClicked() {
- if (VERBOSE) log("onPhoneAccountClicked");
- }
-
private Call getCall() {
if (mOriginalConnection != null) {
return mOriginalConnection.getCall();
@@ -230,6 +225,8 @@
case DIALING:
case ALERTING:
setDialing();
+ // For SIP calls, we need to ask the framework to play the ringback for us.
+ setRingbackRequested(true);
break;
case INCOMING:
case WAITING:
@@ -275,14 +272,14 @@
/**
* Updates the handle on this connection based on the original connection.
*/
- private void updateHandle() {
+ private void updateAddress() {
if (mOriginalConnection != null) {
- Uri handle = getHandleFromAddress(mOriginalConnection.getAddress());
+ Uri address = getAddressFromNumber(mOriginalConnection.getAddress());
int presentation = mOriginalConnection.getNumberPresentation();
- if (!Objects.equals(handle, getHandle()) ||
- presentation != getHandlePresentation()) {
- com.android.services.telephony.Log.v(this, "updateHandle, handle changed");
- setHandle(handle, presentation);
+ if (!Objects.equals(address, getAddress()) ||
+ presentation != getAddressPresentation()) {
+ com.android.services.telephony.Log.v(this, "updateAddress, address changed");
+ setAddress(address, presentation);
}
String name = mOriginalConnection.getCnapName();
@@ -290,24 +287,24 @@
if (!Objects.equals(name, getCallerDisplayName()) ||
namePresentation != getCallerDisplayNamePresentation()) {
com.android.services.telephony.Log
- .v(this, "updateHandle, caller display name changed");
+ .v(this, "updateAddress, caller display name changed");
setCallerDisplayName(name, namePresentation);
}
}
}
/**
- * Determines the handle for an incoming number.
+ * Determines the address for an incoming number.
*
- * @param address The incoming number.
+ * @param number The incoming number.
* @return The Uri representing the number.
*/
- private static Uri getHandleFromAddress(String address) {
+ private static Uri getAddressFromNumber(String number) {
// Address can be null for blocked calls.
- if (address == null) {
- address = "";
+ if (number == null) {
+ number = "";
}
- return Uri.fromParts(PhoneAccount.SCHEME_SIP, address, null);
+ return Uri.fromParts(PhoneAccount.SCHEME_SIP, number, null);
}
private void close() {
diff --git a/sip/src/com/android/services/telephony/sip/SipConnectionService.java b/sip/src/com/android/services/telephony/sip/SipConnectionService.java
index ffaf64d..74d66f9 100644
--- a/sip/src/com/android/services/telephony/sip/SipConnectionService.java
+++ b/sip/src/com/android/services/telephony/sip/SipConnectionService.java
@@ -32,7 +32,7 @@
import android.telecomm.ConnectionRequest;
import android.telecomm.ConnectionService;
import android.telecomm.PhoneAccountHandle;
-import android.telecomm.PropertyPresentation;
+import android.telecomm.TelecommManager;
import android.telephony.DisconnectCause;
import android.util.Log;
@@ -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,
@@ -74,7 +68,8 @@
if (VERBOSE) log("onCreateOutgoingConnection, request: " + request);
Bundle extras = request.getExtras();
- if (extras != null && extras.getString(SipUtil.GATEWAY_PROVIDER_PACKAGE) != null) {
+ if (extras != null &&
+ extras.getString(TelecommManager.GATEWAY_PROVIDER_PACKAGE) != null) {
return Connection.createFailedConnection(
DisconnectCause.CALL_BARRED, "Cannot make a SIP call with a gateway number.");
}
@@ -86,9 +81,8 @@
DisconnectCause.OUTGOING_FAILURE, "Did not match service connection");
}
-
final SipConnection connection = new SipConnection();
- connection.setHandle(request.getHandle(), PropertyPresentation.ALLOWED);
+ connection.setAddress(request.getAddress(), TelecommManager.PRESENTATION_ALLOWED);
connection.setInitializing();
connection.onAddedToCallService();
boolean attemptCall = true;
@@ -265,7 +259,7 @@
private com.android.internal.telephony.Connection startCallWithPhone(
SipPhone phone, ConnectionRequest request) {
- String number = request.getHandle().getSchemeSpecificPart();
+ String number = request.getAddress().getSchemeSpecificPart();
if (VERBOSE) log("startCallWithPhone, number: " + number);
try {
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..7747637 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;
@@ -97,20 +99,17 @@
void setProfile(SipProfile p) {
mProfile = p;
setTitle(getProfileName(p));
- updateSummary(mSipSharedPreferences.isReceivingCallsEnabled()
+ boolean isEnabled = SipUtil.isPhoneAccountEnabled(getContext(), p);
+ updateSummary(isEnabled && mSipSharedPreferences.isReceivingCallsEnabled()
? getString(R.string.registration_status_checking_status)
: getString(R.string.registration_status_not_receiving));
}
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 +117,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 +215,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) {
@@ -305,7 +300,8 @@
if (!mSipSharedPreferences.isReceivingCallsEnabled()) return;
for (SipProfile p : mSipProfileList) {
- if (mUid == p.getCallingUid()) {
+ if (mUid == p.getCallingUid() &&
+ SipUtil.isPhoneAccountEnabled(getApplicationContext(), p)) {
try {
mSipManager.setRegistrationListener(
p.getUriString(), createRegistrationListener());
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..6194902 100644
--- a/sip/src/com/android/services/telephony/sip/SipUtil.java
+++ b/sip/src/com/android/services/telephony/sip/SipUtil.java
@@ -16,13 +16,22 @@
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 android.text.TextUtils;
+
+import java.util.ArrayList;
public class SipUtil {
static final String LOG_TAG = "SIP";
@@ -30,24 +39,16 @@
"com.android.services.telephony.sip.incoming_call_intent";
static final String EXTRA_PHONE_ACCOUNT =
"com.android.services.telephony.sip.phone_account";
- 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 +75,74 @@
return new PhoneAccountHandle(
new ComponentName(context, SipConnectionService.class), sipUri);
}
+
+ /**
+ * Determines the SIP Uri for a specified {@link PhoneAccountHandle}.
+ *
+ * @param phoneAccountHandle The {@link PhoneAccountHandle}.
+ * @return The SIP Uri.
+ */
+ static String getSipUriFromPhoneAccount(PhoneAccountHandle phoneAccountHandle) {
+ if (phoneAccountHandle == null) {
+ return null;
+ }
+
+ String sipUri = phoneAccountHandle.getId();
+ if (TextUtils.isEmpty(sipUri)) {
+ return null;
+ }
+ return 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());
+
+ final ArrayList<String> supportedUriSchemes = new ArrayList<String>();
+ supportedUriSchemes.add(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/MobileNetworkSettings.java b/src/com/android/phone/MobileNetworkSettings.java
index e6fc11c..20134ba 100644
--- a/src/com/android/phone/MobileNetworkSettings.java
+++ b/src/com/android/phone/MobileNetworkSettings.java
@@ -122,10 +122,7 @@
@Override
public void onDismiss(DialogInterface dialog) {
// Assuming that onClick gets called first
- if (!mOkClicked) {
- mButtonDataRoam.setChecked(false);
- getPreferenceScreen().setEnabled(true);
- }
+ mButtonDataRoam.setChecked(mOkClicked);
}
/**
@@ -185,6 +182,9 @@
preferredNetworkMode);
mButtonEnabledNetworks.setValue(Integer.toString(settingsNetworkMode));
return true;
+ } else if (preference == mButtonDataRoam) {
+ // Do not disable the preference screen if the user clicks Data roaming.
+ return true;
} else {
// if the button is anything but the simple toggle preference,
// we'll need to disable all preferences to reject all click
@@ -249,7 +249,7 @@
boolean isLteOnCdma = mPhone.getLteOnCdmaMode() == PhoneConstants.LTE_ON_CDMA_TRUE;
mIsGlobalCdma = isLteOnCdma && getResources().getBoolean(R.bool.config_show_cdma);
TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
- if (tm.getSimplifiedNetworkSettingsEnabled(SubscriptionManager.getDefaultSubId())) {
+ if (tm.getSimplifiedNetworkSettingsEnabledForSubscriber(SubscriptionManager.getDefaultSubId())) {
prefSet.removePreference(mButtonPreferredNetworkMode);
prefSet.removePreference(mButtonEnabledNetworks);
prefSet.removePreference(mLteDataServicePref);
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 99cb206..2ac98d3 100644
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -21,6 +21,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
@@ -37,6 +38,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
+import android.preference.PreferenceManager;
import android.provider.Settings;
import android.telephony.CellInfo;
import android.telephony.IccOpenLogicalChannelResponse;
@@ -129,12 +131,11 @@
AppOpsManager mAppOps;
MainThreadHandler mMainThreadHandler;
- /**
- * Indicates if Android should display a simplified Mobile Network Settings UI in a specific
- * subscription.
- */
- Set<Long> mSimplifiedNetworkSettings;
- Map<Long, AdnRecord> mAdnRecordsForDisplay;
+ SharedPreferences carrierPrivilegeConfigs;
+ private static final String PREF_CARRIERS_ALPHATAG_PREFIX = "carrier_alphtag_";
+ private static final String PREF_CARRIERS_NUMBER_PREFIX = "carrier_number_";
+ private static final String PREF_CARRIERS_SIMPLIFIED_NETWORK_SETTINGS_PREFIX =
+ "carrier_simplified_network_settings_";
/**
* A request object to use for transmitting data to an ICC.
@@ -696,10 +697,10 @@
mApp = app;
mPhone = phone;
mCM = PhoneGlobals.getInstance().mCM;
- mSimplifiedNetworkSettings = new HashSet<Long>();
mAppOps = (AppOpsManager)app.getSystemService(Context.APP_OPS_SERVICE);
mMainThreadHandler = new MainThreadHandler();
- mAdnRecordsForDisplay = new HashMap<Long, AdnRecord>();
+ carrierPrivilegeConfigs =
+ PreferenceManager.getDefaultSharedPreferences(mPhone.getContext());
publish();
}
@@ -714,17 +715,17 @@
private Phone getPhone(long subId) {
// FIXME: hack for the moment
return mPhone;
- // return PhoneUtils.getPhoneUsingSubId(subId);
+ // return PhoneUtils.getPhoneForSubscriber(subId);
}
//
// Implementation of the ITelephony interface.
//
public void dial(String number) {
- dialUsingSubId(getPreferredVoiceSubscription(), number);
+ dialForSubscriber(getPreferredVoiceSubscription(), number);
}
- public void dialUsingSubId(long subId, String number) {
+ public void dialForSubscriber(long subId, String number) {
if (DBG) log("dial: " + number);
// No permission check needed here: This is just a wrapper around the
// ACTION_DIAL intent, which is available to any app since it puts up
@@ -746,10 +747,10 @@
}
public void call(String callingPackage, String number) {
- callUsingSubId(getPreferredVoiceSubscription(), callingPackage, number);
+ callForSubscriber(getPreferredVoiceSubscription(), callingPackage, number);
}
- public void callUsingSubId(long subId, String callingPackage, String number) {
+ public void callForSubscriber(long subId, String callingPackage, String number) {
if (DBG) log("call: " + number);
// This is just a wrapper around the ACTION_CALL intent, but we still
@@ -778,23 +779,23 @@
* @return true is a call was ended
*/
public boolean endCall() {
- return endCallUsingSubId(getDefaultSubscription());
+ return endCallForSubscriber(getDefaultSubscription());
}
/**
* End a call based on the call state of the subId
* @return true is a call was ended
*/
- public boolean endCallUsingSubId(long subId) {
+ public boolean endCallForSubscriber(long subId) {
enforceCallPermission();
return (Boolean) sendRequest(CMD_END_CALL, subId, null);
}
public void answerRingingCall() {
- answerRingingCallUsingSubId(getDefaultSubscription());
+ answerRingingCallForSubscriber(getDefaultSubscription());
}
- public void answerRingingCallUsingSubId(long subId) {
+ public void answerRingingCallForSubscriber(long subId) {
if (DBG) log("answerRingingCall...");
// TODO: there should eventually be a separate "ANSWER_PHONE" permission,
// but that can probably wait till the big TelephonyManager API overhaul.
@@ -865,26 +866,26 @@
}
public boolean isOffhook() {
- return isOffhookUsingSubId(getDefaultSubscription());
+ return isOffhookForSubscriber(getDefaultSubscription());
}
- public boolean isOffhookUsingSubId(long subId) {
+ public boolean isOffhookForSubscriber(long subId) {
return (getPhone(subId).getState() == PhoneConstants.State.OFFHOOK);
}
public boolean isRinging() {
- return (isRingingUsingSubId(getDefaultSubscription()));
+ return (isRingingForSubscriber(getDefaultSubscription()));
}
- public boolean isRingingUsingSubId(long subId) {
+ public boolean isRingingForSubscriber(long subId) {
return (getPhone(subId).getState() == PhoneConstants.State.RINGING);
}
public boolean isIdle() {
- return isIdleUsingSubId(getDefaultSubscription());
+ return isIdleForSubscriber(getDefaultSubscription());
}
- public boolean isIdleUsingSubId(long subId) {
+ public boolean isIdleForSubscriber(long subId) {
return (getPhone(subId).getState() == PhoneConstants.State.IDLE);
}
@@ -894,29 +895,29 @@
}
public boolean supplyPin(String pin) {
- return supplyPinUsingSubId(getDefaultSubscription(), pin);
+ return supplyPinForSubscriber(getDefaultSubscription(), pin);
}
- public boolean supplyPinUsingSubId(long subId, String pin) {
- int [] resultArray = supplyPinReportResultUsingSubId(subId, pin);
+ public boolean supplyPinForSubscriber(long subId, String pin) {
+ int [] resultArray = supplyPinReportResultForSubscriber(subId, pin);
return (resultArray[0] == PhoneConstants.PIN_RESULT_SUCCESS) ? true : false;
}
public boolean supplyPuk(String puk, String pin) {
- return supplyPukUsingSubId(getDefaultSubscription(), puk, pin);
+ return supplyPukForSubscriber(getDefaultSubscription(), puk, pin);
}
- public boolean supplyPukUsingSubId(long subId, String puk, String pin) {
- int [] resultArray = supplyPukReportResultUsingSubId(subId, puk, pin);
+ public boolean supplyPukForSubscriber(long subId, String puk, String pin) {
+ int [] resultArray = supplyPukReportResultForSubscriber(subId, puk, pin);
return (resultArray[0] == PhoneConstants.PIN_RESULT_SUCCESS) ? true : false;
}
/** {@hide} */
public int[] supplyPinReportResult(String pin) {
- return supplyPinReportResultUsingSubId(getDefaultSubscription(), pin);
+ return supplyPinReportResultForSubscriber(getDefaultSubscription(), pin);
}
- public int[] supplyPinReportResultUsingSubId(long subId, String pin) {
+ public int[] supplyPinReportResultForSubscriber(long subId, String pin) {
enforceModifyPermission();
final UnlockSim checkSimPin = new UnlockSim(getPhone(subId).getIccCard());
checkSimPin.start();
@@ -925,10 +926,10 @@
/** {@hide} */
public int[] supplyPukReportResult(String puk, String pin) {
- return supplyPukReportResultUsingSubId(getDefaultSubscription(), puk, pin);
+ return supplyPukReportResultForSubscriber(getDefaultSubscription(), puk, pin);
}
- public int[] supplyPukReportResultUsingSubId(long subId, String puk, String pin) {
+ public int[] supplyPukReportResultForSubscriber(long subId, String puk, String pin) {
enforceModifyPermission();
final UnlockSim checkSimPuk = new UnlockSim(getPhone(subId).getIccCard());
checkSimPuk.start();
@@ -1035,11 +1036,11 @@
}
public void updateServiceLocation() {
- updateServiceLocationUsingSubId(getDefaultSubscription());
+ updateServiceLocationForSubscriber(getDefaultSubscription());
}
- public void updateServiceLocationUsingSubId(long subId) {
+ public void updateServiceLocationForSubscriber(long subId) {
// No permission check needed here: this call is harmless, and it's
// needed for the ServiceState.requestStateUpdate() call (which is
// already intentionally exposed to 3rd parties.)
@@ -1047,32 +1048,32 @@
}
public boolean isRadioOn() {
- return isRadioOnUsingSubId(getDefaultSubscription());
+ return isRadioOnForSubscriber(getDefaultSubscription());
}
- public boolean isRadioOnUsingSubId(long subId) {
+ public boolean isRadioOnForSubscriber(long subId) {
return getPhone(subId).getServiceState().getState() != ServiceState.STATE_POWER_OFF;
}
public void toggleRadioOnOff() {
- toggleRadioOnOffUsingSubId(getDefaultSubscription());
+ toggleRadioOnOffForSubscriber(getDefaultSubscription());
}
- public void toggleRadioOnOffUsingSubId(long subId) {
+ public void toggleRadioOnOffForSubscriber(long subId) {
enforceModifyPermission();
- getPhone(subId).setRadioPower(!isRadioOnUsingSubId(subId));
+ getPhone(subId).setRadioPower(!isRadioOnForSubscriber(subId));
}
public boolean setRadio(boolean turnOn) {
- return setRadioUsingSubId(getDefaultSubscription(), turnOn);
+ return setRadioForSubscriber(getDefaultSubscription(), turnOn);
}
- public boolean setRadioUsingSubId(long subId, boolean turnOn) {
+ public boolean setRadioForSubscriber(long subId, boolean turnOn) {
enforceModifyPermission();
if ((getPhone(subId).getServiceState().getState() !=
ServiceState.STATE_POWER_OFF) != turnOn) {
- toggleRadioOnOffUsingSubId(subId);
+ toggleRadioOnOffForSubscriber(subId);
}
return true;
}
@@ -1106,10 +1107,10 @@
}
public boolean setRadioPower(boolean turnOn) {
- return setRadioPowerUsingSubId(getDefaultSubscription(), turnOn);
+ return setRadioPowerForSubscriber(getDefaultSubscription(), turnOn);
}
- public boolean setRadioPowerUsingSubId(long subId, boolean turnOn) {
+ public boolean setRadioPowerForSubscriber(long subId, boolean turnOn) {
enforceModifyPermission();
getPhone(subId).setRadioPower(turnOn);
return true;
@@ -1138,19 +1139,19 @@
}
public boolean handlePinMmi(String dialString) {
- return handlePinMmiUsingSubId(getDefaultSubscription(), dialString);
+ return handlePinMmiForSubscriber(getDefaultSubscription(), dialString);
}
- public boolean handlePinMmiUsingSubId(long subId, String dialString) {
+ public boolean handlePinMmiForSubscriber(long subId, String dialString) {
enforceModifyPermission();
return (Boolean) sendRequest(CMD_HANDLE_PIN_MMI, dialString, subId);
}
public int getCallState() {
- return getCallStateUsingSubId(getDefaultSubscription());
+ return getCallStateForSubscriber(getDefaultSubscription());
}
- public int getCallStateUsingSubId(long subId) {
+ public int getCallStateForSubscriber(long subId) {
return DefaultPhoneNotifier.convertCallState(getPhone(subId).getState());
}
@@ -1190,10 +1191,10 @@
@Override
public void enableLocationUpdates() {
- enableLocationUpdatesUsingSubId(getDefaultSubscription());
+ enableLocationUpdatesForSubscriber(getDefaultSubscription());
}
- public void enableLocationUpdatesUsingSubId(long subId) {
+ public void enableLocationUpdatesForSubscriber(long subId) {
mApp.enforceCallingOrSelfPermission(
android.Manifest.permission.CONTROL_LOCATION_UPDATES, null);
getPhone(subId).enableLocationUpdates();
@@ -1201,10 +1202,10 @@
@Override
public void disableLocationUpdates() {
- disableLocationUpdatesUsingSubId(getDefaultSubscription());
+ disableLocationUpdatesForSubscriber(getDefaultSubscription());
}
- public void disableLocationUpdatesUsingSubId(long subId) {
+ public void disableLocationUpdatesForSubscriber(long subId) {
mApp.enforceCallingOrSelfPermission(
android.Manifest.permission.CONTROL_LOCATION_UPDATES, null);
getPhone(subId).disableLocationUpdates();
@@ -1400,10 +1401,10 @@
}
public int getActivePhoneType() {
- return getActivePhoneTypeUsingSubId(getDefaultSubscription());
+ return getActivePhoneTypeForSubscriber(getDefaultSubscription());
}
- public int getActivePhoneTypeUsingSubId(long subId) {
+ public int getActivePhoneTypeForSubscriber(long subId) {
return getPhone(subId).getPhoneType();
}
@@ -1411,11 +1412,11 @@
* Returns the CDMA ERI icon index to display
*/
public int getCdmaEriIconIndex() {
- return getCdmaEriIconIndexUsingSubId(getDefaultSubscription());
+ return getCdmaEriIconIndexForSubscriber(getDefaultSubscription());
}
- public int getCdmaEriIconIndexUsingSubId(long subId) {
+ public int getCdmaEriIconIndexForSubscriber(long subId) {
return getPhone(subId).getCdmaEriIconIndex();
}
@@ -1425,10 +1426,10 @@
* 1 - FLASHING
*/
public int getCdmaEriIconMode() {
- return getCdmaEriIconModeUsingSubId(getDefaultSubscription());
+ return getCdmaEriIconModeForSubscriber(getDefaultSubscription());
}
- public int getCdmaEriIconModeUsingSubId(long subId) {
+ public int getCdmaEriIconModeForSubscriber(long subId) {
return getPhone(subId).getCdmaEriIconMode();
}
@@ -1436,10 +1437,10 @@
* Returns the CDMA ERI text,
*/
public String getCdmaEriText() {
- return getCdmaEriTextUsingSubId(getDefaultSubscription());
+ return getCdmaEriTextForSubscriber(getDefaultSubscription());
}
- public String getCdmaEriTextUsingSubId(long subId) {
+ public String getCdmaEriTextForSubscriber(long subId) {
return getPhone(subId).getCdmaEriText();
}
@@ -1478,13 +1479,13 @@
* Returns the unread count of voicemails
*/
public int getVoiceMessageCount() {
- return getVoiceMessageCountUsingSubId(getDefaultSubscription());
+ return getVoiceMessageCountForSubscriber(getDefaultSubscription());
}
/**
* Returns the unread count of voicemails for a subId
*/
- public int getVoiceMessageCountUsingSubId( long subId) {
+ public int getVoiceMessageCountForSubscriber( long subId) {
return getPhone(subId).getVoiceMessageCount();
}
@@ -1495,14 +1496,14 @@
*/
@Override
public int getNetworkType() {
- return getNetworkTypeUsingSubId(getDefaultSubscription());
+ return getNetworkTypeForSubscriber(getDefaultSubscription());
}
/**
* Returns the network type for a subId
*/
@Override
- public int getNetworkTypeUsingSubId(long subId) {
+ public int getNetworkTypeForSubscriber(long subId) {
return getPhone(subId).getServiceState().getDataNetworkType();
}
@@ -1511,14 +1512,14 @@
*/
@Override
public int getDataNetworkType() {
- return getDataNetworkTypeUsingSubId(getDefaultSubscription());
+ return getDataNetworkTypeForSubscriber(getDefaultSubscription());
}
/**
* Returns the data network type for a subId
*/
@Override
- public int getDataNetworkTypeUsingSubId(long subId) {
+ public int getDataNetworkTypeForSubscriber(long subId) {
return getPhone(subId).getServiceState().getDataNetworkType();
}
@@ -1527,14 +1528,14 @@
*/
@Override
public int getVoiceNetworkType() {
- return getVoiceNetworkTypeUsingSubId(getDefaultSubscription());
+ return getVoiceNetworkTypeForSubscriber(getDefaultSubscription());
}
/**
* Returns the Voice network type for a subId
*/
@Override
- public int getVoiceNetworkTypeUsingSubId(long subId) {
+ public int getVoiceNetworkTypeForSubscriber(long subId) {
return getPhone(subId).getServiceState().getVoiceNetworkType();
}
@@ -1562,10 +1563,10 @@
* or {@link Phone#LTE_ON_CDMA_TRUE}
*/
public int getLteOnCdmaMode() {
- return getLteOnCdmaModeUsingSubId(getDefaultSubscription());
+ return getLteOnCdmaModeForSubscriber(getDefaultSubscription());
}
- public int getLteOnCdmaModeUsingSubId(long subId) {
+ public int getLteOnCdmaModeForSubscriber(long subId) {
return getPhone(subId).getLteOnCdmaMode();
}
@@ -1929,52 +1930,94 @@
mPhone.getContext().getPackageManager(), intent);
}
+ private String getIccId(long subId) {
+ UiccCard card = getPhone(subId).getUiccCard();
+ if (card == null) {
+ loge("getIccId: No UICC");
+ return null;
+ }
+ String iccId = card.getIccId();
+ if (TextUtils.isEmpty(iccId)) {
+ loge("getIccId: ICC ID is null or empty.");
+ return null;
+ }
+ return iccId;
+ }
+
@Override
- public void enableSimplifiedNetworkSettings(long subId, boolean enable) {
+ public void enableSimplifiedNetworkSettingsForSubscriber(long subId, boolean enable) {
enforceModifyPermissionOrCarrierPrivilege();
- if (enable) {
- mSimplifiedNetworkSettings.add(subId);
- } else {
- mSimplifiedNetworkSettings.remove(subId);
+
+ String iccId = getIccId(subId);
+ if (iccId != null) {
+ String snsPrefKey = PREF_CARRIERS_SIMPLIFIED_NETWORK_SETTINGS_PREFIX + iccId;
+ SharedPreferences.Editor editor = carrierPrivilegeConfigs.edit();
+ if (enable) {
+ editor.putBoolean(snsPrefKey, true);
+ } else {
+ editor.remove(snsPrefKey);
+ }
+ editor.commit();
}
}
@Override
- public boolean getSimplifiedNetworkSettingsEnabled(long subId) {
+ public boolean getSimplifiedNetworkSettingsEnabledForSubscriber(long subId) {
enforceReadPermission();
- return mSimplifiedNetworkSettings.contains(subId);
+ String iccId = getIccId(subId);
+ if (iccId != null) {
+ String snsPrefKey = PREF_CARRIERS_SIMPLIFIED_NETWORK_SETTINGS_PREFIX + iccId;
+ return carrierPrivilegeConfigs.getBoolean(snsPrefKey, false);
+ }
+ return false;
}
@Override
- public void setLine1NumberForDisplay(long subId, String alphaTag, String number) {
+ public void setLine1NumberForDisplayForSubscriber(long subId, String alphaTag, String number) {
enforceModifyPermissionOrCarrierPrivilege();
- mAdnRecordsForDisplay.put(subId, new AdnRecord(alphaTag, number));
+
+ String iccId = getIccId(subId);
+ if (iccId != null) {
+ String alphaTagPrefKey = PREF_CARRIERS_ALPHATAG_PREFIX + iccId;
+ SharedPreferences.Editor editor = carrierPrivilegeConfigs.edit();
+ if (alphaTag == null) {
+ editor.remove(alphaTagPrefKey);
+ } else {
+ editor.putString(alphaTagPrefKey, alphaTag);
+ }
+
+ String numberPrefKey = PREF_CARRIERS_NUMBER_PREFIX + iccId;
+ if (number == null) {
+ editor.remove(numberPrefKey);
+ } else {
+ editor.putString(numberPrefKey, number);
+ }
+ editor.commit();
+ }
}
@Override
public String getLine1NumberForDisplay(long subId) {
enforceReadPermission();
- if (!mAdnRecordsForDisplay.containsKey(subId)) {
- return null;
+
+ String iccId = getIccId(subId);
+ if (iccId != null) {
+ String numberPrefKey = PREF_CARRIERS_NUMBER_PREFIX + iccId;
+ return carrierPrivilegeConfigs.getString(numberPrefKey, null);
}
- AdnRecord adnRecord = mAdnRecordsForDisplay.get(subId);
- if (adnRecord.getNumber() == null || adnRecord.getNumber().isEmpty()) {
- return null;
- }
- return adnRecord.getNumber();
+ return null;
}
@Override
public String getLine1AlphaTagForDisplay(long subId) {
enforceReadPermission();
- if (!mAdnRecordsForDisplay.containsKey(subId)) {
- return null;
+
+ String iccId = getIccId(subId);
+ if (iccId != null) {
+ String alphaTagPrefKey = PREF_CARRIERS_ALPHATAG_PREFIX + iccId;
+ return carrierPrivilegeConfigs.getString(alphaTagPrefKey, null);
}
- AdnRecord adnRecord = mAdnRecordsForDisplay.get(subId);
- if (adnRecord.getAlphaTag() == null || adnRecord.getAlphaTag().isEmpty()) {
- return null;
- }
- return adnRecord.getAlphaTag();
+ return null;
}
@Override
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/CdmaConnection.java b/src/com/android/services/telephony/CdmaConnection.java
index cb99b55..b204208 100644
--- a/src/com/android/services/telephony/CdmaConnection.java
+++ b/src/com/android/services/telephony/CdmaConnection.java
@@ -129,11 +129,11 @@
}
@Override
- public void onSetState(int state) {
+ public void onStateChanged(int state) {
Connection originalConnection = getOriginalConnection();
mIsCallWaiting = originalConnection != null &&
originalConnection.getState() == Call.State.WAITING;
- super.onSetState(state);
+ super.onStateChanged(state);
}
@Override
diff --git a/src/com/android/services/telephony/TelecommAccountRegistry.java b/src/com/android/services/telephony/TelecommAccountRegistry.java
index 1eaf6e1..f6220bb 100644
--- a/src/com/android/services/telephony/TelecommAccountRegistry.java
+++ b/src/com/android/services/telephony/TelecommAccountRegistry.java
@@ -25,14 +25,18 @@
import android.telecomm.PhoneAccount;
import android.telecomm.PhoneAccountHandle;
import android.telecomm.TelecommManager;
+import android.telephony.SubInfoRecord;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import android.text.TextUtils;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneFactory;
import com.android.internal.telephony.PhoneProxy;
import com.android.internal.telephony.TelephonyIntents;
+import com.android.phone.R;
+import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
@@ -41,14 +45,21 @@
* removal of SIMs and SIP accounts.
*/
final class TelecommAccountRegistry {
+ private static final boolean DBG = false; /* STOP SHIP if true */
+
+ // Slot IDs are zero based indices but the numbered icons represent the first, second,
+ // etc... SIM in the device. So that means that index 0 is SIM 1, index 1 is SIM 2 and so on.
private final static int[] phoneAccountIcons = {
- com.android.phone.R.drawable.ic_multi_sim,
- com.android.phone.R.drawable.ic_multi_sim1,
- com.android.phone.R.drawable.ic_multi_sim2,
- com.android.phone.R.drawable.ic_multi_sim3,
- com.android.phone.R.drawable.ic_multi_sim4
+ R.drawable.ic_multi_sim1,
+ R.drawable.ic_multi_sim2,
+ R.drawable.ic_multi_sim3,
+ R.drawable.ic_multi_sim4
};
+ // This icon is the one that is used when the Slot ID that we have for a particular SIM
+ // is not supported, i.e. SubscriptionManager.INVALID_SLOT_ID or the 5th SIM in a phone.
+ private final static int defaultPhoneAccountIcon = R.drawable.ic_multi_sim;
+
private final class AccountEntry {
private final Phone mPhone;
private final PhoneAccount mAccount;
@@ -63,7 +74,6 @@
}
void teardown() {
- mTelecommManager.unregisterPhoneAccount(mAccount.getAccountHandle());
mIncomingCallNotifier.teardown();
}
@@ -80,8 +90,7 @@
// Populate the phone account data.
long subId = mPhone.getSubId();
- int slotId = mPhone.getPhoneId() + 1;
- String line1Number = telephonyManager.getLine1Number(subId);
+ String line1Number = telephonyManager.getLine1NumberForSubscriber(subId);
if (line1Number == null) {
line1Number = "";
}
@@ -89,34 +98,78 @@
if (subNumber == null) {
subNumber = "";
}
- String label = isEmergency
- ? "Emergency calls"
- : dummyPrefix + "SIM " + slotId;
- String description = isEmergency
- ? "Emergency calling only"
- : dummyPrefix + "SIM card in slot " + slotId;
- PhoneAccount account = PhoneAccount.builder()
- .withAccountHandle(phoneAccountHandle)
- .withHandle(Uri.fromParts(PhoneAccount.SCHEME_TEL, line1Number, null))
- .withSubscriptionNumber(subNumber)
- .withCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION |
- PhoneAccount.CAPABILITY_CALL_PROVIDER)
- .withIconResId(getPhoneAccountIcon(slotId))
- .withLabel(label)
- .withShortDescription(description)
- .withSupportedUriScheme(PhoneAccount.SCHEME_TEL)
- .withSupportedUriScheme(PhoneAccount.SCHEME_VOICEMAIL)
+
+ String subDisplayName = null;
+ // We can only get the real slotId from the SubInfoRecord, we can't calculate the
+ // slotId from the subId or the phoneId in all instances.
+ SubInfoRecord record = SubscriptionManager.getSubInfoForSubscriber(subId);
+ int slotId = SubscriptionManager.INVALID_SLOT_ID;
+ if (record != null) {
+ subDisplayName = record.displayName;
+ slotId = record.slotId;
+ }
+
+ String slotIdString;
+ if (SubscriptionManager.isValidSlotId(slotId)) {
+ slotIdString = Integer.toString(slotId);
+ } else {
+ slotIdString = mContext.getResources().getString(R.string.unknown);
+ }
+
+ if (TextUtils.isEmpty(subDisplayName)) {
+ // Either the sub record is not there or it has an empty display name.
+ Log.w(this, "Could not get a display name for subid: %d", subId);
+ subDisplayName = mContext.getResources().getString(
+ R.string.sim_description_default, slotIdString);
+ }
+
+ // The label is user-visible so let's use the display name that the user may
+ // have set in Settings->Sim cards.
+ String label = isEmergency ?
+ mContext.getResources().getString(R.string.sim_label_emergency_calls) :
+ dummyPrefix + subDisplayName;
+ String description = isEmergency ?
+ mContext.getResources().getString(R.string.sim_description_emergency_calls) :
+ dummyPrefix + mContext.getResources().getString(
+ R.string.sim_description_default, slotIdString);
+
+ // 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(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() {
@Override
public void onReceive(Context context, Intent intent) {
+ boolean rebuildAccounts = false;
String action = intent.getAction();
if (TelephonyIntents.ACTION_SUBINFO_RECORD_UPDATED.equals(action)) {
int status = intent.getIntExtra(
@@ -126,6 +179,15 @@
// Anytime the SIM state changes...rerun the setup
// We rely on this notification even when the status is EXTRA_VALUE_NOCHANGE,
// so we explicitly do not check for that here.
+ rebuildAccounts = true;
+ } else if (TelephonyIntents.ACTION_SUBINFO_CONTENT_CHANGE.equals(action)) {
+ String columnName = intent.getStringExtra(TelephonyIntents.EXTRA_COLUMN_NAME);
+ String stringContent = intent.getStringExtra(TelephonyIntents.EXTRA_STRING_CONTENT);
+ Log.v(this, "SUBINFO_CONTENT_CHANGE: Column: %s Content: %s",
+ columnName, stringContent);
+ rebuildAccounts = true;
+ }
+ if (rebuildAccounts) {
tearDownAccounts();
setupAccounts();
}
@@ -153,11 +215,12 @@
* Sets up all the phone accounts for SIMs on first boot.
*/
void setupOnBoot() {
- IntentFilter intentFilter =
- new IntentFilter(TelephonyIntents.ACTION_SUBINFO_RECORD_UPDATED);
+ // We need to register for both types of intents if we want to see added/removed Subs
+ // along with changes to a given Sub.
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(TelephonyIntents.ACTION_SUBINFO_RECORD_UPDATED);
+ intentFilter.addAction(TelephonyIntents.ACTION_SUBINFO_CONTENT_CHANGE);
mContext.registerReceiver(mReceiver, intentFilter);
-
- setupAccounts();
}
static PhoneAccountHandle makePstnPhoneAccountHandle(Phone phone) {
@@ -174,22 +237,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) {
@@ -209,19 +293,22 @@
}
// 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 */));
}
- // TODO: Add SIP accounts.
+ // Clean up any PhoneAccounts that are no longer relevant
+ cleanupPhoneAccounts();
}
private int getPhoneAccountIcon(int index) {
- if (index < TelecommAccountRegistry.phoneAccountIcons.length) {
+ // A valid slot id doesn't necessarily mean that we have an icon for it.
+ if (SubscriptionManager.isValidSlotId(index) &&
+ index < TelecommAccountRegistry.phoneAccountIcons.length) {
return TelecommAccountRegistry.phoneAccountIcons[index];
}
- // default blank icon
- return TelecommAccountRegistry.phoneAccountIcons[0];
+ // Invalid indices get the default icon that has no number associated with it.
+ return defaultPhoneAccountIcon;
}
private void tearDownAccounts() {
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index 60e5d17..91fd49e 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -30,6 +30,7 @@
import com.android.internal.telephony.CallStateException;
import com.android.internal.telephony.Connection.PostDialListener;
import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.imsphone.ImsPhoneConnection;
import java.lang.Override;
import java.util.Objects;
@@ -66,7 +67,7 @@
"not foreground connection, skipping");
return;
}
- setRequestingRingback((Boolean) ((AsyncResult) msg.obj).result);
+ setRingbackRequested((Boolean) ((AsyncResult) msg.obj).result);
break;
}
}
@@ -174,7 +175,7 @@
}
@Override
- public void onSetAudioState(AudioState audioState) {
+ public void onAudioStateChanged(AudioState audioState) {
// TODO: update TTY mode.
if (getPhone() != null) {
getPhone().setEchoSuppressionEnabled();
@@ -182,8 +183,8 @@
}
@Override
- public void onSetState(int state) {
- Log.v(this, "onSetState, state: " + Connection.stateToString(state));
+ public void onStateChanged(int state) {
+ Log.v(this, "onStateChanged, state: " + Connection.stateToString(state));
}
@Override
@@ -253,11 +254,6 @@
}
}
- @Override
- public void onPhoneAccountClicked() {
- Log.v(this, "onPhoneAccountClicked");
- }
-
public void performHold() {
Log.v(this, "performHold");
// TODO: Can dialing calls be put on hold as well since they take up the
@@ -331,28 +327,29 @@
int newCallCapabilities = buildCallCapabilities();
newCallCapabilities = applyVideoCapabilities(newCallCapabilities);
newCallCapabilities = applyAudioQualityCapabilities(newCallCapabilities);
+ newCallCapabilities = applyConferenceTerminationCapabilities(newCallCapabilities);
if (getCallCapabilities() != newCallCapabilities) {
setCallCapabilities(newCallCapabilities);
}
}
- protected final void updateHandle() {
+ protected final void updateAddress() {
updateCallCapabilities();
if (mOriginalConnection != null) {
- Uri handle = getHandleFromAddress(mOriginalConnection.getAddress());
+ Uri address = getAddressFromNumber(mOriginalConnection.getAddress());
int presentation = mOriginalConnection.getNumberPresentation();
- if (!Objects.equals(handle, getHandle()) ||
- presentation != getHandlePresentation()) {
- Log.v(this, "updateHandle, handle changed");
- setHandle(handle, presentation);
+ if (!Objects.equals(address, getAddress()) ||
+ presentation != getAddressPresentation()) {
+ Log.v(this, "updateAddress, address changed");
+ setAddress(address, presentation);
}
String name = mOriginalConnection.getCnapName();
int namePresentation = mOriginalConnection.getCnapNamePresentation();
if (!Objects.equals(name, getCallerDisplayName()) ||
namePresentation != getCallerDisplayNamePresentation()) {
- Log.v(this, "updateHandle, caller display name changed");
+ Log.v(this, "updateAddress, caller display name changed");
setCallerDisplayName(name, namePresentation);
}
}
@@ -385,7 +382,7 @@
setVideoProvider(mOriginalConnection.getVideoProvider());
setAudioQuality(mOriginalConnection.getAudioQuality());
- updateHandle();
+ updateAddress();
}
protected void hangup(int disconnectCause) {
@@ -523,7 +520,7 @@
}
}
updateCallCapabilities();
- updateHandle();
+ updateAddress();
}
private void close() {
@@ -585,6 +582,27 @@
}
/**
+ * Applies capabilities specific to conferences termination to the
+ * {@code CallCapabilities} bit-mask.
+ *
+ * @param callCapabilities The {@code CallCapabilities} bit-mask.
+ * @return The capabilities with the IMS conference capabilities applied.
+ */
+ private int applyConferenceTerminationCapabilities(int callCapabilities) {
+ int currentCapabilities = callCapabilities;
+
+ // An IMS call cannot be individually disconnected or separated from its parent conference
+ boolean isImsCall = getOriginalConnection() instanceof ImsPhoneConnection;
+ if (!isImsCall) {
+ currentCapabilities |=
+ PhoneCapabilities.DISCONNECT_FROM_CONFERENCE
+ | PhoneCapabilities.SEPARATE_FROM_CONFERENCE;
+ }
+
+ return currentCapabilities;
+ }
+
+ /**
* Returns the local video capability state for the connection.
*
* @return {@code True} if the connection has local video capabilities.
@@ -635,12 +653,19 @@
updateCallCapabilities();
}
- private static Uri getHandleFromAddress(String address) {
+ /**
+ * Obtains the current call audio quality.
+ */
+ public int getAudioQuality() {
+ return mAudioQuality;
+ }
+
+ private static Uri getAddressFromNumber(String number) {
// Address can be null for blocked calls.
- if (address == null) {
- address = "";
+ if (number == null) {
+ number = "";
}
- return Uri.fromParts(PhoneAccount.SCHEME_TEL, address, null);
+ return Uri.fromParts(PhoneAccount.SCHEME_TEL, number, null);
}
/**
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 5d96665..38b6001 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -65,7 +65,7 @@
final ConnectionRequest request) {
Log.i(this, "onCreateOutgoingConnection, request: " + request);
- Uri handle = request.getHandle();
+ Uri handle = request.getAddress();
if (handle == null) {
Log.d(this, "onCreateOutgoingConnection, handle is null");
return Connection.createFailedConnection(DisconnectCause.NO_PHONE_NUMBER_SUPPLIED,
@@ -143,7 +143,7 @@
return Connection.createFailedConnection(
DisconnectCause.OUTGOING_FAILURE, "Invalid phone type");
}
- connection.setHandle(handle, PhoneConstants.PRESENTATION_ALLOWED);
+ connection.setAddress(handle, PhoneConstants.PRESENTATION_ALLOWED);
connection.setInitializing();
connection.setVideoState(request.getVideoState());
@@ -224,7 +224,7 @@
private void placeOutgoingConnection(
TelephonyConnection connection, Phone phone, ConnectionRequest request) {
- String number = connection.getHandle().getSchemeSpecificPart();
+ String number = connection.getAddress().getSchemeSpecificPart();
com.android.internal.telephony.Connection originalConnection;
try {