| /* |
| * 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 android.app.settings.SettingsEnums; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.res.Resources; |
| import android.graphics.drawable.BitmapDrawable; |
| import android.os.Bundle; |
| import android.os.SystemProperties; |
| import android.provider.SearchIndexableResource; |
| import android.telecom.PhoneAccountHandle; |
| import android.telecom.TelecomManager; |
| import android.telephony.PhoneNumberUtils; |
| import android.telephony.PhoneStateListener; |
| import android.telephony.SubscriptionInfo; |
| import android.telephony.SubscriptionManager; |
| import android.telephony.TelephonyManager; |
| import android.text.TextUtils; |
| import android.util.Log; |
| |
| import androidx.preference.Preference; |
| import androidx.preference.PreferenceScreen; |
| |
| import com.android.internal.telephony.TelephonyProperties; |
| import com.android.settings.R; |
| import com.android.settings.RestrictedSettingsFragment; |
| import com.android.settings.Utils; |
| import com.android.settings.search.BaseSearchIndexProvider; |
| import com.android.settings.search.Indexable; |
| import com.android.settingslib.search.SearchIndexable; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| @SearchIndexable |
| public class SimSettings extends RestrictedSettingsFragment implements Indexable { |
| private static final String TAG = "SimSettings"; |
| private static final boolean DBG = false; |
| |
| 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"; |
| public static final String EXTRA_SLOT_ID = "slot_id"; |
| |
| /** |
| * By UX design we 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. |
| * mSelectableSubInfos is the list of SubInfos that a user can select for data, calls, and SMS. |
| */ |
| private List<SubscriptionInfo> mAvailableSubInfos = null; |
| private List<SubscriptionInfo> mSubInfoList = null; |
| private List<SubscriptionInfo> mSelectableSubInfos = null; |
| private PreferenceScreen mSimCards = null; |
| private SubscriptionManager mSubscriptionManager; |
| private int mNumSlots; |
| private Context mContext; |
| |
| private int mPhoneCount = TelephonyManager.getDefault().getPhoneCount(); |
| private int[] mCallState = new int[mPhoneCount]; |
| private PhoneStateListener[] mPhoneStateListener = new PhoneStateListener[mPhoneCount]; |
| |
| public SimSettings() { |
| super(DISALLOW_CONFIG_SIM); |
| } |
| |
| @Override |
| public int getMetricsCategory() { |
| return SettingsEnums.SIM; |
| } |
| |
| @Override |
| public void onCreate(final Bundle bundle) { |
| super.onCreate(bundle); |
| mContext = getActivity(); |
| |
| mSubscriptionManager = SubscriptionManager.from(getActivity()); |
| final TelephonyManager tm = |
| (TelephonyManager) getActivity().getSystemService(Context.TELEPHONY_SERVICE); |
| addPreferencesFromResource(R.xml.sim_settings); |
| |
| mNumSlots = tm.getSimCount(); |
| mSimCards = (PreferenceScreen)findPreference(SIM_CARD_CATEGORY); |
| mAvailableSubInfos = new ArrayList<SubscriptionInfo>(mNumSlots); |
| mSelectableSubInfos = new ArrayList<SubscriptionInfo>(); |
| SimSelectNotification.cancelSimSelectNotification(getActivity()); |
| } |
| |
| private final SubscriptionManager.OnSubscriptionsChangedListener mOnSubscriptionsChangeListener |
| = new SubscriptionManager.OnSubscriptionsChangedListener() { |
| @Override |
| public void onSubscriptionsChanged() { |
| if (DBG) log("onSubscriptionsChanged:"); |
| updateSubscriptions(); |
| } |
| }; |
| |
| private void updateSubscriptions() { |
| mSubInfoList = mSubscriptionManager.getActiveSubscriptionInfoList(true); |
| for (int i = 0; i < mNumSlots; ++i) { |
| Preference pref = mSimCards.findPreference("sim" + i); |
| if (pref instanceof SimPreference) { |
| mSimCards.removePreference(pref); |
| } |
| } |
| mAvailableSubInfos.clear(); |
| mSelectableSubInfos.clear(); |
| |
| for (int i = 0; i < mNumSlots; ++i) { |
| final SubscriptionInfo sir = mSubscriptionManager |
| .getActiveSubscriptionInfoForSimSlotIndex(i); |
| SimPreference simPreference = new SimPreference(getPrefContext(), sir, i); |
| simPreference.setOrder(i-mNumSlots); |
| mSimCards.addPreference(simPreference); |
| mAvailableSubInfos.add(sir); |
| if (sir != null) { |
| mSelectableSubInfos.add(sir); |
| } |
| } |
| updateAllOptions(); |
| } |
| |
| private void updateAllOptions() { |
| updateSimSlotValues(); |
| updateActivitesCategory(); |
| } |
| |
| private void updateSimSlotValues() { |
| final int prefSize = mSimCards.getPreferenceCount(); |
| for (int i = 0; i < prefSize; ++i) { |
| Preference pref = mSimCards.getPreference(i); |
| if (pref instanceof SimPreference) { |
| ((SimPreference)pref).update(); |
| } |
| } |
| } |
| |
| private void updateActivitesCategory() { |
| updateCellularDataValues(); |
| updateCallValues(); |
| updateSmsValues(); |
| } |
| |
| private void updateSmsValues() { |
| final Preference simPref = findPreference(KEY_SMS); |
| final SubscriptionInfo sir = mSubscriptionManager.getDefaultSmsSubscriptionInfo(); |
| simPref.setTitle(R.string.sms_messages_title); |
| if (DBG) log("[updateSmsValues] mSubInfoList=" + mSubInfoList); |
| |
| if (sir != null) { |
| simPref.setSummary(sir.getDisplayName()); |
| simPref.setEnabled(mSelectableSubInfos.size() > 1); |
| } else if (sir == null) { |
| simPref.setSummary(R.string.sim_selection_required_pref); |
| simPref.setEnabled(mSelectableSubInfos.size() >= 1); |
| } |
| } |
| |
| private void updateCellularDataValues() { |
| final Preference simPref = findPreference(KEY_CELLULAR_DATA); |
| final SubscriptionInfo sir = mSubscriptionManager.getDefaultDataSubscriptionInfo(); |
| simPref.setTitle(R.string.cellular_data_title); |
| if (DBG) log("[updateCellularDataValues] mSubInfoList=" + mSubInfoList); |
| |
| boolean callStateIdle = isCallStateIdle(); |
| final boolean ecbMode = SystemProperties.getBoolean( |
| TelephonyProperties.PROPERTY_INECM_MODE, false); |
| if (sir != null) { |
| simPref.setSummary(sir.getDisplayName()); |
| // Enable data preference in msim mode and call state idle |
| simPref.setEnabled((mSelectableSubInfos.size() > 1) && callStateIdle && !ecbMode); |
| } else if (sir == null) { |
| simPref.setSummary(R.string.sim_selection_required_pref); |
| // Enable data preference in msim mode and call state idle |
| simPref.setEnabled((mSelectableSubInfos.size() >= 1) && callStateIdle && !ecbMode); |
| } |
| } |
| |
| private void updateCallValues() { |
| final Preference simPref = findPreference(KEY_CALLS); |
| final TelecomManager telecomManager = TelecomManager.from(mContext); |
| final PhoneAccountHandle phoneAccount = |
| telecomManager.getUserSelectedOutgoingPhoneAccount(); |
| final List<PhoneAccountHandle> allPhoneAccounts = |
| telecomManager.getCallCapablePhoneAccounts(); |
| |
| simPref.setTitle(R.string.calls_title); |
| simPref.setSummary(phoneAccount == null |
| ? mContext.getResources().getString(R.string.sim_calls_ask_first_prefs_title) |
| : (String)telecomManager.getPhoneAccount(phoneAccount).getLabel()); |
| simPref.setEnabled(allPhoneAccounts.size() > 1); |
| } |
| |
| @Override |
| public void onResume() { |
| super.onResume(); |
| mSubscriptionManager.addOnSubscriptionsChangedListener(mOnSubscriptionsChangeListener); |
| updateSubscriptions(); |
| final TelephonyManager tm = |
| (TelephonyManager) getActivity().getSystemService(Context.TELEPHONY_SERVICE); |
| if (mSelectableSubInfos.size() > 1) { |
| Log.d(TAG, "Register for call state change"); |
| for (int i = 0; i < mPhoneCount; i++) { |
| int subId = mSelectableSubInfos.get(i).getSubscriptionId(); |
| tm.createForSubscriptionId(subId).listen(getPhoneStateListener(i), |
| PhoneStateListener.LISTEN_CALL_STATE); |
| } |
| } |
| } |
| |
| @Override |
| public void onPause() { |
| super.onPause(); |
| mSubscriptionManager.removeOnSubscriptionsChangedListener(mOnSubscriptionsChangeListener); |
| final TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); |
| for (int i = 0; i < mPhoneCount; i++) { |
| if (mPhoneStateListener[i] != null) { |
| tm.listen(mPhoneStateListener[i], PhoneStateListener.LISTEN_NONE); |
| mPhoneStateListener[i] = null; |
| } |
| } |
| } |
| |
| private PhoneStateListener getPhoneStateListener(int phoneId) { |
| // Disable Sim selection for Data when voice call is going on as changing the default data |
| // sim causes a modem reset currently and call gets disconnected |
| // ToDo : Add subtext on disabled preference to let user know that default data sim cannot |
| // be changed while call is going on |
| final int i = phoneId; |
| mPhoneStateListener[phoneId] = new PhoneStateListener() { |
| @Override |
| public void onCallStateChanged(int state, String incomingNumber) { |
| if (DBG) log("PhoneStateListener.onCallStateChanged: state=" + state); |
| mCallState[i] = state; |
| updateCellularDataValues(); |
| } |
| }; |
| return mPhoneStateListener[phoneId]; |
| } |
| |
| @Override |
| public boolean onPreferenceTreeClick(final Preference preference) { |
| final Context context = mContext; |
| Intent intent = new Intent(context, SimDialogActivity.class); |
| intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
| |
| if (preference instanceof SimPreference) { |
| Intent newIntent = new Intent(context, SimPreferenceDialog.class); |
| newIntent.putExtra(EXTRA_SLOT_ID, ((SimPreference)preference).getSlotId()); |
| startActivity(newIntent); |
| } else if (findPreference(KEY_CELLULAR_DATA) == preference) { |
| intent.putExtra(SimDialogActivity.DIALOG_TYPE_KEY, SimDialogActivity.DATA_PICK); |
| context.startActivity(intent); |
| } else if (findPreference(KEY_CALLS) == preference) { |
| intent.putExtra(SimDialogActivity.DIALOG_TYPE_KEY, SimDialogActivity.CALLS_PICK); |
| context.startActivity(intent); |
| } else if (findPreference(KEY_SMS) == preference) { |
| intent.putExtra(SimDialogActivity.DIALOG_TYPE_KEY, SimDialogActivity.SMS_PICK); |
| context.startActivity(intent); |
| } |
| |
| return true; |
| } |
| |
| private class SimPreference extends Preference { |
| private SubscriptionInfo mSubInfoRecord; |
| private int mSlotId; |
| Context mContext; |
| |
| public SimPreference(Context context, SubscriptionInfo subInfoRecord, int slotId) { |
| super(context); |
| |
| mContext = context; |
| mSubInfoRecord = subInfoRecord; |
| mSlotId = slotId; |
| setKey("sim" + mSlotId); |
| update(); |
| } |
| |
| public void update() { |
| final Resources res = mContext.getResources(); |
| |
| setTitle(String.format(mContext.getResources() |
| .getString(R.string.sim_editor_title), (mSlotId + 1))); |
| if (mSubInfoRecord != null) { |
| if (TextUtils.isEmpty(getPhoneNumber(mSubInfoRecord))) { |
| setSummary(mSubInfoRecord.getDisplayName()); |
| } else { |
| setSummary(mSubInfoRecord.getDisplayName() + " - " + |
| PhoneNumberUtils.createTtsSpannable(getPhoneNumber(mSubInfoRecord))); |
| setEnabled(true); |
| } |
| setIcon(new BitmapDrawable(res, (mSubInfoRecord.createIconBitmap(mContext)))); |
| } else { |
| setSummary(R.string.sim_slot_empty); |
| setFragment(null); |
| setEnabled(false); |
| } |
| } |
| |
| private int getSlotId() { |
| return mSlotId; |
| } |
| } |
| |
| // Returns the line1Number. Line1number should always be read from TelephonyManager since it can |
| // be overridden for display purposes. |
| private String getPhoneNumber(SubscriptionInfo info) { |
| final TelephonyManager tm = |
| (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); |
| return tm.getLine1Number(info.getSubscriptionId()); |
| } |
| |
| private void log(String s) { |
| Log.d(TAG, s); |
| } |
| |
| /** |
| * For search |
| */ |
| public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = |
| new BaseSearchIndexProvider() { |
| @Override |
| public List<SearchIndexableResource> getXmlResourcesToIndex(Context context, |
| boolean enabled) { |
| ArrayList<SearchIndexableResource> result = |
| new ArrayList<SearchIndexableResource>(); |
| |
| if (Utils.showSimCardTile(context)) { |
| SearchIndexableResource sir = new SearchIndexableResource(context); |
| sir.xmlResId = R.xml.sim_settings; |
| result.add(sir); |
| } |
| |
| return result; |
| } |
| }; |
| |
| private boolean isCallStateIdle() { |
| boolean callStateIdle = true; |
| for (int i = 0; i < mCallState.length; i++) { |
| if (TelephonyManager.CALL_STATE_IDLE != mCallState[i]) { |
| callStateIdle = false; |
| } |
| } |
| Log.d(TAG, "isCallStateIdle " + callStateIdle); |
| return callStateIdle; |
| } |
| } |