Adding the ability for carrier app to override SPN and carrier name.
The change allows system apps (holding MODIFY_PHONE_STATE permission) or
carrier apps to override the "carrier branding" on a per ICCID basis. The
override affects the service provider name as well as the network operator
name. The override is also saved as a SharedPreference and will persist for
the iccId across reboots.
Change-Id: I985ba247e10e2501e3d0d21567ccadc46f365879
diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java
index ce9d235..6a5a82d 100644
--- a/src/java/com/android/internal/telephony/Phone.java
+++ b/src/java/com/android/internal/telephony/Phone.java
@@ -1807,4 +1807,9 @@
* otherwise return the current voice service state
*/
int getVoicePhoneServiceState();
+
+ /**
+ * Override the service provider name and the operator name for the input ICCID.
+ */
+ public boolean setOperatorBrandOverride(String iccId, String brand);
}
diff --git a/src/java/com/android/internal/telephony/PhoneBase.java b/src/java/com/android/internal/telephony/PhoneBase.java
index 15b5a77..642b770 100644
--- a/src/java/com/android/internal/telephony/PhoneBase.java
+++ b/src/java/com/android/internal/telephony/PhoneBase.java
@@ -1816,4 +1816,9 @@
}
return getServiceState().getState();
}
+
+ @Override
+ public boolean setOperatorBrandOverride(String iccId, String brand) {
+ return false;
+ }
}
diff --git a/src/java/com/android/internal/telephony/PhoneProxy.java b/src/java/com/android/internal/telephony/PhoneProxy.java
index 05b28b1..e043bf9 100644
--- a/src/java/com/android/internal/telephony/PhoneProxy.java
+++ b/src/java/com/android/internal/telephony/PhoneProxy.java
@@ -1359,4 +1359,9 @@
public int getVoicePhoneServiceState() {
return mActivePhone.getVoicePhoneServiceState();
}
+
+ @Override
+ public boolean setOperatorBrandOverride(String iccId, String brand) {
+ return mActivePhone.setOperatorBrandOverride(iccId, brand);
+ }
}
diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java
index 8462427..7164869 100644
--- a/src/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -467,6 +467,7 @@
public abstract boolean isConcurrentVoiceAndDataAllowed();
public abstract void setImsRegistrationState(boolean registered);
+ public abstract void pollState();
/**
* Registration point for transition into DataConnection attached.
diff --git a/src/java/com/android/internal/telephony/cdma/CDMALTEPhone.java b/src/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
index dd07281..374f814 100644
--- a/src/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
+++ b/src/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
@@ -354,17 +354,21 @@
new Integer(PhoneConstants.PHONE_TYPE_CDMA).toString());
// Sets operator alpha property by retrieving from build-time system property
String operatorAlpha = SystemProperties.get("ro.cdma.home.operator.alpha");
- setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, operatorAlpha);
+ if (!TextUtils.isEmpty(operatorAlpha)) {
+ setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, operatorAlpha);
+ }
// Sets operator numeric property by retrieving from build-time system property
String operatorNumeric = SystemProperties.get(PROPERTY_CDMA_HOME_OPERATOR_NUMERIC);
log("update icc_operator_numeric=" + operatorNumeric);
- setSystemProperty(PROPERTY_ICC_OPERATOR_NUMERIC, operatorNumeric);
- // Sets iso country property by retrieving from build-time system property
- setIsoCountryProperty(operatorNumeric);
- // Updates MCC MNC device configuration information
- log("update mccmnc=" + operatorNumeric);
- MccTable.updateMccMncConfiguration(mContext, operatorNumeric, false);
+ if (!TextUtils.isEmpty(operatorNumeric)) {
+ setSystemProperty(PROPERTY_ICC_OPERATOR_NUMERIC, operatorNumeric);
+ // Sets iso country property by retrieving from build-time system property
+ setIsoCountryProperty(operatorNumeric);
+ // Updates MCC MNC device configuration information
+ log("update mccmnc=" + operatorNumeric);
+ MccTable.updateMccMncConfiguration(mContext, operatorNumeric, false);
+ }
// Sets current entry in the telephony carrier table
updateCurrentCarrierInProvider();
}
diff --git a/src/java/com/android/internal/telephony/cdma/CDMAPhone.java b/src/java/com/android/internal/telephony/cdma/CDMAPhone.java
index 7991810..d4fb7e3 100644
--- a/src/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/src/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -1719,4 +1719,31 @@
pw.println(" isMinInfoReady()=" + isMinInfoReady());
pw.println(" isCspPlmnEnabled()=" + isCspPlmnEnabled());
}
+
+ @Override
+ public boolean setOperatorBrandOverride(String iccId, String brand) {
+ if (mUiccController == null) {
+ return false;
+ }
+
+ UiccCard card = mUiccController.getUiccCard();
+ if (card == null) {
+ return false;
+ }
+
+ boolean status = card.setOperatorBrandOverride(iccId, brand);
+
+ // Refresh.
+ if (status) {
+ IccRecords iccRecords = mIccRecords.get();
+ if (iccRecords != null) {
+ SystemProperties.set(TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA,
+ iccRecords.getServiceProviderName());
+ }
+ if (mSST != null) {
+ mSST.pollState();
+ }
+ }
+ return status;
+ }
}
diff --git a/src/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java b/src/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
index 0015cd7..7c698dc 100644
--- a/src/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
+++ b/src/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
@@ -236,7 +236,7 @@
}
@Override
- protected void pollState() {
+ public void pollState() {
mPollingContext = new int[1];
mPollingContext[0] = 0;
diff --git a/src/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/src/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
index ca38aab..cbe575f 100644
--- a/src/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/src/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -713,7 +713,7 @@
} else {
mRegistrationDeniedReason = "";
}
-
+
if (mRegistrationState == 3) {
if (DBG) log("Registration denied, " + mRegistrationDeniedReason);
}
@@ -721,8 +721,9 @@
case EVENT_POLL_STATE_OPERATOR_CDMA: // Handle RIL_REQUEST_OPERATOR
String opNames[] = (String[])ar.result;
-
+
if (opNames != null && opNames.length >= 3) {
+ // TODO: Do we care about overriding in this case.
// If the NUMERIC field isn't valid use PROPERTY_CDMA_HOME_OPERATOR_NUMERIC
if ((opNames[2] == null) || (opNames[2].length() < 5)
|| ("00000".equals(opNames[2]))) {
@@ -741,17 +742,20 @@
// ERI text, so here it is ignored what is coming from the modem.
mNewSS.setOperatorName(null, opNames[1], opNames[2]);
} else {
- mNewSS.setOperatorName(opNames[0], opNames[1], opNames[2]);
+ String brandOverride = mUiccController.getUiccCard() != null ?
+ mUiccController.getUiccCard().getOperatorBrandOverride() : null;
+ if (brandOverride != null) {
+ mNewSS.setOperatorName(brandOverride, brandOverride, opNames[2]);
+ } else {
+ mNewSS.setOperatorName(opNames[0], opNames[1], opNames[2]);
+ }
}
} else {
if (DBG) log("EVENT_POLL_STATE_OPERATOR_CDMA: error parsing opNames");
}
break;
-
default:
-
-
loge("handlePollStateResultMessage: RIL response handle in wrong phone!"
+ " Expected CDMA RIL request and get GSM RIL request.");
break;
@@ -882,8 +886,8 @@
* and start over again if the radio notifies us that some
* event has changed
*/
- protected void
- pollState() {
+ @Override
+ public void pollState() {
mPollingContext = new int[1];
mPollingContext[0] = 0;
diff --git a/src/java/com/android/internal/telephony/gsm/GSMPhone.java b/src/java/com/android/internal/telephony/gsm/GSMPhone.java
index c30a08f..6d2a8ad 100644
--- a/src/java/com/android/internal/telephony/gsm/GSMPhone.java
+++ b/src/java/com/android/internal/telephony/gsm/GSMPhone.java
@@ -78,6 +78,7 @@
import com.android.internal.telephony.test.SimulatedRadioControl;
import com.android.internal.telephony.uicc.IccRecords;
import com.android.internal.telephony.uicc.IccVmNotSupportedException;
+import com.android.internal.telephony.uicc.UiccCard;
import com.android.internal.telephony.uicc.UiccCardApplication;
import com.android.internal.telephony.uicc.UiccController;
import com.android.internal.telephony.ServiceStateTracker;
@@ -1718,6 +1719,33 @@
pw.println(" mVmNumber=" + mVmNumber);
}
+ @Override
+ public boolean setOperatorBrandOverride(String iccId, String brand) {
+ if (mUiccController == null) {
+ return false;
+ }
+
+ UiccCard card = mUiccController.getUiccCard();
+ if (card == null) {
+ return false;
+ }
+
+ boolean status = card.setOperatorBrandOverride(iccId, brand);
+
+ // Refresh.
+ if (status) {
+ IccRecords iccRecords = mIccRecords.get();
+ if (iccRecords != null) {
+ SystemProperties.set(TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA,
+ iccRecords.getServiceProviderName());
+ }
+ if (mSST != null) {
+ mSST.pollState();
+ }
+ }
+ return status;
+ }
+
/**
* @return operator numeric.
*/
diff --git a/src/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/src/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
index f69942f..8e63562 100644
--- a/src/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
+++ b/src/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
@@ -785,7 +785,13 @@
String opNames[] = (String[])ar.result;
if (opNames != null && opNames.length >= 3) {
- mNewSS.setOperatorName (opNames[0], opNames[1], opNames[2]);
+ String brandOverride = mUiccController.getUiccCard() != null ?
+ mUiccController.getUiccCard().getOperatorBrandOverride() : null;
+ if (brandOverride != null) {
+ mNewSS.setOperatorName(brandOverride, brandOverride, opNames[2]);
+ } else {
+ mNewSS.setOperatorName(opNames[0], opNames[1], opNames[2]);
+ }
}
break;
}
@@ -841,7 +847,8 @@
* and start over again if the radio notifies us that some
* event has changed
*/
- private void pollState() {
+ @Override
+ public void pollState() {
mPollingContext = new int[1];
mPollingContext[0] = 0;
diff --git a/src/java/com/android/internal/telephony/uicc/IccRecords.java b/src/java/com/android/internal/telephony/uicc/IccRecords.java
index 2e9bea3..e54dfa4 100644
--- a/src/java/com/android/internal/telephony/uicc/IccRecords.java
+++ b/src/java/com/android/internal/telephony/uicc/IccRecords.java
@@ -72,7 +72,7 @@
protected int mMncLength = UNINITIALIZED;
protected int mMailboxIndex = 0; // 0 is no mailbox dailing number associated
- protected String mSpn;
+ private String mSpn;
protected String mGid1;
@@ -304,11 +304,17 @@
}
/**
- * Return Service Provider Name stored in SIM (EF_SPN=0x6F46) or in RUIM (EF_RUIM_SPN=0x6F41)
+ * Return Service Provider Name stored in SIM (EF_SPN=0x6F46) or in RUIM (EF_RUIM_SPN=0x6F41).
+ *
* @return null if SIM is not yet ready or no RUIM entry
*/
public String getServiceProviderName() {
- return mSpn;
+ String brandOverride = mParentApp.getUiccCard().getOperatorBrandOverride();
+ return brandOverride == null ? mSpn : brandOverride;
+ }
+
+ protected void setServiceProviderName(String spn) {
+ mSpn = spn;
}
/**
diff --git a/src/java/com/android/internal/telephony/uicc/RuimRecords.java b/src/java/com/android/internal/telephony/uicc/RuimRecords.java
index ff2e651..7897753 100755
--- a/src/java/com/android/internal/telephony/uicc/RuimRecords.java
+++ b/src/java/com/android/internal/telephony/uicc/RuimRecords.java
@@ -296,24 +296,25 @@
}
if (numBytes == 0) {
- mSpn = "";
+ setServiceProviderName("");
return;
}
try {
switch (encoding) {
case UserData.ENCODING_OCTET:
case UserData.ENCODING_LATIN:
- mSpn = new String(spnData, 0, numBytes, "ISO-8859-1");
+ setServiceProviderName(new String(spnData, 0, numBytes, "ISO-8859-1"));
break;
case UserData.ENCODING_IA5:
case UserData.ENCODING_GSM_7BIT_ALPHABET:
- mSpn = GsmAlphabet.gsm7BitPackedToString(spnData, 0, (numBytes*8)/7);
+ setServiceProviderName(
+ GsmAlphabet.gsm7BitPackedToString(spnData, 0, (numBytes*8)/7));
break;
case UserData.ENCODING_7BIT_ASCII:
- mSpn = new String(spnData, 0, numBytes, "US-ASCII");
+ setServiceProviderName(new String(spnData, 0, numBytes, "US-ASCII"));
break;
case UserData.ENCODING_UNICODE_16:
- mSpn = new String(spnData, 0, numBytes, "utf-16");
+ setServiceProviderName(new String(spnData, 0, numBytes, "utf-16"));
break;
default:
log("SPN encoding not supported");
@@ -321,9 +322,9 @@
} catch(Exception e) {
log("spn decode error: " + e);
}
- if (DBG) log("spn=" + mSpn);
+ if (DBG) log("spn=" + getServiceProviderName());
if (DBG) log("spnCondition=" + mCsimSpnDisplayCondition);
- SystemProperties.set(PROPERTY_ICC_OPERATOR_ALPHA, mSpn);
+ SystemProperties.set(PROPERTY_ICC_OPERATOR_ALPHA, getServiceProviderName());
}
}
diff --git a/src/java/com/android/internal/telephony/uicc/SIMRecords.java b/src/java/com/android/internal/telephony/uicc/SIMRecords.java
index dbf573b..772b6c5 100644
--- a/src/java/com/android/internal/telephony/uicc/SIMRecords.java
+++ b/src/java/com/android/internal/telephony/uicc/SIMRecords.java
@@ -1375,7 +1375,7 @@
private void setSpnFromConfig(String carrier) {
if (mSpnOverride.containsCarrier(carrier)) {
- mSpn = mSpnOverride.getSpn(carrier);
+ setServiceProviderName(mSpnOverride.getSpn(carrier));
}
}
@@ -1491,7 +1491,7 @@
@Override
public int getDisplayRule(String plmn) {
int rule;
- if (TextUtils.isEmpty(mSpn) || mSpnDisplayCondition == -1) {
+ if (TextUtils.isEmpty(getServiceProviderName()) || mSpnDisplayCondition == -1) {
// No EF_SPN content was found on the SIM, or not yet loaded. Just show ONS.
rule = SPN_RULE_SHOW_PLMN;
} else if (isOnMatchingPlmn(plmn)) {
@@ -1579,7 +1579,7 @@
switch(mSpnState){
case INIT:
- mSpn = null;
+ setServiceProviderName(null);
mFh.loadEFTransparent(EF_SPN,
obtainMessage(EVENT_GET_SPN_DONE));
@@ -1591,11 +1591,12 @@
if (ar != null && ar.exception == null) {
data = (byte[]) ar.result;
mSpnDisplayCondition = 0xff & data[0];
- mSpn = IccUtils.adnStringFieldToString(data, 1, data.length - 1);
+ setServiceProviderName(IccUtils.adnStringFieldToString(
+ data, 1, data.length - 1));
- if (DBG) log("Load EF_SPN: " + mSpn
+ if (DBG) log("Load EF_SPN: " + getServiceProviderName()
+ " spnDisplayCondition: " + mSpnDisplayCondition);
- setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, mSpn);
+ setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, getServiceProviderName());
mSpnState = GetSpnFsmState.IDLE;
} else {
@@ -1613,10 +1614,10 @@
case READ_SPN_CPHS:
if (ar != null && ar.exception == null) {
data = (byte[]) ar.result;
- mSpn = IccUtils.adnStringFieldToString(data, 0, data.length);
+ setServiceProviderName(IccUtils.adnStringFieldToString(data, 0, data.length));
- if (DBG) log("Load EF_SPN_CPHS: " + mSpn);
- setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, mSpn);
+ if (DBG) log("Load EF_SPN_CPHS: " + getServiceProviderName());
+ setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, getServiceProviderName());
mSpnState = GetSpnFsmState.IDLE;
} else {
@@ -1630,10 +1631,10 @@
case READ_SPN_SHORT_CPHS:
if (ar != null && ar.exception == null) {
data = (byte[]) ar.result;
- mSpn = IccUtils.adnStringFieldToString(data, 0, data.length);
+ setServiceProviderName(IccUtils.adnStringFieldToString(data, 0, data.length));
- if (DBG) log("Load EF_SPN_SHORT_CPHS: " + mSpn);
- setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, mSpn);
+ if (DBG) log("Load EF_SPN_SHORT_CPHS: " + getServiceProviderName());
+ setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, getServiceProviderName());
}else {
if (DBG) log("No SPN loaded in either CHPS or 3GPP");
}
diff --git a/src/java/com/android/internal/telephony/uicc/UiccCard.java b/src/java/com/android/internal/telephony/uicc/UiccCard.java
index fa501ad..51521dd 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccCard.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccCard.java
@@ -22,6 +22,7 @@
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
+import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
import android.content.res.Resources;
@@ -31,8 +32,10 @@
import android.os.PowerManager;
import android.os.Registrant;
import android.os.RegistrantList;
+import android.preference.PreferenceManager;
import android.telephony.Rlog;
import android.telephony.TelephonyManager;
+import android.text.TextUtils;
import android.view.WindowManager;
import com.android.internal.telephony.CommandsInterface;
@@ -62,6 +65,8 @@
protected static final String LOG_TAG = "UiccCard";
protected static final boolean DBG = true;
+ private static final String OPERATOR_BRAND_OVERRIDE_PREFIX = "operator_branding_";
+
private final Object mLock = new Object();
private CardState mCardState;
private PinState mUniversalPinState;
@@ -503,6 +508,47 @@
packageManager, intent);
}
+ public boolean setOperatorBrandOverride(String iccId, String brand) {
+ log("setOperatorBrandOverride: " + iccId + " : " + brand);
+ log("current iccId: " + getIccId());
+
+ if (iccId.isEmpty() || !TextUtils.isDigitsOnly(iccId)) {
+ return false;
+ }
+
+ SharedPreferences.Editor spEditor =
+ PreferenceManager.getDefaultSharedPreferences(mContext).edit();
+ String key = OPERATOR_BRAND_OVERRIDE_PREFIX + iccId;
+ if (brand == null) {
+ spEditor.remove(key).commit();
+ } else {
+ spEditor.putString(key, brand).commit();
+ }
+ return true;
+ }
+
+ public String getOperatorBrandOverride() {
+ String iccId = getIccId();
+ if (iccId == null) {
+ return null;
+ }
+ SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
+ return sp.getString(OPERATOR_BRAND_OVERRIDE_PREFIX + iccId, null);
+ }
+
+ private String getIccId() {
+ // ICCID should be same across all the apps.
+ for (UiccCardApplication app : mUiccApplications) {
+ if (app != null) {
+ IccRecords ir = app.getIccRecords();
+ if (ir != null && ir.getIccId() != null) {
+ return ir.getIccId();
+ }
+ }
+ }
+ return null;
+ }
+
private void log(String msg) {
Rlog.d(LOG_TAG, msg);
}
diff --git a/src/java/com/android/internal/telephony/uicc/UiccCardApplication.java b/src/java/com/android/internal/telephony/uicc/UiccCardApplication.java
index 647ef09..94efb98 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccCardApplication.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccCardApplication.java
@@ -804,6 +804,10 @@
}
}
+ protected UiccCard getUiccCard() {
+ return mUiccCard;
+ }
+
private void log(String msg) {
Rlog.d(LOG_TAG, msg);
}