summaryrefslogtreecommitdiffstats
path: root/src/com/android/settings/sim/SimSettings.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/settings/sim/SimSettings.java')
-rw-r--r--src/com/android/settings/sim/SimSettings.java791
1 files changed, 753 insertions, 38 deletions
diff --git a/src/com/android/settings/sim/SimSettings.java b/src/com/android/settings/sim/SimSettings.java
index 23e6275..20a401e 100644
--- a/src/com/android/settings/sim/SimSettings.java
+++ b/src/com/android/settings/sim/SimSettings.java
@@ -16,29 +16,53 @@
package com.android.settings.sim;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.ProgressDialog;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.res.Resources;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemProperties;
import android.preference.Preference;
import android.preference.PreferenceScreen;
+import android.preference.PreferenceCategory;
import android.provider.SearchIndexableResource;
+import android.provider.Settings;
import android.telephony.PhoneStateListener;
+import android.telephony.SmsManager;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
import android.text.TextUtils;
+import android.util.AttributeSet;
import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.CompoundButton;
+import android.widget.CompoundButton.OnCheckedChangeListener;
+
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.telephony.PhoneConstants;
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.settings.R;
-import android.os.SystemProperties;
+import com.android.internal.telephony.IExtTelephony;
import com.android.internal.telephony.TelephonyProperties;
import java.util.ArrayList;
@@ -48,12 +72,25 @@ public class SimSettings extends RestrictedSettingsFragment implements Indexable
private static final String TAG = "SimSettings";
private static final boolean DBG = false;
+ // These are the list of possible values that
+ // IExtTelephony.getCurrentUiccCardProvisioningStatus() can return
+ private static final int PROVISIONED = 1;
+ private static final int NOT_PROVISIONED = 0;
+ private static final int INVALID_STATE = -1;
+ private static final int CARD_NOT_PRESENT = -2;
+
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";
+ private static final String SIM_ACTIVITIES_CATEGORY = "sim_activities";
+ private static final String MOBILE_NETWORK_CATEGORY = "mobile_network";
+ private static final String KEY_PRIMARY_SUB_SELECT = "select_primary_sub";
+
+ private IExtTelephony mExtTelephony = IExtTelephony.Stub.
+ asInterface(ServiceManager.getService("extphone"));
/**
* By UX design we use only one Subscription Information(SubInfo) record per SIM slot.
@@ -64,11 +101,31 @@ public class SimSettings extends RestrictedSettingsFragment implements Indexable
private List<SubscriptionInfo> mAvailableSubInfos = null;
private List<SubscriptionInfo> mSubInfoList = null;
private List<SubscriptionInfo> mSelectableSubInfos = null;
- private PreferenceScreen mSimCards = null;
+ private PreferenceCategory mSimCards = null;
+ private PreferenceCategory mMobileNetwork;
private SubscriptionManager mSubscriptionManager;
private int mNumSlots;
private Context mContext;
+ private static AlertDialog sAlertDialog = null;
+ private static ProgressDialog sProgressDialog = null;
+ private boolean needUpdate = false;
+ private int mPhoneCount = TelephonyManager.getDefault().getPhoneCount();
+ private int[] mUiccProvisionStatus = new int[mPhoneCount];
+ private Preference mPrimarySubSelect = null;
+ private int[] mCallState = new int[mPhoneCount];
+ private PhoneStateListener[] mPhoneStateListener = new PhoneStateListener[mPhoneCount];
+
+ private static final String ACTION_UICC_MANUAL_PROVISION_STATUS_CHANGED =
+ "org.codeaurora.intent.action.ACTION_UICC_MANUAL_PROVISION_STATUS_CHANGED";
+ private static final String EXTRA_NEW_PROVISION_STATE = "newProvisionState";
+ private static final String CONFIG_LTE_SUB_SELECT_MODE = "config_lte_sub_select_mode";
+ private static final String CONFIG_PRIMARY_SUB_SETABLE = "config_primary_sub_setable";
+ private static final String CONFIG_CURRENT_PRIMARY_SUB = "config_current_primary_sub";
+ // If this config set to '1' DDS option would be greyed out on UI.
+ // For more info pls refere framework code.
+ private static final String CONFIG_DISABLE_DDS_PREFERENCE = "config_disable_dds_preference";
+
public SimSettings() {
super(DISALLOW_CONFIG_SIM);
}
@@ -88,11 +145,23 @@ public class SimSettings extends RestrictedSettingsFragment implements Indexable
(TelephonyManager) getActivity().getSystemService(Context.TELEPHONY_SERVICE);
addPreferencesFromResource(R.xml.sim_settings);
+ mPrimarySubSelect = (Preference) findPreference(KEY_PRIMARY_SUB_SELECT);
mNumSlots = tm.getSimCount();
- mSimCards = (PreferenceScreen)findPreference(SIM_CARD_CATEGORY);
+ mSimCards = (PreferenceCategory)findPreference(SIM_CARD_CATEGORY);
+ mMobileNetwork = (PreferenceCategory) findPreference(MOBILE_NETWORK_CATEGORY);
mAvailableSubInfos = new ArrayList<SubscriptionInfo>(mNumSlots);
mSelectableSubInfos = new ArrayList<SubscriptionInfo>();
SimSelectNotification.cancelNotification(getActivity());
+
+ IntentFilter intentFilter = new IntentFilter(ACTION_UICC_MANUAL_PROVISION_STATUS_CHANGED);
+ mContext.registerReceiver(mReceiver, intentFilter);
+ }
+
+ @Override
+ public void onDestroy() {
+ mContext.unregisterReceiver(mReceiver);
+ Log.d(TAG,"on onDestroy");
+ super.onDestroy();
}
private final SubscriptionManager.OnSubscriptionsChangedListener mOnSubscriptionsChangeListener
@@ -100,7 +169,10 @@ public class SimSettings extends RestrictedSettingsFragment implements Indexable
@Override
public void onSubscriptionsChanged() {
if (DBG) log("onSubscriptionsChanged:");
- updateSubscriptions();
+ Activity activity = getActivity();
+ if (activity != null && !activity.isFinishing()) {
+ updateSubscriptions();
+ }
}
};
@@ -112,19 +184,34 @@ public class SimSettings extends RestrictedSettingsFragment implements Indexable
mSimCards.removePreference(pref);
}
}
+ mMobileNetwork.removeAll();
mAvailableSubInfos.clear();
mSelectableSubInfos.clear();
for (int i = 0; i < mNumSlots; ++i) {
final SubscriptionInfo sir = mSubscriptionManager
.getActiveSubscriptionInfoForSimSlotIndex(i);
- SimPreference simPreference = new SimPreference(mContext, sir, i);
+ int subscriptionId = sir != null ?
+ sir.getSubscriptionId() :
+ SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ SimPreference simPreference = new SimEnablerPreference(mContext, sir, i);
simPreference.setOrder(i-mNumSlots);
mSimCards.addPreference(simPreference);
mAvailableSubInfos.add(sir);
- if (sir != null) {
+ if (sir != null && (isSubProvisioned(i))) {
mSelectableSubInfos.add(sir);
}
+ Intent mobileNetworkIntent = new Intent();
+ mobileNetworkIntent.setComponent(new ComponentName(
+ "com.android.phone", "com.android.phone.MobileNetworkSettings"));
+ SubscriptionManager.putPhoneIdAndSubIdExtra(mobileNetworkIntent, i, subscriptionId);
+ Preference mobileNetworkPref = new Preference(getActivity());
+ mobileNetworkPref.setTitle(
+ getString(R.string.sim_mobile_network_settings_title, (i + 1)));
+ mobileNetworkPref.setIntent(mobileNetworkIntent);
+ mobileNetworkPref.setEnabled(
+ subscriptionId != SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+ mMobileNetwork.addPreference(mobileNetworkPref);
}
updateAllOptions();
}
@@ -152,16 +239,29 @@ public class SimSettings extends RestrictedSettingsFragment implements Indexable
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) {
+ boolean isSMSPrompt = false;
+ SubscriptionInfo sir = mSubscriptionManager.getActiveSubscriptionInfo(
+ mSubscriptionManager.getDefaultSmsSubId());
+ try {
+ isSMSPrompt = mExtTelephony.isSMSPromptEnabled();
+ } catch (RemoteException ex) {
+ loge("RemoteException @isSMSPromptEnabled" + ex);
+ } catch (NullPointerException ex) {
+ loge("NullPointerException @isSMSPromptEnabled" + ex);
+ }
+ // External telephony interfaces may not exist, fall back to our impl
+ if (mExtTelephony == null) {
+ isSMSPrompt = SmsManager.getDefault().isSMSPromptEnabled();
+ }
+ log("[updateSmsValues] isSMSPrompt: " + isSMSPrompt);
+ if (isSMSPrompt || sir == null) {
+ simPref.setSummary(mContext.getResources().getString(
+ R.string.sim_calls_ask_first_prefs_title));
+ } else {
simPref.setSummary(sir.getDisplayName());
- } else if (sir == null) {
- simPref.setSummary(R.string.sim_selection_required_pref);
}
- simPref.setEnabled(mSelectableSubInfos.size() >= 1);
+ simPref.setEnabled(mSelectableSubInfos.size() > 1);
}
private void updateCellularDataValues() {
@@ -175,7 +275,13 @@ public class SimSettings extends RestrictedSettingsFragment implements Indexable
} else if (sir == null) {
simPref.setSummary(R.string.sim_selection_required_pref);
}
- simPref.setEnabled(mSelectableSubInfos.size() >= 1);
+
+ boolean callStateIdle = isCallStateIdle();
+ final boolean ecbMode = SystemProperties.getBoolean(
+ TelephonyProperties.PROPERTY_INECM_MODE, false);
+ // Enable data preference in msim mode and call state idle
+ simPref.setEnabled((mSelectableSubInfos.size() > 1) && !disableDds()
+ && callStateIdle && !ecbMode);
}
private void updateCallValues() {
@@ -197,36 +303,25 @@ public class SimSettings extends RestrictedSettingsFragment implements Indexable
public void onResume() {
super.onResume();
mSubscriptionManager.addOnSubscriptionsChangedListener(mOnSubscriptionsChangeListener);
- final TelephonyManager tm =
- (TelephonyManager) getActivity().getSystemService(Context.TELEPHONY_SERVICE);
- tm.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
+ initLTEPreference();
updateSubscriptions();
+ listen();
}
@Override
public void onPause() {
super.onPause();
mSubscriptionManager.removeOnSubscriptionsChangedListener(mOnSubscriptionsChangeListener);
- final TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
- tm.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
- }
+ unRegisterPhoneStateListener();
- private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
- // 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
- @Override
- public void onCallStateChanged(int state, String incomingNumber) {
- if (DBG) log("PhoneStateListener.onCallStateChanged: state=" + state);
- final Preference pref = findPreference(KEY_CELLULAR_DATA);
- if (pref != null) {
- final boolean ecbMode = SystemProperties.getBoolean(
- TelephonyProperties.PROPERTY_INECM_MODE, false);
- pref.setEnabled((state == TelephonyManager.CALL_STATE_IDLE) && !ecbMode);
+ for (int i = 0; i < mSimCards.getPreferenceCount(); ++i) {
+ Preference pref = mSimCards.getPreference(i);
+ if (pref instanceof SimEnablerPreference) {
+ // Calling cleanUp() here to dismiss/cleanup any pending dialog exists.
+ ((SimEnablerPreference)pref).cleanUpPendingDialogs();
}
}
- };
+ }
@Override
public boolean onPreferenceTreeClick(final PreferenceScreen preferenceScreen,
@@ -239,25 +334,39 @@ public class SimSettings extends RestrictedSettingsFragment implements Indexable
Intent newIntent = new Intent(context, SimPreferenceDialog.class);
newIntent.putExtra(EXTRA_SLOT_ID, ((SimPreference)preference).getSlotId());
startActivity(newIntent);
+ return true;
} else if (findPreference(KEY_CELLULAR_DATA) == preference) {
intent.putExtra(SimDialogActivity.DIALOG_TYPE_KEY, SimDialogActivity.DATA_PICK);
context.startActivity(intent);
+ return true;
} else if (findPreference(KEY_CALLS) == preference) {
intent.putExtra(SimDialogActivity.DIALOG_TYPE_KEY, SimDialogActivity.CALLS_PICK);
context.startActivity(intent);
+ return true;
} else if (findPreference(KEY_SMS) == preference) {
intent.putExtra(SimDialogActivity.DIALOG_TYPE_KEY, SimDialogActivity.SMS_PICK);
context.startActivity(intent);
+ return true;
}
- return true;
+ return false;
+ }
+ private void loge(String msg) {
+ if (DBG) Log.e(TAG + "message", msg);
+ }
+
+ private void simEnablerUpdate() {
+ if (isAdded()) {
+ updateAllOptions();
+ } else {
+ needUpdate = true;
+ }
}
private class SimPreference extends Preference {
- private SubscriptionInfo mSubInfoRecord;
- private int mSlotId;
+ SubscriptionInfo mSubInfoRecord;
+ int mSlotId;
Context mContext;
-
public SimPreference(Context context, SubscriptionInfo subInfoRecord, int slotId) {
super(context);
@@ -267,6 +376,9 @@ public class SimSettings extends RestrictedSettingsFragment implements Indexable
setKey("sim" + mSlotId);
update();
}
+ public SimPreference (Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
public void update() {
final Resources res = mContext.getResources();
@@ -292,6 +404,488 @@ public class SimSettings extends RestrictedSettingsFragment implements Indexable
private int getSlotId() {
return mSlotId;
}
+
+ @Override
+ protected void onAttachedToActivity() {
+ super.onAttachedToActivity();
+ if (needUpdate) {
+ needUpdate = false;
+ updateAllOptions();
+ }
+ }
+ }
+
+ // This is to show SIM Enable options on/off on UI for user selection.
+ // User can activate/de-activate through SIM on/off options.
+ private class SimEnablerPreference extends SimPreference implements OnCheckedChangeListener {
+
+ private String TAG = "SimEnablerPreference";
+ private static final boolean DBG = true;
+
+ private static final int EVT_UPDATE = 1;
+ private static final int EVT_SHOW_RESULT_DLG = 2;
+ private static final int EVT_SHOW_PROGRESS_DLG = 3;
+ private static final int EVT_PROGRESS_DLG_TIME_OUT = 4;
+
+ private static final int CONFIRM_ALERT_DLG_ID = 1;
+ private static final int ERROR_ALERT_DLG_ID = 2;
+ private static final int RESULT_ALERT_DLG_ID = 3;
+
+ private static final int REQUEST_SUCCESS = 0;
+ private static final int GENERIC_FAILURE = -1;
+ private static final int INVALID_INPUT = -2;
+ private static final int REQUEST_IN_PROGRESS = -3;
+
+
+
+ private static final String DISPLAY_NUMBERS_TYPE = "display_numbers_type";
+
+ private SubscriptionInfo mSir;
+ private boolean mCurrentUiccProvisionState;
+ private boolean mIsChecked;
+
+ private boolean mCmdInProgress = false;
+ private int mSwitchVisibility = View.VISIBLE;
+ private CompoundButton mSwitch;
+ //Delay for progress dialog to dismiss
+ private static final int PROGRESS_DLG_TIME_OUT = 30000;
+ private static final int MSG_DELAY_TIME = 2000;
+
+ private IExtTelephony mExtTelephony;
+
+
+ public SimEnablerPreference(Context context, SubscriptionInfo sir, int slotId) {
+ super(context, (AttributeSet)null,
+ com.android.internal.R.attr.checkBoxPreferenceStyle);
+ logd("Contructor..Enter");
+ mContext = context;
+ mSlotId = slotId;
+ mSir = sir;
+ mSubInfoRecord = sir;
+ if (mContext.getResources().getBoolean(R.bool.config_custom_multi_sim_checkbox)) {
+ setWidgetLayoutResource(R.layout.custom_sim_checkbox);
+ } else {
+ setWidgetLayoutResource(R.layout.custom_sim_switch);
+ }
+
+ mExtTelephony = IExtTelephony.Stub.asInterface(ServiceManager.getService("extphone"));
+
+ setSwitchVisibility(View.VISIBLE);
+ setKey("sim" + mSlotId);
+ update();
+ }
+
+ private void sendMessage(int event, Handler handler, int delay) {
+ Message message = handler.obtainMessage(event);
+ handler.sendMessageDelayed(message, delay);
+ }
+
+ private void sendMessage(int event, Handler handler, int delay, int arg1, int arg2) {
+ Message message = handler.obtainMessage(event, arg1, arg2);
+ handler.sendMessageDelayed(message, delay);
+ }
+
+ private boolean hasCard() {
+ return TelephonyManager.getDefault().hasIccCard(mSlotId);
+ }
+
+ private boolean isAirplaneModeOn() {
+ return (Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.AIRPLANE_MODE_ON, 0) != 0);
+ }
+
+ private int getProvisionStatus(int slotId) {
+ return mUiccProvisionStatus[slotId];
+ }
+
+ @Override
+ protected void onBindView(View view) {
+ super.onBindView(view);
+ logd("onBindView....");
+ mSwitch = (CompoundButton) view.findViewById(R.id.sub_switch_widget);
+ mSwitch.setOnCheckedChangeListener(this);
+ update();
+ // now use other config screen to active/deactive sim card\
+ mSwitch.setVisibility(mSwitchVisibility);
+
+ // Disable manual provisioning option to user when
+ // device is in Airplane mode. Hide it if the extphone framework
+ // is not present, as the operation relies on said framework.
+ if (mExtTelephony == null) {
+ mSwitch.setVisibility(View.GONE);
+ } else {
+ mSwitch.setVisibility(View.VISIBLE);
+ mSwitch.setEnabled(!isAirplaneModeOn());
+ }
+ }
+
+ @Override
+ public void update() {
+ final Resources res = mContext.getResources();
+ logd("update()" + mSir);
+ try {
+ //get current provision state of the SIM.
+ mUiccProvisionStatus[mSlotId] =
+ mExtTelephony.getCurrentUiccCardProvisioningStatus(mSlotId);
+ } catch (RemoteException ex) {
+ mUiccProvisionStatus[mSlotId] = INVALID_STATE;
+ loge("Failed to get pref, slotId: "+ mSlotId +" Exception: " + ex);
+ } catch (NullPointerException ex) {
+ mUiccProvisionStatus[mSlotId] = INVALID_STATE;
+ loge("Failed to get pref, slotId: "+ mSlotId +" Exception: " + ex);
+ }
+
+ if (mUiccProvisionStatus[mSlotId] == INVALID_STATE) {
+ mUiccProvisionStatus[mSlotId] = PROVISIONED;
+ }
+
+ boolean isSubValid = isCurrentSubValid();
+ setEnabled(isSubValid);
+
+ logd("update: isSubValid " + isSubValid + " provision status["
+ + mSlotId + "] = " + mUiccProvisionStatus[mSlotId]);
+ setTitle(res.getString(R.string.sim_card_number_title, mSlotId + 1));
+ if (isSubValid) {
+ updateSummary();
+ setIcon(new BitmapDrawable(res, (mSir.createIconBitmap(mContext))));
+ } else {
+ setSummary(res.getString(R.string.sim_slot_empty));
+ }
+ }
+
+ // This method returns true if SubScription record corresponds to this
+ // Preference screen has a valid SIM and slot index/SubId.
+ private boolean isCurrentSubValid() {
+ boolean isSubValid = false;
+ if (hasCard()) {
+ List<SubscriptionInfo> sirList =
+ mSubscriptionManager.getActiveSubscriptionInfoList();
+ if (sirList != null ) {
+ for (SubscriptionInfo sir : sirList) {
+ if (sir != null && mSlotId == sir.getSimSlotIndex()) {
+ mSir = sir;
+ break;
+ }
+ }
+ if (mSir != null &&
+ SubscriptionManager.isValidSubscriptionId(mSir.getSubscriptionId()) &&
+ mSir.getSimSlotIndex() >= 0 &&
+ getProvisionStatus(mSir.getSimSlotIndex()) >= 0) {
+ isSubValid = true;
+ }
+ }
+ }
+ return isSubValid;
+ }
+
+ public void setSwitchVisibility (int visibility) {
+ mSwitchVisibility = visibility;
+ }
+
+ // Based on the received SIM provision state this method
+ // sets the check box on Sim Preference UI and updates new
+ // state to mCurrentUiccProvisionState.
+ private void setChecked(boolean uiccProvisionState) {
+ logd("setChecked: uiccProvisionState " + uiccProvisionState + "sir:" + mSir);
+ if (mSwitch != null) {
+ mSwitch.setOnCheckedChangeListener(null);
+ // Do not update update checkstatus again in progress
+ if (!mCmdInProgress) {
+ mSwitch.setChecked(uiccProvisionState);
+ }
+ mSwitch.setOnCheckedChangeListener(this);
+ mCurrentUiccProvisionState = uiccProvisionState;
+ }
+ }
+
+ private void updateSummary() {
+ Resources res = mContext.getResources();
+ String summary;
+ boolean isActivated = (getProvisionStatus(mSir.getSimSlotIndex()) == PROVISIONED);
+ logd("updateSummary: subId " + mSir.getSubscriptionId() + " isActivated = "
+ + isActivated + " slot id = " + mSlotId);
+
+ String displayName = mSir == null ? "SIM" : (String)mSir.getDisplayName();
+ if (isActivated) {
+ summary = displayName;
+ if (!TextUtils.isEmpty(mSir.getNumber())) {
+ summary = displayName + " - " + mSir.getNumber();
+ }
+ } else {
+ summary = mContext.getString(R.string.sim_enabler_summary, displayName,
+ res.getString(hasCard() ? R.string.sim_disabled : R.string.sim_missing));
+ }
+
+ setSummary(summary);
+ setChecked(isActivated);
+ }
+
+
+ /**
+ * get number of Subs provisioned on the device
+ * @param context
+ * @return
+ */
+ public int getNumOfSubsProvisioned() {
+ int activeSubInfoCount = 0;
+ List<SubscriptionInfo> subInfoLists =
+ mSubscriptionManager.getActiveSubscriptionInfoList();
+ if (subInfoLists != null) {
+ for (SubscriptionInfo subInfo : subInfoLists) {
+ if (getProvisionStatus(subInfo.getSimSlotIndex())
+ == PROVISIONED) activeSubInfoCount++;
+ }
+ }
+ return activeSubInfoCount;
+ }
+
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ mIsChecked = isChecked;
+ logd("onClick: " + isChecked);
+
+ handleUserRequest();
+ }
+
+ // This internal method called when user changes preference from UI
+ // 1. For activation/deactivation request from User, if device in APM mode
+ // OR if voice call active on any SIM it dispay error dialog and returns.
+ // 2. For deactivation request it returns error dialog if only one SUB in
+ // active state.
+ // 3. In other cases it sends user request to framework.
+ synchronized private void handleUserRequest() {
+ if (isAirplaneModeOn()) {
+ // do nothing but warning
+ logd("APM is on, EXIT!");
+ showAlertDialog(ERROR_ALERT_DLG_ID, R.string.sim_enabler_airplane_on);
+ return;
+ }
+ for (int i = 0; i < mPhoneCount; i++) {
+ int[] subId = SubscriptionManager.getSubId(i);
+ //when voice call in progress, subscription can't be activate/deactivate.
+ if (TelephonyManager.getDefault().getCallState(subId[0])
+ != TelephonyManager.CALL_STATE_IDLE) {
+ logd("Call state for phoneId: " + i + " is not idle, EXIT!");
+ showAlertDialog(ERROR_ALERT_DLG_ID, R.string.sim_enabler_in_call);
+ return;
+ }
+ }
+
+ if (!mIsChecked) {
+ if (getNumOfSubsProvisioned() > 1) {
+ logd("More than one sub is active, Deactivation possible.");
+ showAlertDialog(CONFIRM_ALERT_DLG_ID, 0);
+ } else {
+ logd("Only one sub is active. Deactivation not possible.");
+ showAlertDialog(ERROR_ALERT_DLG_ID, R.string.sim_enabler_both_inactive);
+ return;
+ }
+ } else {
+ logd("Activate the sub");
+ sendUiccProvisioningRequest();
+ }
+ }
+
+ private void sendUiccProvisioningRequest() {
+ if (!mSwitch.isEnabled()) {
+ return;
+ }
+ int result = -1;
+ int newProvisionedState = NOT_PROVISIONED;
+ mCmdInProgress = true;
+
+ showProgressDialog();
+ setEnabled(false);
+ try {
+ if (mIsChecked) {
+ result = mExtTelephony.activateUiccCard(mSir.getSimSlotIndex());
+ newProvisionedState = PROVISIONED;
+ } else {
+ result = mExtTelephony.deactivateUiccCard(mSir.getSimSlotIndex());
+ }
+ } catch (RemoteException ex) {
+ loge("Activate sub failed " + result + " phoneId " + mSir.getSimSlotIndex());
+ } catch (NullPointerException ex) {
+ loge("Failed to activate sub Exception: " + ex);
+ }
+
+ processSetUiccDone(result, newProvisionedState);
+ }
+
+ private void processSetUiccDone(int result, int newProvisionedState) {
+ sendMessage(EVT_UPDATE, mHandler, MSG_DELAY_TIME);
+ sendMessage(EVT_SHOW_RESULT_DLG, mHandler, MSG_DELAY_TIME, result, newProvisionedState);
+ mCmdInProgress = false;
+ }
+
+ private void showAlertDialog(int dialogId, int msgId) {
+
+ String title = mSir == null ? "SUB" : mSir.getDisplayName().toString();
+ // Confirm only one AlertDialog instance to show.
+ dismissDialog(sAlertDialog);
+ dismissDialog(sProgressDialog);
+ AlertDialog.Builder builder = new AlertDialog.Builder(mContext)
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setTitle(title);
+
+ switch(dialogId) {
+ case CONFIRM_ALERT_DLG_ID:
+ String message;
+ if (mContext.getResources().getBoolean(
+ R.bool.confirm_to_switch_data_service)) {
+ if (SubscriptionManager.getDefaultDataSubId() ==
+ mSir.getSubscriptionId()) {
+ message = mContext.getString(
+ R.string.sim_enabler_need_switch_data_service,
+ getProvisionedSlotId(mContext));
+ } else {
+ message = mContext.getString(R.string.sim_enabler_need_disable_sim);
+ }
+ builder.setTitle(R.string.sim_enabler_will_disable_sim_title);
+ } else {
+ message = mContext.getString(R.string.sim_enabler_need_disable_sim);
+ }
+ builder.setMessage(message);
+ builder.setPositiveButton(android.R.string.ok, mDialogClickListener);
+ builder.setNegativeButton(android.R.string.no, mDialogClickListener);
+ builder.setOnCancelListener(mDialogCanceListener);
+ break;
+
+ case ERROR_ALERT_DLG_ID:
+ builder.setMessage(mContext.getString(msgId));
+ builder.setNeutralButton(android.R.string.ok, mDialogClickListener);
+ builder.setCancelable(false);
+ break;
+
+ case RESULT_ALERT_DLG_ID:
+ String msg = mCurrentUiccProvisionState ?
+ mContext.getString(R.string.sub_activate_success) :
+ mContext.getString(R.string.sub_deactivate_success);
+ builder.setMessage(msg);
+ builder.setNeutralButton(android.R.string.ok, null);
+ break;
+ default:
+ break;
+ }
+
+ sAlertDialog = builder.create();
+ sAlertDialog.setCanceledOnTouchOutside(false);
+ sAlertDialog.show();
+ }
+
+ private int getProvisionedSlotId(Context context) {
+ int activeSlotId = -1;
+ List<SubscriptionInfo> subInfoLists =
+ mSubscriptionManager.getActiveSubscriptionInfoList();
+ if (subInfoLists != null) {
+ for (SubscriptionInfo subInfo : subInfoLists) {
+ if (getProvisionStatus(subInfo.getSimSlotIndex()) == PROVISIONED
+ && subInfo.getSubscriptionId() != mSir.getSubscriptionId())
+ activeSlotId = subInfo.getSimSlotIndex() + 1;
+ }
+ }
+ return activeSlotId;
+ }
+
+ private void showProgressDialog() {
+ String title = mSir == null ? "SUB" : mSir.getDisplayName().toString();
+
+ String msg = mContext.getString(mIsChecked ? R.string.sim_enabler_enabling
+ : R.string.sim_enabler_disabling);
+ dismissDialog(sProgressDialog);
+ sProgressDialog = new ProgressDialog(mContext);
+ sProgressDialog.setIndeterminate(true);
+ sProgressDialog.setTitle(title);
+ sProgressDialog.setMessage(msg);
+ sProgressDialog.setCancelable(false);
+ sProgressDialog.setCanceledOnTouchOutside(false);
+ sProgressDialog.show();
+
+ sendMessage(EVT_PROGRESS_DLG_TIME_OUT, mHandler, PROGRESS_DLG_TIME_OUT);
+ }
+
+ private void dismissDialog(Dialog dialog) {
+ if((dialog != null) && (dialog.isShowing())) {
+ dialog.dismiss();
+ dialog = null;
+ }
+ }
+
+ public void cleanUpPendingDialogs() {
+ dismissDialog(sProgressDialog);
+ dismissDialog(sAlertDialog);
+ }
+
+ private DialogInterface.OnClickListener mDialogClickListener = new DialogInterface
+ .OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ if (which == DialogInterface.BUTTON_POSITIVE) {
+ sendUiccProvisioningRequest();
+ } else if (which == DialogInterface.BUTTON_NEGATIVE) {
+ update();
+ } else if (which == DialogInterface.BUTTON_NEUTRAL) {
+ update();
+ }
+ }
+ };
+
+ private DialogInterface.OnCancelListener mDialogCanceListener = new DialogInterface
+ .OnCancelListener() {
+ public void onCancel(DialogInterface dialog) {
+ update();
+ }
+ };
+
+
+ private Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+
+ switch(msg.what) {
+ case EVT_UPDATE:
+ simEnablerUpdate();
+
+ case EVT_SHOW_RESULT_DLG:
+ int result = msg.arg1;
+ int newProvisionedState = msg.arg2;
+ logd("EVT_SHOW_RESULT_DLG result: " + result +
+ " new provisioned state " + newProvisionedState);
+ update();
+ if (result != REQUEST_SUCCESS) {
+ int msgId = (newProvisionedState == PROVISIONED) ?
+ R.string.sub_activate_failed :
+ R.string.sub_deactivate_failed;
+ showAlertDialog(ERROR_ALERT_DLG_ID, msgId);
+ } else {
+ showAlertDialog(RESULT_ALERT_DLG_ID, 0);
+ }
+ mHandler.removeMessages(EVT_PROGRESS_DLG_TIME_OUT);
+ break;
+
+ case EVT_SHOW_PROGRESS_DLG:
+ logd("EVT_SHOW_PROGRESS_DLG");
+ showProgressDialog();
+ break;
+
+ case EVT_PROGRESS_DLG_TIME_OUT:
+ logd("EVT_PROGRESS_DLG_TIME_OUT");
+ dismissDialog(sProgressDialog);
+ // Must update UI when time out
+ update();
+ break;
+
+ default:
+ break;
+ }
+ }
+ };
+
+ private void logd(String msg) {
+ if (DBG) Log.d(TAG + "(" + mSlotId + ")", msg);
+ }
+
+ private void loge(String msg) {
+ Log.e(TAG + "(" + mSlotId + ")", msg);
+ }
}
// Returns the line1Number. Line1number should always be read from TelephonyManager since it can
@@ -326,4 +920,125 @@ public class SimSettings extends RestrictedSettingsFragment implements Indexable
return result;
}
};
+
+ // Internal utility, returns true if Uicc card
+ // corresponds to given slotId is provisioned.
+ private boolean isSubProvisioned(int slotId) {
+ boolean retVal = false;
+
+ if (mUiccProvisionStatus[slotId] == PROVISIONED) retVal = true;
+ return retVal;
+ }
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ Log.d(TAG, "Intent received: " + action);
+ if (ACTION_UICC_MANUAL_PROVISION_STATUS_CHANGED.equals(action)) {
+ int phoneId = intent.getIntExtra(PhoneConstants.PHONE_KEY,
+ SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+ int newProvisionedState = intent.getIntExtra(EXTRA_NEW_PROVISION_STATE,
+ NOT_PROVISIONED);
+ updateSubscriptions();
+ Log.d(TAG, "Received ACTION_UICC_MANUAL_PROVISION_STATUS_CHANGED on phoneId: "
+ + phoneId + " new sub state " + newProvisionedState);
+ }
+ }
+ };
+
+ // When primarycard feature enabled this provides menu option for user
+ // to view/select current primary slot.
+ private void initLTEPreference() {
+ boolean isPrimarySubFeatureEnable =
+ SystemProperties.getBoolean("persist.radio.primarycard", false);
+ boolean primarySetable = Settings.Global.getInt(mContext.getContentResolver(),
+ CONFIG_PRIMARY_SUB_SETABLE, 0) == 1;
+
+ log("isPrimarySubFeatureEnable :" + isPrimarySubFeatureEnable +
+ " primarySetable :" + primarySetable);
+
+ if (!isPrimarySubFeatureEnable || !primarySetable) {
+ final PreferenceCategory simActivities =
+ (PreferenceCategory) findPreference(SIM_ACTIVITIES_CATEGORY);
+ simActivities.removePreference(mPrimarySubSelect);
+ return;
+ }
+ int currentPrimarySlot = Settings.Global.getInt(mContext.getContentResolver(),
+ CONFIG_CURRENT_PRIMARY_SUB, SubscriptionManager.INVALID_SIM_SLOT_INDEX);
+ boolean isManualMode = Settings.Global.getInt(mContext.getContentResolver(),
+ CONFIG_LTE_SUB_SELECT_MODE, 1) == 0;
+
+ log("init LTE primary slot : " + currentPrimarySlot + " isManualMode :" + isManualMode);
+
+ if (SubscriptionManager.isValidSlotId(currentPrimarySlot)) {
+ final SubscriptionInfo subInfo = mSubscriptionManager
+ .getActiveSubscriptionInfoForSimSlotIndex(currentPrimarySlot);
+ CharSequence lteSummary = (subInfo == null ) ? null : subInfo.getDisplayName();
+ mPrimarySubSelect.setSummary(lteSummary);
+ } else {
+ mPrimarySubSelect.setSummary("");
+ }
+ mPrimarySubSelect.setEnabled(isManualMode);
+ }
+
+ private boolean disableDds() {
+ boolean disableDds = Settings.Global.getInt(mContext.getContentResolver(),
+ CONFIG_DISABLE_DDS_PREFERENCE, 0) == 1;
+
+ log(" config disable dds = " + disableDds);
+ return disableDds;
+ }
+
+ private void listen() {
+ 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.listen(getPhoneStateListener(i, subId),
+ PhoneStateListener.LISTEN_CALL_STATE);
+ }
+ }
+ }
+
+ private void unRegisterPhoneStateListener() {
+ TelephonyManager tm =
+ (TelephonyManager) getActivity().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, int subId) {
+ // 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(subId) {
+ @Override
+ public void onCallStateChanged(int state, String incomingNumber) {
+ if (DBG) log("PhoneStateListener.onCallStateChanged: state=" + state);
+ mCallState[i] = state;
+ updateCellularDataValues();
+ }
+ };
+ return mPhoneStateListener[phoneId];
+ }
+
+ 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;
+ }
}