diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 17f1e542a79..72defac760c 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -1896,6 +1896,20 @@ android:resource="@xml/file_paths" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values/dimens.xml b/res/values/dimens.xml index eda676f4c19..4d06c1c727c 100755 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -192,4 +192,13 @@ 40dp + + 8dip + + 16dip + + 8dip + + 32 + diff --git a/res/values/strings.xml b/res/values/strings.xml index 76fdafc0961..1298289b2a4 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -5422,6 +5422,8 @@ SIM cards SIM cards + + %1$s - %2$s SIM cards have changed @@ -5436,6 +5438,8 @@ Select a SIM card SIM %1$d + + SIM empty SIM name diff --git a/res/xml/dashboard_categories.xml b/res/xml/dashboard_categories.xml index 53a6d5a6928..01a4f8386c1 100644 --- a/res/xml/dashboard_categories.xml +++ b/res/xml/dashboard_categories.xml @@ -38,6 +38,14 @@ android:icon="@drawable/ic_settings_bluetooth2" /> + + + + + + + + + + + + + + + + + + + + diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java index 01149f32b21..fcaa7aeb46f 100644 --- a/src/com/android/settings/Settings.java +++ b/src/com/android/settings/Settings.java @@ -28,6 +28,7 @@ public class Settings extends SettingsActivity { */ public static class BluetoothSettingsActivity extends SettingsActivity { /* empty */ } public static class WirelessSettingsActivity extends SettingsActivity { /* empty */ } + public static class SimSettingsActivity extends SettingsActivity { /* empty */ } public static class TetherSettingsActivity extends SettingsActivity { /* empty */ } public static class VpnSettingsActivity extends SettingsActivity { /* empty */ } public static class DateTimeSettingsActivity extends SettingsActivity { /* empty */ } diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java index 90e8fd4f536..bd53eb66478 100644 --- a/src/com/android/settings/SettingsActivity.java +++ b/src/com/android/settings/SettingsActivity.java @@ -100,6 +100,7 @@ import com.android.settings.notification.NotificationStation; import com.android.settings.notification.ZenModeSettings; import com.android.settings.print.PrintJobSettingsFragment; import com.android.settings.print.PrintSettingsFragment; +import com.android.settings.sim.SimSettings; import com.android.settings.tts.TextToSpeechSettings; import com.android.settings.users.UserSettings; import com.android.settings.vpn2.VpnSettings; @@ -204,6 +205,7 @@ public class SettingsActivity extends Activity R.id.wifi_settings, R.id.bluetooth_settings, R.id.data_usage_settings, + R.id.sim_settings, R.id.wireless_settings, R.id.device_section, R.id.notification_settings, @@ -234,6 +236,7 @@ public class SettingsActivity extends Activity SavedAccessPointsWifiSettings.class.getName(), BluetoothSettings.class.getName(), MessageAccessSettings.class.getName(), + SimSettings.class.getName(), TetherSettings.class.getName(), WifiP2pSettings.class.getName(), VpnSettings.class.getName(), @@ -1034,7 +1037,10 @@ public class SettingsActivity extends Activity curBundle = null; } - category.addTile(tile); + // Show the SIM Cards setting if there are more than 2 SIMs installed. + if(tile.id != R.id.sim_settings || SimSettings.showSimCardScreen(this)){ + category.addTile(tile); + } } else { XmlUtils.skipCurrentTag(parser); diff --git a/src/com/android/settings/notification/DropDownPreference.java b/src/com/android/settings/notification/DropDownPreference.java index 45c83a5d2f9..1d1b366785b 100644 --- a/src/com/android/settings/notification/DropDownPreference.java +++ b/src/com/android/settings/notification/DropDownPreference.java @@ -106,6 +106,11 @@ public class DropDownPreference extends Preference { mValues.add(value); } + public void clearItems(){ + mAdapter.clear(); + mValues.clear(); + } + @Override protected void onBindView(View view) { super.onBindView(view); @@ -123,4 +128,4 @@ public class DropDownPreference extends Preference { public interface Callback { boolean onItemSelected(int pos, Object value); } -} \ No newline at end of file +} diff --git a/src/com/android/settings/search/Ranking.java b/src/com/android/settings/search/Ranking.java index 96e057e0d63..44717c15443 100644 --- a/src/com/android/settings/search/Ranking.java +++ b/src/com/android/settings/search/Ranking.java @@ -41,6 +41,7 @@ import com.android.settings.notification.NotificationSettings; import com.android.settings.notification.OtherSoundSettings; import com.android.settings.notification.ZenModeSettings; import com.android.settings.print.PrintSettingsFragment; +import com.android.settings.sim.SimSettings; import com.android.settings.users.UserSettings; import com.android.settings.wifi.AdvancedWifiSettings; import com.android.settings.wifi.SavedAccessPointsWifiSettings; @@ -55,24 +56,25 @@ public final class Ranking { public static final int RANK_WIFI = 1; public static final int RANK_BT = 2; - public static final int RANK_DATA_USAGE = 3; - public static final int RANK_WIRELESS = 4; - public static final int RANK_HOME = 5; - public static final int RANK_DISPLAY = 6; - public static final int RANK_WALLPAPER = 7; - public static final int RANK_NOTIFICATIONS = 8; - public static final int RANK_MEMORY = 9; - public static final int RANK_POWER_USAGE = 10; - public static final int RANK_USERS = 11; - public static final int RANK_LOCATION = 12; - public static final int RANK_SECURITY = 13; - public static final int RANK_IME = 14; - public static final int RANK_PRIVACY = 15; - public static final int RANK_DATE_TIME = 16; - public static final int RANK_ACCESSIBILITY = 17; - public static final int RANK_PRINTING = 18; - public static final int RANK_DEVELOPEMENT = 19; - public static final int RANK_DEVICE_INFO = 20; + public static final int RANK_SIM = 3; + public static final int RANK_DATA_USAGE = 4; + public static final int RANK_WIRELESS = 5; + public static final int RANK_HOME = 6; + public static final int RANK_DISPLAY = 7; + public static final int RANK_WALLPAPER = 8; + public static final int RANK_NOTIFICATIONS = 9; + public static final int RANK_MEMORY = 10; + public static final int RANK_POWER_USAGE = 11; + public static final int RANK_USERS = 12; + public static final int RANK_LOCATION = 13; + public static final int RANK_SECURITY = 14; + public static final int RANK_IME = 15; + public static final int RANK_PRIVACY = 16; + public static final int RANK_DATE_TIME = 17; + public static final int RANK_ACCESSIBILITY = 18; + public static final int RANK_PRINTING = 19; + public static final int RANK_DEVELOPEMENT = 20; + public static final int RANK_DEVICE_INFO = 21; public static final int RANK_UNDEFINED = -1; public static final int RANK_OTHERS = 1024; @@ -93,6 +95,9 @@ public final class Ranking { sRankMap.put(BluetoothSettings.class.getName(), RANK_BT); sRankMap.put(MessageAccessSettings.class.getName(), RANK_BT); + // SIM Cards + sRankMap.put(SimSettings.class.getName(), RANK_SIM); + // DataUsage sRankMap.put(DataUsageSummary.class.getName(), RANK_DATA_USAGE); sRankMap.put(DataUsageMeteredSettings.class.getName(), RANK_DATA_USAGE); diff --git a/src/com/android/settings/search/SearchIndexableResources.java b/src/com/android/settings/search/SearchIndexableResources.java index 4749733ed41..a3d2b8d713f 100644 --- a/src/com/android/settings/search/SearchIndexableResources.java +++ b/src/com/android/settings/search/SearchIndexableResources.java @@ -44,6 +44,7 @@ import com.android.settings.notification.NotificationSettings; import com.android.settings.notification.OtherSoundSettings; import com.android.settings.notification.ZenModeSettings; import com.android.settings.print.PrintSettingsFragment; +import com.android.settings.sim.SimSettings; import com.android.settings.users.UserSettings; import com.android.settings.wifi.AdvancedWifiSettings; import com.android.settings.wifi.SavedAccessPointsWifiSettings; @@ -88,6 +89,13 @@ public final class SearchIndexableResources { BluetoothSettings.class.getName(), R.drawable.ic_settings_bluetooth2)); + sResMap.put(SimSettings.class.getName(), + new SearchIndexableResource( + Ranking.getRankForClassName(SimSettings.class.getName()), + R.xml.sim_settings, + SimSettings.class.getName(), + R.drawable.ic_sim_sd)); + sResMap.put(MessageAccessSettings.class.getName(), new SearchIndexableResource( Ranking.getRankForClassName(MessageAccessSettings.class.getName()), diff --git a/src/com/android/settings/sim/SimSettings.java b/src/com/android/settings/sim/SimSettings.java new file mode 100644 index 00000000000..2e1c0f5bc8b --- /dev/null +++ b/src/com/android/settings/sim/SimSettings.java @@ -0,0 +1,373 @@ +/* + * 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.settings.sim; + +import com.android.settings.R; + +import android.app.AlertDialog; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.DialogInterface; +import android.content.res.Resources; +import android.os.Bundle; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.UserHandle; +import android.preference.ListPreference; +import android.preference.Preference; +import android.preference.PreferenceCategory; +import android.preference.Preference.OnPreferenceChangeListener; +import android.preference.PreferenceScreen; +import android.telephony.SubInfoRecord; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; +import android.telecomm.PhoneAccount; +import android.telephony.CellInfo; +import android.text.TextUtils; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.ArrayAdapter; +import android.widget.EditText; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.Spinner; +import android.widget.TextView; + +import com.android.internal.telephony.PhoneConstants; +import com.android.internal.telephony.TelephonyIntents; +import com.android.settings.RestrictedSettingsFragment; +import com.android.settings.SettingsPreferenceFragment; +import com.android.settings.notification.DropDownPreference; +import com.android.settings.search.BaseSearchIndexProvider; +import com.android.settings.search.Indexable; +import com.android.settings.search.Indexable.SearchIndexProvider; +import com.android.settings.search.SearchIndexableRaw; + +import java.util.ArrayList; +import java.util.List; + +public class SimSettings extends RestrictedSettingsFragment implements Indexable { + private static final String TAG = "SimSettings"; + + private static final String DISALLOW_CONFIG_SIM = "no_config_sim"; + private static final String SIM_CARD_CATEGORY = "sim_cards"; + private static final String KEY_CELLULAR_DATA = "sim_cellular_data"; + private static final String KEY_CALLS = "sim_calls"; + private static final String KEY_SMS = "sim_sms"; + private static final String KEY_ACTIVITIES = "activities"; + + /** + * By UX design we have use only one Subscription Information(SubInfo) record per SIM slot. + * mAvalableSubInfos is the list of SubInfos we present to the user. + * mSubInfoList is the list of all SubInfos. + */ + private List mAvailableSubInfos = null; + private List mSubInfoList = null; + + private SubInfoRecord mCellularData = null; + private SubInfoRecord mCalls = null; + private SubInfoRecord mSMS = null; + + /** + * Return whether or not the user should have a SIM Cards option in Settings. + * TODO: Change back to returning true if count is greater than one after testing. + * TODO: See bug 16533525. + */ + public static boolean showSimCardScreen(Context context) { + final TelephonyManager tm = + (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); + + return tm.getSimCount() > 0; + } + + public SimSettings() { + super(DISALLOW_CONFIG_SIM); + } + + @Override + public void onCreate(final Bundle bundle) { + super.onCreate(bundle); + + if (mSubInfoList == null) { + mSubInfoList = SubscriptionManager.getActivatedSubInfoList(getActivity()); + } + + createPreferences(); + updateAllOptions(); + } + + private void createPreferences() { + final TelephonyManager tm = + (TelephonyManager) getActivity().getSystemService(Context.TELEPHONY_SERVICE); + + addPreferencesFromResource(R.xml.sim_settings); + + final PreferenceCategory simCards = (PreferenceCategory)findPreference(SIM_CARD_CATEGORY); + + final int numSlots = tm.getSimCount(); + mAvailableSubInfos = new ArrayList(numSlots); + for (int i = 0; i < numSlots; ++i) { + final SubInfoRecord sir = findRecordBySlotId(i); + simCards.addPreference(new SimPreference(getActivity(), sir, i)); + mAvailableSubInfos.add(sir); + } + + updateActivitesCategory(); + } + + private void updateAllOptions() { + updateSimSlotValues(); + updateActivitesCategory(); + } + + private void updateSimSlotValues() { + SubscriptionManager.getAllSubInfoList(getActivity()); + final PreferenceCategory simCards = (PreferenceCategory)findPreference(SIM_CARD_CATEGORY); + final PreferenceScreen prefScreen = getPreferenceScreen(); + + final int prefSize = prefScreen.getPreferenceCount(); + for (int i = 0; i < prefSize; ++i) { + Preference pref = prefScreen.getPreference(i); + if (pref instanceof SimPreference) { + ((SimPreference)pref).update(); + } + } + } + + private void updateActivitesCategory() { + createDropDown((DropDownPreference) findPreference(KEY_CELLULAR_DATA)); + createDropDown((DropDownPreference) findPreference(KEY_CALLS)); + createDropDown((DropDownPreference) findPreference(KEY_SMS)); + + updateCellularDataValues(); + updateCallValues(); + updateSmsValues(); + } + + /** + * finds a record with subId. + * Since the number of SIMs are few, an array is fine. + */ + private SubInfoRecord findRecordBySubId(final long subId) { + final int availableSubInfoLength = mAvailableSubInfos.size(); + + for (int i = 0; i < availableSubInfoLength; ++i) { + final SubInfoRecord sir = mAvailableSubInfos.get(i); + if (sir != null && sir.mSubId == subId) { + return sir; + } + } + + return null; + } + + /** + * finds a record with slotId. + * Since the number of SIMs are few, an array is fine. + */ + private SubInfoRecord findRecordBySlotId(final int slotId) { + if (mSubInfoList != null){ + final int availableSubInfoLength = mSubInfoList.size(); + + for (int i = 0; i < availableSubInfoLength; ++i) { + final SubInfoRecord sir = mSubInfoList.get(i); + if (sir.mSlotId == slotId) { + //Right now we take the first subscription on a SIM. + return sir; + } + } + } + + return null; + } + + private void updateSmsValues() { + final DropDownPreference simPref = (DropDownPreference) findPreference(KEY_SMS); + final SubInfoRecord sir = findRecordBySubId(SubscriptionManager.getPreferredSmsSubId()); + if (sir != null) { + simPref.setSelectedItem(sir.mSlotId + 1); + } + } + + private void updateCellularDataValues() { + final DropDownPreference simPref = (DropDownPreference) findPreference(KEY_CELLULAR_DATA); + final SubInfoRecord sir = findRecordBySubId(SubscriptionManager.getDefaultDataSubId()); + if (sir != null) { + simPref.setSelectedItem(sir.mSlotId); + } + } + + private void updateCallValues() { + final DropDownPreference simPref = (DropDownPreference) findPreference(KEY_CALLS); + final SubInfoRecord sir = findRecordBySubId(SubscriptionManager.getDefaultVoiceSubId()); + if (sir != null) { + simPref.setSelectedItem(sir.mSlotId + 1); + } + } + + @Override + public void onResume() { + super.onResume(); + updateAllOptions(); + } + + @Override + public boolean onPreferenceTreeClick(final PreferenceScreen preferenceScreen, + final Preference preference) { + if (preference instanceof SimPreference) { + ((SimPreference)preference).createEditDialog((SimPreference)preference); + } + + return true; + } + + public void createDropDown(DropDownPreference preference) { + final DropDownPreference simPref = preference; + final String keyPref = simPref.getKey(); + final boolean askFirst = keyPref.equals(KEY_CALLS) || keyPref.equals(KEY_SMS); + + simPref.clearItems(); + + if (askFirst) { + simPref.addItem(getResources().getString( + R.string.sim_calls_ask_first_prefs_title), null); + } + + final int subAvailableSize = mAvailableSubInfos.size(); + for (int i = 0; i < subAvailableSize; ++i) { + final SubInfoRecord sir = mAvailableSubInfos.get(i); + if(sir != null){ + simPref.addItem(sir.mDisplayName, sir); + } + } + + simPref.setCallback(new DropDownPreference.Callback() { + @Override + public boolean onItemSelected(int pos, Object value) { + final long subId = value == null ? 0 : ((SubInfoRecord)value).mSubId; + + if (simPref.getKey().equals(KEY_CELLULAR_DATA)) { + SubscriptionManager.setDefaultDataSubId(subId); + } else if (simPref.getKey().equals(KEY_CALLS)) { + SubscriptionManager.setDefaultVoiceSubId(subId); + } else if (simPref.getKey().equals(KEY_SMS)) { + // TODO: uncomment once implemented. Bug: 16520931 + // SubscriptionManager.setDefaultSMSSubId(subId); + } + + updateAllOptions(); + + return true; + } + }); + } + + private void setActivity(Preference preference, SubInfoRecord sir) { + final String key = preference.getKey(); + + if (key.equals(KEY_CELLULAR_DATA)) { + mCellularData = sir; + } else if (key.equals(KEY_CALLS)) { + mCalls = sir; + } else if (key.equals(KEY_SMS)) { + mSMS = sir; + } + + updateActivitesCategory(); + } + + private class SimPreference extends Preference{ + private SubInfoRecord mSubInfoRecord; + private int mSlotId; + + public SimPreference(Context context, SubInfoRecord subInfoRecord, int slotId) { + super(context); + + mSubInfoRecord = subInfoRecord; + mSlotId = slotId; + setKey("sim" + mSlotId); + update(); + } + + public void update() { + final Resources res = getResources(); + + setTitle(res.getString(R.string.sim_card_number_title, mSlotId + 1)); + if (mSubInfoRecord != null) { + setSummary(res.getString(R.string.sim_settings_summary, + mSubInfoRecord.mDisplayName, mSubInfoRecord.mNumber)); + setEnabled(true); + } else { + setSummary(R.string.sim_slot_empty); + setFragment(null); + setEnabled(false); + } + } + + public void createEditDialog(SimPreference simPref) { + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + + final View dialogLayout = getActivity().getLayoutInflater().inflate( + R.layout.multi_sim_dialog, null); + builder.setView(dialogLayout); + + EditText nameText = (EditText)dialogLayout.findViewById(R.id.sim_name); + nameText.setText(mSubInfoRecord.mDisplayName); + + TextView numberView = (TextView)dialogLayout.findViewById(R.id.number); + numberView.setText(mSubInfoRecord.mNumber); + + TextView carrierView = (TextView)dialogLayout.findViewById(R.id.carrier); + carrierView.setText(mSubInfoRecord.mDisplayName); + + builder.setTitle(R.string.sim_editor_title); + + builder.setPositiveButton(R.string.okay, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int whichButton) { + final EditText nameText = (EditText)dialogLayout.findViewById(R.id.sim_name); + final Spinner displayNumbers = + (Spinner)dialogLayout.findViewById(R.id.display_numbers); + + SubscriptionManager.setDisplayNumberFormat(getActivity(), + displayNumbers.getSelectedItemPosition() == 0 + ? SubscriptionManager.DISPLAY_NUMBER_LAST + : SubscriptionManager.DISPLAY_NUMBER_FIRST, mSubInfoRecord.mSubId); + + mSubInfoRecord.mDisplayName = nameText.getText().toString(); + SubscriptionManager.setDisplayName(getActivity(), mSubInfoRecord.mDisplayName, + mSubInfoRecord.mSubId); + + updateAllOptions(); + } + }); + + builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int whichButton) { + dialog.dismiss(); + } + }); + + builder.create().show(); + } + } +}