Merge tag 'android-9.0.0_r37' of https://android.googlesource.com/platform//frameworks/opt/telephony into HEAD
Android 9.0.0 Release 37 (PQ3A.190505.002)
Change-Id: I78816ee5aa17ed42fe2afe633d8e2e3d87fe9bb3
Signed-off-by: Jackeagle <jackeagle102@gmail.com>
diff --git a/.gitreview b/.gitreview
new file mode 100644
index 0000000..a8a330a
--- /dev/null
+++ b/.gitreview
@@ -0,0 +1,5 @@
+[gerrit]
+host=review.blissroms.com
+port=29418
+project=platform_frameworks_opt_telephony.git
+defaultbranch=p9.0
diff --git a/Android.mk b/Android.mk
index 561aed0..24f9128 100644
--- a/Android.mk
+++ b/Android.mk
@@ -24,7 +24,7 @@
$(call all-Iaidl-files-under, src/java) \
$(call all-logtags-files-under, src/java)
-LOCAL_JAVA_LIBRARIES := voip-common ims-common services bouncycastle
+LOCAL_JAVA_LIBRARIES := voip-common ims-common telephony-ext services bouncycastle
LOCAL_STATIC_JAVA_LIBRARIES := \
telephony-protos \
android.hardware.radio-V1.0-java \
@@ -32,7 +32,8 @@
android.hardware.radio-V1.2-java \
android.hardware.radio.config-V1.0-java \
android.hardware.radio.deprecated-V1.0-java \
- android.hidl.base-V1.0-java
+ android.hidl.base-V1.0-java \
+ ims-ext-common
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := telephony-common
diff --git a/src/java/com/android/internal/telephony/BaseCommands.java b/src/java/com/android/internal/telephony/BaseCommands.java
index c8cea5a..7b61364 100644
--- a/src/java/com/android/internal/telephony/BaseCommands.java
+++ b/src/java/com/android/internal/telephony/BaseCommands.java
@@ -879,8 +879,7 @@
return mRilVersion;
}
- public void setUiccSubscription(int slotId, int appIndex, int subId, int subStatus,
- Message response) {
+ public void setUiccSubscription(int appIndex, boolean activate, Message response) {
}
public void setDataAllowed(boolean allowed, Message response) {
diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java
index 9f6ce5e..c9ce5b4 100644
--- a/src/java/com/android/internal/telephony/CommandsInterface.java
+++ b/src/java/com/android/internal/telephony/CommandsInterface.java
@@ -1952,20 +1952,15 @@
/**
* Sets user selected subscription at Modem.
*
- * @param slotId
- * Slot.
* @param appIndex
* Application index in the card.
- * @param subId
- * Indicates subscription 0 or subscription 1.
- * @param subStatus
- * Activation status, 1 = activate and 0 = deactivate.
+ * @param activate
+ * Whether to activate or deactivate the subscription.
* @param result
* Callback message contains the information of SUCCESS/FAILURE.
*/
// FIXME Update the doc and consider modifying the request to make more generic.
- public void setUiccSubscription(int slotId, int appIndex, int subId, int subStatus,
- Message result);
+ public void setUiccSubscription(int appIndex, boolean activate, Message result);
/**
* Tells the modem if data is allowed or not.
diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
index 13f8b0b..fa8cbe2 100644
--- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
@@ -2164,7 +2164,11 @@
// Complete pending USSD
if (isUssdRelease) {
- found.onUssdRelease();
+ if (SystemProperties.getBoolean("ro.telephony.isHisiRIL", false)) {
+ found.onUssdFinished(ussdMessage, isUssdRequest);
+ } else {
+ found.onUssdRelease();
+ }
} else if (isUssdError) {
found.onUssdFinishedError();
} else {
@@ -2668,6 +2672,7 @@
}
mUiccApplication.set(newUiccApplication);
mIccRecords.set(newUiccApplication.getIccRecords());
+ logd("mIccRecords = " + mIccRecords);
registerForIccRecordEvents();
mIccPhoneBookIntManager.updateIccRecords(mIccRecords.get());
}
@@ -3282,7 +3287,7 @@
}
}
- private void phoneObjectUpdater(int newVoiceRadioTech) {
+ protected void phoneObjectUpdater(int newVoiceRadioTech) {
logd("phoneObjectUpdater: newVoiceRadioTech=" + newVoiceRadioTech);
// Check for a voice over lte replacement
@@ -3467,6 +3472,8 @@
pw.println("GsmCdmaPhone extends:");
super.dump(fd, pw, args);
pw.println(" mPrecisePhoneType=" + mPrecisePhoneType);
+ pw.println(" mSimRecords=" + mSimRecords);
+ pw.println(" mIsimUiccRecords=" + mIsimUiccRecords);
pw.println(" mCT=" + mCT);
pw.println(" mSST=" + mSST);
pw.println(" mPendingMMIs=" + mPendingMMIs);
@@ -3522,7 +3529,8 @@
/**
* @return operator numeric.
*/
- private String getOperatorNumeric() {
+ @Override
+ public String getOperatorNumeric() {
String operatorNumeric = null;
if (isPhoneTypeGsm()) {
IccRecords r = mIccRecords.get();
diff --git a/src/java/com/android/internal/telephony/IIccPhoneBook.aidl b/src/java/com/android/internal/telephony/IIccPhoneBook.aidl
index 5090d1a..3dc3ba3 100644
--- a/src/java/com/android/internal/telephony/IIccPhoneBook.aidl
+++ b/src/java/com/android/internal/telephony/IIccPhoneBook.aidl
@@ -16,6 +16,8 @@
package com.android.internal.telephony;
+import android.content.ContentValues;
+
import com.android.internal.telephony.uicc.AdnRecord;
@@ -103,6 +105,22 @@
String oldTag, String oldPhoneNumber,
String newTag, String newPhoneNumber,
String pin2);
+
+ /**
+ * Replace oldAdn with newAdn in ADN-like record in EF
+ *
+ * getAdnRecordsInEf must be called at least once before this function,
+ * otherwise an error will be returned
+ *
+ * @param subId user preferred subId
+ * @param efid must be one among EF_ADN, EF_FDN, and EF_SDN
+ * @param values including ADN,EMAIL,ANR to be updated
+ * @param pin2 required to update EF_FDN, otherwise must be null
+ * @return true for success
+ */
+ boolean updateAdnRecordsWithContentValuesInEfBySearchUsingSubId(int subId,
+ int efid, in ContentValues values, String pin2);
+
/**
* Update an ADN-like EF record by record index
*
@@ -165,4 +183,39 @@
*/
int[] getAdnRecordsSizeForSubscriber(int subId, int efid);
+ /**
+ * Get the capacity of ADN records
+ *
+ * @return int[10] array
+ * capacity[0] is the max count of ADN
+ * capacity[1] is the used count of ADN
+ * capacity[2] is the max count of EMAIL
+ * capacity[3] is the used count of EMAIL
+ * capacity[4] is the max count of ANR
+ * capacity[5] is the used count of ANR
+ * capacity[6] is the max length of name
+ * capacity[7] is the max length of number
+ * capacity[8] is the max length of email
+ * capacity[9] is the max length of anr
+ */
+ int[] getAdnRecordsCapacity();
+
+ /**
+ * Get the capacity of ADN records
+ *
+ * @param subId user preferred subId
+ * @return int[10] array
+ * capacity[0] is the max count of ADN
+ * capacity[1] is the used count of ADN
+ * capacity[2] is the max count of EMAIL
+ * capacity[3] is the used count of EMAIL
+ * capacity[4] is the max count of ANR
+ * capacity[5] is the used count of ANR
+ * capacity[6] is the max length of name
+ * capacity[7] is the max length of number
+ * capacity[8] is the max length of email
+ * capacity[9] is the max length of anr
+ */
+ int[] getAdnRecordsCapacityForSubscriber(int subId);
+
}
diff --git a/src/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java b/src/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java
index 2a35370..40e8ba4 100644
--- a/src/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java
+++ b/src/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java
@@ -16,12 +16,15 @@
package com.android.internal.telephony;
+import android.content.ContentValues;
import android.content.pm.PackageManager;
import android.os.AsyncResult;
import android.os.Handler;
+import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.telephony.Rlog;
+import android.text.TextUtils;
import com.android.internal.telephony.uicc.AdnRecord;
import com.android.internal.telephony.uicc.AdnRecordCache;
@@ -58,7 +61,18 @@
protected static final int EVENT_LOAD_DONE = 2;
protected static final int EVENT_UPDATE_DONE = 3;
- protected Handler mBaseHandler = new Handler() {
+ protected final IccPbHandler mBaseHandler;
+
+ private static final HandlerThread mHandlerThread = new HandlerThread("IccPbHandlerLoader");
+ static {
+ mHandlerThread.start();
+ }
+
+ protected class IccPbHandler extends Handler {
+ public IccPbHandler(Looper looper) {
+ super(looper);
+ }
+
@Override
public void handleMessage(Message msg) {
AsyncResult ar;
@@ -81,6 +95,9 @@
break;
case EVENT_UPDATE_DONE:
ar = (AsyncResult) msg.obj;
+ if (ar.exception != null) {
+ if(DBG) logd("exception of EVENT_UPDATE_DONE is" + ar.exception);
+ }
synchronized (mLock) {
mSuccess = (ar.exception == null);
notifyPending(ar);
@@ -90,6 +107,7 @@
ar = (AsyncResult)msg.obj;
synchronized (mLock) {
if (ar.exception == null) {
+ if(DBG) logd("Load ADN records done");
mRecords = (List<AdnRecord>) ar.result;
} else {
if(DBG) logd("Cannot load ADN records");
@@ -116,6 +134,7 @@
if (r != null) {
mAdnCache = r.getAdnCache();
}
+ mBaseHandler = new IccPbHandler(mHandlerThread.getLooper());
}
public void dispose() {
@@ -196,6 +215,66 @@
}
/**
+ * Replace oldAdn with newAdn in ADN-like record in EF
+ *
+ * getAdnRecordsInEf must be called at least once before this function,
+ * otherwise an error will be returned.
+ * throws SecurityException if no WRITE_CONTACTS permission
+ *
+ * @param efid must be one among EF_ADN, EF_FDN, and EF_SDN
+ * @param values old adn tag, phone number, email and anr to be replaced
+ * new adn tag, phone number, email and anr to be stored
+ * @param newPhoneNumber adn number ot be stored
+ * @param oldPhoneNumber adn number to be replaced
+ * Set both oldTag, oldPhoneNubmer, oldEmail and oldAnr to ""
+ * means to replace an empty record, aka, insert new record
+ * Set both newTag, newPhoneNubmer, newEmail and newAnr ""
+ * means to replace the old record with empty one, aka, delete old record
+ * @param pin2 required to update EF_FDN, otherwise must be null
+ * @return true for success
+ */
+ public boolean updateAdnRecordsWithContentValuesInEfBySearch(int efid, ContentValues values,
+ String pin2) {
+
+ if (mPhone.getContext().checkCallingOrSelfPermission(
+ android.Manifest.permission.WRITE_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires android.permission.WRITE_CONTACTS permission");
+ }
+
+ String oldTag = values.getAsString(IccProvider.STR_TAG);
+ String newTag = values.getAsString(IccProvider.STR_NEW_TAG);
+ String oldPhoneNumber = values.getAsString(IccProvider.STR_NUMBER);
+ String newPhoneNumber = values.getAsString(IccProvider.STR_NEW_NUMBER);
+ String oldEmail = values.getAsString(IccProvider.STR_EMAILS);
+ String newEmail = values.getAsString(IccProvider.STR_NEW_EMAILS);
+ String oldAnr = values.getAsString(IccProvider.STR_ANRS);
+ String newAnr = values.getAsString(IccProvider.STR_NEW_ANRS);
+ String[] oldEmailArray = TextUtils.isEmpty(oldEmail) ? null : getStringArray(oldEmail);
+ String[] newEmailArray = TextUtils.isEmpty(newEmail) ? null : getStringArray(newEmail);
+ String[] oldAnrArray = TextUtils.isEmpty(oldAnr) ? null : getAnrStringArray(oldAnr);
+ String[] newAnrArray = TextUtils.isEmpty(newAnr) ? null : getAnrStringArray(newAnr);
+ efid = updateEfForIccType(efid);
+
+ if (DBG) logd("updateAdnRecordsWithContentValuesInEfBySearch: efid=" + efid +
+ ", values = " + values + ", pin2=" + pin2);
+ synchronized (mLock) {
+ checkThread();
+ mSuccess = false;
+ AtomicBoolean status = new AtomicBoolean(false);
+ Message response = mBaseHandler.obtainMessage(EVENT_UPDATE_DONE, status);
+ AdnRecord oldAdn = new AdnRecord(oldTag, oldPhoneNumber, oldEmailArray, oldAnrArray);
+ AdnRecord newAdn = new AdnRecord(newTag, newPhoneNumber, newEmailArray, newAnrArray);
+ if (mAdnCache != null) {
+ mAdnCache.updateAdnBySearch(efid, oldAdn, newAdn, pin2, response);
+ waitForResult(status);
+ } else {
+ loge("Failure while trying to update by search due to uninitialised adncache");
+ }
+ }
+ return mSuccess;
+ }
+
+ /**
* Update an ADN-like EF record by record index
*
* This is useful for iteration the whole ADN file, such as write the whole
@@ -311,7 +390,7 @@
protected void checkThread() {
if (!ALLOW_SIM_OP_IN_UI_THREAD) {
// Make sure this isn't the UI thread, since it will block
- if (mBaseHandler.getLooper().equals(Looper.myLooper())) {
+ if (Looper.getMainLooper().equals(Looper.myLooper())) {
loge("query() called on the main UI thread!");
throw new IllegalStateException(
"You cannot call query on this provder from the main UI thread.");
@@ -329,7 +408,7 @@
}
}
- private int updateEfForIccType(int efid) {
+ protected int updateEfForIccType(int efid) {
// Check if we are trying to read ADN records
if (efid == IccConstants.EF_ADN) {
if (mPhone.getCurrentUiccAppType() == AppType.APPTYPE_USIM) {
@@ -338,5 +417,41 @@
}
return efid;
}
+
+ protected String[] getStringArray(String str) {
+ if (str != null) {
+ return str.split(",");
+ }
+ return null;
+ }
+
+ protected String[] getAnrStringArray(String str) {
+ if (str != null) {
+ return str.split(":");
+ }
+ return null;
+ }
+
+ /**
+ * Get the capacity of ADN records
+ *
+ * @return int[6] array
+ * capacity[0] is the max count of ADN
+ * capacity[1] is the used count of ADN
+ * capacity[2] is the max count of EMAIL
+ * capacity[3] is the used count of EMAIL
+ * capacity[4] is the max count of ANR
+ * capacity[5] is the used count of ANR
+ * capacity[6] is the max length of name
+ * capacity[7] is the max length of number
+ * capacity[8] is the max length of email
+ * capacity[9] is the max length of anr
+ */
+ public int[] getAdnRecordsCapacity() {
+ if (DBG) logd("getAdnRecordsCapacity");
+ int capacity[] = new int[10];
+
+ return capacity;
+ }
}
diff --git a/src/java/com/android/internal/telephony/IccProvider.java b/src/java/com/android/internal/telephony/IccProvider.java
index 8feec94..a1ada42 100644
--- a/src/java/com/android/internal/telephony/IccProvider.java
+++ b/src/java/com/android/internal/telephony/IccProvider.java
@@ -48,6 +48,7 @@
"name",
"number",
"emails",
+ "anrs",
"_id"
};
@@ -59,10 +60,15 @@
protected static final int SDN_SUB = 6;
protected static final int ADN_ALL = 7;
- protected static final String STR_TAG = "tag";
- protected static final String STR_NUMBER = "number";
- protected static final String STR_EMAILS = "emails";
- protected static final String STR_PIN2 = "pin2";
+ public static final String STR_TAG = "tag";
+ public static final String STR_NUMBER = "number";
+ public static final String STR_EMAILS = "emails";
+ public static final String STR_ANRS = "anrs";
+ public static final String STR_NEW_TAG = "newTag";
+ public static final String STR_NEW_NUMBER = "newNumber";
+ public static final String STR_NEW_EMAILS = "newEmails";
+ public static final String STR_NEW_ANRS = "newAnrs";
+ public static final String STR_PIN2 = "pin2";
private static final UriMatcher URL_MATCHER =
new UriMatcher(UriMatcher.NO_MATCH);
@@ -197,8 +203,19 @@
String tag = initialValues.getAsString("tag");
String number = initialValues.getAsString("number");
- // TODO(): Read email instead of sending null.
- boolean success = addIccRecordToEf(efType, tag, number, null, pin2, subId);
+ String emails = initialValues.getAsString("emails");
+ String anrs = initialValues.getAsString("anrs");
+
+ ContentValues values = new ContentValues();
+ values.put(STR_TAG,"");
+ values.put(STR_NUMBER,"");
+ values.put(STR_EMAILS,"");
+ values.put(STR_ANRS,"");
+ values.put(STR_NEW_TAG,tag);
+ values.put(STR_NEW_NUMBER,number);
+ values.put(STR_NEW_EMAILS,emails);
+ values.put(STR_NEW_ANRS,anrs);
+ boolean success = updateIccRecordInEf(efType, values, pin2, subId);
if (!success) {
return null;
@@ -291,10 +308,11 @@
// parse where clause
String tag = null;
String number = null;
- String[] emails = null;
+ String emails = null;
+ String anrs = null;
String pin2 = null;
- String[] tokens = where.split("AND");
+ String[] tokens = where.split(" AND ");
int n = tokens.length;
while (--n >= 0) {
@@ -315,18 +333,29 @@
} else if (STR_NUMBER.equals(key)) {
number = normalizeValue(val);
} else if (STR_EMAILS.equals(key)) {
- //TODO(): Email is null.
- emails = null;
+ emails = normalizeValue(val);
+ } else if (STR_ANRS.equals(key)) {
+ anrs = normalizeValue(val);
} else if (STR_PIN2.equals(key)) {
pin2 = normalizeValue(val);
}
}
+ ContentValues values = new ContentValues();
+ values.put(STR_TAG,tag);
+ values.put(STR_NUMBER,number);
+ values.put(STR_EMAILS,emails);
+ values.put(STR_ANRS,anrs);
+ values.put(STR_NEW_TAG,"");
+ values.put(STR_NEW_NUMBER,"");
+ values.put(STR_NEW_EMAILS,"");
+ values.put(STR_NEW_ANRS,"");
if (efType == FDN && TextUtils.isEmpty(pin2)) {
return 0;
}
- boolean success = deleteIccRecordFromEf(efType, tag, number, emails, pin2, subId);
+ if (DBG) log("delete mvalues= " + values);
+ boolean success = updateIccRecordInEf(efType, values, pin2, subId);
if (!success) {
return 0;
}
@@ -379,8 +408,7 @@
String newNumber = values.getAsString("newNumber");
String[] newEmails = null;
// TODO(): Update for email.
- boolean success = updateIccRecordInEf(efType, tag, number,
- newTag, newNumber, pin2, subId);
+ boolean success = updateIccRecordInEf(efType, values, pin2, subId);
if (!success) {
return 0;
@@ -454,21 +482,17 @@
}
private boolean
- updateIccRecordInEf(int efType, String oldName, String oldNumber,
- String newName, String newNumber, String pin2, int subId) {
- if (DBG) log("updateIccRecordInEf: efType=0x" + Integer.toHexString(efType).toUpperCase() +
- ", oldname=" + Rlog.pii(TAG, oldName) + ", oldnumber=" + Rlog.pii(TAG, oldNumber) +
- ", newname=" + Rlog.pii(TAG, newName) + ", newnumber=" + Rlog.pii(TAG, newName) +
- ", subscription=" + subId);
-
+ updateIccRecordInEf(int efType, ContentValues values, String pin2, int subId) {
boolean success = false;
+ if (DBG) log("updateIccRecordInEf: efType=" + efType +
+ ", values: [ "+ values + " ], subId:" + subId);
try {
IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface(
ServiceManager.getService("simphonebook"));
if (iccIpb != null) {
- success = iccIpb.updateAdnRecordsInEfBySearchForSubscriber(subId, efType, oldName,
- oldNumber, newName, newNumber, pin2);
+ success = iccIpb.updateAdnRecordsWithContentValuesInEfBySearchUsingSubId(subId,
+ efType, values, pin2);
}
} catch (RemoteException ex) {
// ignore it
@@ -479,7 +503,6 @@
return success;
}
-
private boolean deleteIccRecordFromEf(int efType, String name, String number, String[] emails,
String pin2, int subId) {
if (DBG) log("deleteIccRecordFromEf: efType=0x" +
@@ -513,9 +536,10 @@
*/
private void loadRecord(AdnRecord record, MatrixCursor cursor, int id) {
if (!record.isEmpty()) {
- Object[] contact = new Object[4];
+ Object[] contact = new Object[5];
String alphaTag = record.getAlphaTag();
String number = record.getNumber();
+ String[] anrs = record.getAdditionalNumbers();
if (DBG) log("loadRecord: " + alphaTag + ", " + Rlog.pii(TAG, number));
contact[0] = alphaTag;
@@ -531,7 +555,18 @@
}
contact[2] = emailString.toString();
}
- contact[3] = id;
+
+ if (anrs != null) {
+ StringBuilder anrString = new StringBuilder();
+ for (String anr : anrs) {
+ if (DBG) log("Adding anr:" + anr);
+ anrString.append(anr);
+ anrString.append(":");
+ }
+ contact[3] = anrString.toString();
+ }
+
+ contact[4] = id;
cursor.addRow(contact);
}
}
diff --git a/src/java/com/android/internal/telephony/LocaleTracker.java b/src/java/com/android/internal/telephony/LocaleTracker.java
index 996e288..9d730d4 100644
--- a/src/java/com/android/internal/telephony/LocaleTracker.java
+++ b/src/java/com/android/internal/telephony/LocaleTracker.java
@@ -408,8 +408,9 @@
// Set the country code for wifi. This sets allowed wifi channels based on the
// country of the carrier we see. If we can't see any, reset to 0 so we don't
// broadcast on forbidden channels.
- ((WifiManager) mPhone.getContext().getSystemService(Context.WIFI_SERVICE))
- .setCountryCode(countryIso);
+ if (mPhone.getContext().getSystemService(Context.WIFI_SERVICE) != null)
+ ((WifiManager) mPhone.getContext().getSystemService(Context.WIFI_SERVICE))
+ .setCountryCode(countryIso);
}
}
diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java
index c2446e4..3e18b92 100644
--- a/src/java/com/android/internal/telephony/Phone.java
+++ b/src/java/com/android/internal/telephony/Phone.java
@@ -285,7 +285,7 @@
private boolean mImsServiceReady = false;
protected Phone mImsPhone = null;
- private final AtomicReference<RadioCapability> mRadioCapability =
+ protected final AtomicReference<RadioCapability> mRadioCapability =
new AtomicReference<RadioCapability>();
private static final int DEFAULT_REPORT_INTERVAL_MS = 200;
@@ -1289,7 +1289,7 @@
private void updateSavedNetworkOperator(NetworkSelectMessage nsm) {
int subId = getSubId();
- if (SubscriptionManager.isValidSubscriptionId(subId)) {
+ if (SubscriptionController.getInstance().isActiveSubId(subId)) {
// open the shared preferences editor, and write the value.
// nsm.operatorNumeric is "" if we're in automatic.selection.
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
@@ -1762,7 +1762,7 @@
private int getCallForwardingIndicatorFromSharedPref() {
int status = IccRecords.CALL_FORWARDING_STATUS_DISABLED;
int subId = getSubId();
- if (SubscriptionManager.isValidSubscriptionId(subId)) {
+ if (SubscriptionController.getInstance().isActiveSubId(subId)) {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
status = sp.getInt(CF_STATUS + subId, IccRecords.CALL_FORWARDING_STATUS_UNKNOWN);
Rlog.d(LOG_TAG, "getCallForwardingIndicatorFromSharedPref: for subId " + subId + "= " +
@@ -2292,7 +2292,7 @@
public void setVoiceMessageCount(int countWaiting) {
mVmCount = countWaiting;
int subId = getSubId();
- if (SubscriptionManager.isValidSubscriptionId(subId)) {
+ if (SubscriptionController.getInstance().isActiveSubId(subId)) {
Rlog.d(LOG_TAG, "setVoiceMessageCount: Storing Voice Mail Count = " + countWaiting +
" for mVmCountKey = " + VM_COUNT + subId + " in preferences.");
@@ -2312,7 +2312,7 @@
protected int getStoredVoiceMessageCount() {
int countVoiceMessages = 0;
int subId = getSubId();
- if (SubscriptionManager.isValidSubscriptionId(subId)) {
+ if (SubscriptionController.getInstance().isActiveSubId(subId)) {
int invalidCount = -2; //-1 is not really invalid. It is used for unknown number of vm
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
int countFromSP = sp.getInt(VM_COUNT + subId, invalidCount);
@@ -3395,7 +3395,7 @@
protected void setPreferredNetworkTypeIfSimLoaded() {
int subId = getSubId();
- if (SubscriptionManager.isValidSubscriptionId(subId)) {
+ if (SubscriptionManager.from(mContext).isActiveSubId(subId)) {
int type = PhoneFactory.calculatePreferredNetworkType(mContext, getSubId());
setPreferredNetworkType(type, null);
}
@@ -3589,6 +3589,10 @@
public void cancelUSSD() {
}
+ public String getOperatorNumeric() {
+ return "";
+ }
+
/**
* Set boolean broadcastEmergencyCallStateChanges
*/
diff --git a/src/java/com/android/internal/telephony/PhoneFactory.java b/src/java/com/android/internal/telephony/PhoneFactory.java
index ba77747..50627fe 100644
--- a/src/java/com/android/internal/telephony/PhoneFactory.java
+++ b/src/java/com/android/internal/telephony/PhoneFactory.java
@@ -136,6 +136,8 @@
}
sPhoneNotifier = new DefaultPhoneNotifier();
+ TelephonyComponentFactory telephonyComponentFactory
+ = TelephonyComponentFactory.getInstance();
int cdmaSubscription = CdmaSubscriptionSourceManager.getDefault(context);
Rlog.i(LOG_TAG, "Cdma Subscription set to " + cdmaSubscription);
@@ -168,11 +170,11 @@
networkModes[i] = RILConstants.PREFERRED_NETWORK_MODE;
Rlog.i(LOG_TAG, "Network Mode set to " + Integer.toString(networkModes[i]));
- sCommandsInterfaces[i] = new RIL(context, networkModes[i],
- cdmaSubscription, i);
+ sCommandsInterfaces[i] = telephonyComponentFactory.makeRIL(context,
+ networkModes[i], cdmaSubscription, i);
}
Rlog.i(LOG_TAG, "Creating SubscriptionController");
- SubscriptionController.init(context, sCommandsInterfaces);
+ telephonyComponentFactory.initSubscriptionController(context, sCommandsInterfaces);
// Instantiate UiccController so that all other classes can just
// call getInstance()
@@ -188,15 +190,15 @@
Phone phone = null;
int phoneType = TelephonyManager.getPhoneType(networkModes[i]);
if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
- phone = new GsmCdmaPhone(context,
+ phone = telephonyComponentFactory.makePhone(context,
sCommandsInterfaces[i], sPhoneNotifier, i,
PhoneConstants.PHONE_TYPE_GSM,
- TelephonyComponentFactory.getInstance());
+ telephonyComponentFactory);
} else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
- phone = new GsmCdmaPhone(context,
+ phone = telephonyComponentFactory.makePhone(context,
sCommandsInterfaces[i], sPhoneNotifier, i,
- PhoneConstants.PHONE_TYPE_CDMA_LTE,
- TelephonyComponentFactory.getInstance());
+ PhoneConstants.PHONE_TYPE_CDMA,
+ telephonyComponentFactory);
}
Rlog.i(LOG_TAG, "Creating Phone with type = " + phoneType + " sub = " + i);
@@ -225,8 +227,11 @@
sMadeDefaults = true;
Rlog.i(LOG_TAG, "Creating SubInfoRecordUpdater ");
- sSubInfoRecordUpdater = new SubscriptionInfoUpdater(
- BackgroundThread.get().getLooper(), context, sPhones, sCommandsInterfaces);
+ sSubInfoRecordUpdater = sContext.getResources().getBoolean(com.android.internal.R.bool.config_oldQtiTelephony)
+ ? telephonyComponentFactory.makeSubscriptionInfoUpdater(
+ context, sPhones, sCommandsInterfaces)
+ : telephonyComponentFactory.makeSubscriptionInfoUpdater(
+ BackgroundThread.get().getLooper(), context, sPhones, sCommandsInterfaces);
SubscriptionController.getInstance().updatePhonesAvailability(sPhones);
// Start monitoring after defaults have been made.
@@ -243,7 +248,8 @@
sSubscriptionMonitor = new SubscriptionMonitor(tr, sContext, sc, numPhones);
- sPhoneSwitcher = new PhoneSwitcher(MAX_ACTIVE_PHONES, numPhones,
+ sPhoneSwitcher = telephonyComponentFactory.
+ makePhoneSwitcher(MAX_ACTIVE_PHONES, numPhones,
sContext, sc, Looper.myLooper(), tr, sCommandsInterfaces,
sPhones);
@@ -260,6 +266,8 @@
sPhoneSwitcher, sc, sSubscriptionMonitor, Looper.myLooper(),
sContext, i, sPhones[i].mDcTracker);
}
+ telephonyComponentFactory.makeExtTelephonyClasses(
+ context, sPhones, sCommandsInterfaces);
}
}
}
diff --git a/src/java/com/android/internal/telephony/PhoneSwitcher.java b/src/java/com/android/internal/telephony/PhoneSwitcher.java
index cd28b2b..be122bb 100644
--- a/src/java/com/android/internal/telephony/PhoneSwitcher.java
+++ b/src/java/com/android/internal/telephony/PhoneSwitcher.java
@@ -57,29 +57,32 @@
* the active phones. Note we don't wait for data attach (which may not happen anyway).
*/
public class PhoneSwitcher extends Handler {
- private final static String LOG_TAG = "PhoneSwitcher";
- private final static boolean VDBG = false;
+ protected final static String LOG_TAG = "PhoneSwitcher";
+ protected final static boolean VDBG = false;
- private final int mMaxActivePhones;
- private final List<DcRequest> mPrioritizedDcRequests = new ArrayList<DcRequest>();
- private final RegistrantList[] mActivePhoneRegistrants;
- private final SubscriptionController mSubscriptionController;
- private final int[] mPhoneSubscriptions;
- private final CommandsInterface[] mCommandsInterfaces;
- private final Context mContext;
- private final PhoneState[] mPhoneStates;
- private final int mNumPhones;
+ protected int mMaxActivePhones;
+ protected final List<DcRequest> mPrioritizedDcRequests = new ArrayList<DcRequest>();
+ protected final RegistrantList[] mActivePhoneRegistrants;
+ protected final SubscriptionController mSubscriptionController;
+ protected final int[] mPhoneSubscriptions;
+ protected final CommandsInterface[] mCommandsInterfaces;
+ protected final Context mContext;
+ protected final PhoneState[] mPhoneStates;
+ protected final int mNumPhones;
private final Phone[] mPhones;
private final LocalLog mLocalLog;
- private int mDefaultDataSubscription;
+ protected int mDefaultDataSubscription;
- private final static int EVENT_DEFAULT_SUBSCRIPTION_CHANGED = 101;
- private final static int EVENT_SUBSCRIPTION_CHANGED = 102;
+ protected final static int EVENT_DEFAULT_SUBSCRIPTION_CHANGED = 101;
+ protected final static int EVENT_SUBSCRIPTION_CHANGED = 102;
private final static int EVENT_REQUEST_NETWORK = 103;
private final static int EVENT_RELEASE_NETWORK = 104;
private final static int EVENT_EMERGENCY_TOGGLE = 105;
private final static int EVENT_RESEND_DATA_ALLOWED = 106;
+ protected final static int EVENT_VOICE_CALL_ENDED = 107;
+ protected static final int EVENT_UNSOL_MAX_DATA_ALLOWED_CHANGED = 108;
+ protected static final int EVENT_OEM_HOOK_SERVICE_READY = 109;
private final static int MAX_LOCAL_LOG_LINES = 30;
@@ -204,7 +207,7 @@
}
}
- private boolean isEmergency() {
+ protected boolean isEmergency() {
for (Phone p : mPhones) {
if (p == null) continue;
if (p.isInEcm() || p.isInEmergencyCall()) return true;
@@ -255,7 +258,7 @@
}
private static final boolean REQUESTS_CHANGED = true;
- private static final boolean REQUESTS_UNCHANGED = false;
+ protected static final boolean REQUESTS_UNCHANGED = false;
/**
* Re-evaluate things.
* Do nothing if nothing's changed.
@@ -265,7 +268,7 @@
* phones that aren't in the active phone list. Finally, activate all
* phones in the active phone list.
*/
- private void onEvaluate(boolean requestsChanged, String reason) {
+ protected void onEvaluate(boolean requestsChanged, String reason) {
StringBuilder sb = new StringBuilder(reason);
if (isEmergency()) {
log("onEvalute aborted due to Emergency");
@@ -326,12 +329,12 @@
}
}
- private static class PhoneState {
+ protected static class PhoneState {
public volatile boolean active = false;
public long lastRequested = 0;
}
- private void deactivate(int phoneId) {
+ protected void deactivate(int phoneId) {
PhoneState state = mPhoneStates[phoneId];
if (state.active == false) return;
state.active = false;
@@ -344,7 +347,7 @@
mActivePhoneRegistrants[phoneId].notifyRegistrants();
}
- private void activate(int phoneId) {
+ protected void activate(int phoneId) {
PhoneState state = mPhoneStates[phoneId];
if (state.active == true) return;
state.active = true;
@@ -366,7 +369,7 @@
msg.sendToTarget();
}
- private void onResendDataAllowed(Message msg) {
+ protected void onResendDataAllowed(Message msg) {
final int phoneId = msg.arg1;
// Skip ALLOW_DATA for single SIM device
if (mNumPhones > 1) {
@@ -374,7 +377,7 @@
}
}
- private int phoneIdForRequest(NetworkRequest netRequest) {
+ protected int phoneIdForRequest(NetworkRequest netRequest) {
NetworkSpecifier specifier = netRequest.networkCapabilities.getNetworkSpecifier();
int subId;
@@ -427,7 +430,7 @@
}
}
- private void log(String l) {
+ protected void log(String l) {
Rlog.d(LOG_TAG, l);
mLocalLog.log(l);
}
diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java
index 9e74ee2..eeeb3c4 100644
--- a/src/java/com/android/internal/telephony/RIL.java
+++ b/src/java/com/android/internal/telephony/RIL.java
@@ -20,6 +20,7 @@
import static com.android.internal.util.Preconditions.checkNotNull;
import android.content.Context;
+import android.content.res.Resources;
import android.hardware.radio.V1_0.Carrier;
import android.hardware.radio.V1_0.CarrierRestrictions;
import android.hardware.radio.V1_0.CdmaBroadcastSmsConfigInfo;
@@ -71,6 +72,7 @@
import android.os.WorkSource;
import android.service.carrier.CarrierIdentifier;
import android.telephony.AccessNetworkConstants.AccessNetworkType;
+import android.telephony.CarrierConfigManager;
import android.telephony.CellIdentity;
import android.telephony.CellIdentityCdma;
import android.telephony.CellInfo;
@@ -119,6 +121,18 @@
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
+import static android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN;
+import static android.telephony.TelephonyManager.NETWORK_TYPE_GPRS;
+import static android.telephony.TelephonyManager.NETWORK_TYPE_EDGE;
+import static android.telephony.TelephonyManager.NETWORK_TYPE_UMTS;
+import static android.telephony.TelephonyManager.NETWORK_TYPE_HSDPA;
+import static android.telephony.TelephonyManager.NETWORK_TYPE_HSUPA;
+import static android.telephony.TelephonyManager.NETWORK_TYPE_HSPA;
+import static android.telephony.TelephonyManager.NETWORK_TYPE_LTE;
+import static android.telephony.TelephonyManager.NETWORK_TYPE_HSPAP;
+import static android.telephony.TelephonyManager.NETWORK_TYPE_GSM;
+import static android.telephony.TelephonyManager.NETWORK_TYPE_LTE_CA;
+
/**
* RIL implementation of the CommandsInterface.
*
@@ -174,9 +188,10 @@
AtomicBoolean mTestingEmergencyCall = new AtomicBoolean(false);
final Integer mPhoneId;
+ private List<String> mOldRilFeatures;
/* default work source which will blame phone process */
- private WorkSource mRILDefaultWorkSource;
+ protected WorkSource mRILDefaultWorkSource;
/* Worksource containing all applications causing wakelock to be held */
private WorkSource mActiveWakelockWorkSource;
@@ -184,7 +199,7 @@
/** Telephony metrics instance for logging metrics event */
private TelephonyMetrics mMetrics = TelephonyMetrics.getInstance();
- boolean mIsMobileNetworkSupported;
+ protected boolean mIsMobileNetworkSupported;
RadioResponse mRadioResponse;
RadioIndication mRadioIndication;
volatile IRadio mRadioProxy = null;
@@ -195,6 +210,9 @@
final RadioProxyDeathRecipient mRadioProxyDeathRecipient;
final RilHandler mRilHandler;
+ private static RIL sRil;
+ private static int[][] sSignalCust;
+
//***** Events
static final int EVENT_WAKE_LOCK_TIMEOUT = 2;
static final int EVENT_ACK_WAKE_LOCK_TIMEOUT = 4;
@@ -331,7 +349,7 @@
}
}
- private void resetProxyAndRequestList() {
+ protected void resetProxyAndRequestList() {
mRadioProxy = null;
mOemHookProxy = null;
@@ -456,6 +474,9 @@
mPhoneType = RILConstants.NO_PHONE;
mPhoneId = instanceId;
+ final String oldRilFeatures = SystemProperties.get("ro.telephony.ril.config", "");
+ mOldRilFeatures = Arrays.asList(oldRilFeatures.split(","));
+
ConnectivityManager cm = (ConnectivityManager)context.getSystemService(
Context.CONNECTIVITY_SERVICE);
mIsMobileNetworkSupported = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
@@ -467,6 +488,49 @@
mRilHandler = new RilHandler();
mRadioProxyDeathRecipient = new RadioProxyDeathRecipient();
+ sRil = this;
+
+ // Create custom signal strength thresholds based on Huawei's
+ if (sSignalCust == null) {
+ final int THRESHOLDS = 4;
+ final int STEPS = THRESHOLDS - 1;
+ sSignalCust = new int[3][THRESHOLDS];
+ String[][] hwSignalCust = {
+ SystemProperties.get("gsm.sigcust.gsm",
+ "5,false,-109,-103,-97,-91,-85").split(","),
+ SystemProperties.get("gsm.sigcust.lte",
+ "5,false,-120,-115,-110,-105,-97").split(","),
+ SystemProperties.get("gsm.sigcust.umts",
+ "5,false,-112,-105,-99,-93,-87").split(",")
+ };
+ for (int i = 0; i < sSignalCust.length; i++) {
+ // Get the highest and the lowest dBm values
+ int max = Integer.parseInt(hwSignalCust[i][hwSignalCust[i].length - 1]);
+ int min = Integer.parseInt(hwSignalCust[i][hwSignalCust[i].length -
+ Integer.parseInt(hwSignalCust[i][0])]);
+ // Default distance between thresholds
+ int step = (max - min) / STEPS;
+ // Extra distance that needs to be accounted for
+ int rem = (max - min) % STEPS;
+
+ // Fill the array with the basic step distance
+ for (int j = 0; j < sSignalCust[i].length; j++) {
+ sSignalCust[i][j] = min + step * j;
+ }
+
+ // Make the max line up
+ sSignalCust[i][sSignalCust[i].length - 1] += rem;
+
+ // Distribute the remainder
+ int j = sSignalCust[i].length - 2;
+ while (rem > 0 && j > 0) {
+ sSignalCust[i][j]++;
+ j--;
+ rem--;
+ }
+ }
+ }
+
PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, RILJ_WAKELOCK_TAG);
mWakeLock.setReferenceCounted(false);
@@ -515,6 +579,12 @@
return rr;
}
+ protected int obtainRequestSerial(int request, Message result, WorkSource workSource) {
+ RILRequest rr = RILRequest.obtain(request, result, workSource);
+ addRequest(rr);
+ return rr.mSerial;
+ }
+
private void handleRadioProxyExceptionForRR(RILRequest rr, String caller, Exception e) {
riljLoge(caller + ": " + e);
resetProxyAndRequestList();
@@ -3315,8 +3385,7 @@
}
@Override
- public void setUiccSubscription(int slotId, int appIndex, int subId,
- int subStatus, Message result) {
+ public void setUiccSubscription(int appIndex, boolean activate, Message result) {
IRadio radioProxy = getRadioProxy(result);
if (radioProxy != null) {
RILRequest rr = obtainRequest(RIL_REQUEST_SET_UICC_SUBSCRIPTION, result,
@@ -3324,15 +3393,14 @@
if (RILJ_LOGD) {
riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
- + " slot = " + slotId + " appIndex = " + appIndex
- + " subId = " + subId + " subStatus = " + subStatus);
+ + " appIndex: " + appIndex + " activate: " + activate);
}
SelectUiccSub info = new SelectUiccSub();
- info.slot = slotId;
+ info.slot = mPhoneId;
info.appIndex = appIndex;
- info.subType = subId;
- info.actStatus = subStatus;
+ info.subType = mPhoneId;
+ info.actStatus = activate ? 1 : 0;
try {
radioProxy.setUiccSubscription(rr.mSerial, info);
@@ -4196,6 +4264,15 @@
return rr;
}
+ protected Message getMessageFromRequest(Object request) {
+ RILRequest rr = (RILRequest)request;
+ Message result = null;
+ if (rr != null) {
+ result = rr.mResult;
+ }
+ return result;
+ }
+
/**
* This is a helper function to be called at the end of all RadioResponse callbacks.
* It takes care of sending error response, logging, decrementing wakelock if needed, and
@@ -4228,6 +4305,11 @@
}
}
+ protected void processResponseDone(Object request, RadioResponseInfo responseInfo, Object ret) {
+ RILRequest rr = (RILRequest)request;
+ processResponseDone(rr, responseInfo, ret);
+ }
+
/**
* Function to send ack and acquire related wakelock
*/
@@ -5502,10 +5584,159 @@
return response;
}
+ static SignalStrength convertHalSignalStrengthHuawei(
+ android.hardware.radio.V1_0.SignalStrength signalStrength, int phoneId) {
+ int gsmSignalStrength = signalStrength.gw.signalStrength;
+ int gsmBitErrorRate = signalStrength.gw.bitErrorRate;
+ int cdmaDbm = signalStrength.cdma.dbm;
+ int cdmaEcio = signalStrength.cdma.ecio;
+ int evdoDbm = signalStrength.evdo.dbm;
+ int evdoEcio = signalStrength.evdo.ecio;
+ int evdoSnr = signalStrength.evdo.signalNoiseRatio;
+ int lteSignalStrength = signalStrength.lte.signalStrength;
+ int lteRsrp = signalStrength.lte.rsrp;
+ int lteRsrq = signalStrength.lte.rsrq;
+ int lteRssnr = signalStrength.lte.rssnr;
+ int lteCqi = signalStrength.lte.cqi;
+
+ int tdscdmaRscp_1_2 = 255; // 255 is the value for unknown/unreported ASU.
+ // The HAL 1.0 range is 25..120; the ASU/ HAL 1.2 range is 0..96;
+ // yes, this means the range in 1.0 cannot express -24dBm = 96
+ if (signalStrength.tdScdma.rscp >= 25 && signalStrength.tdScdma.rscp <= 120) {
+ // First we flip the sign to convert from the HALs -rscp to the actual RSCP value.
+ int rscpDbm = -signalStrength.tdScdma.rscp;
+ // Then to convert from RSCP to ASU, we apply the offset which aligns 0 ASU to -120dBm.
+ tdscdmaRscp_1_2 = rscpDbm + 120;
+ }
+
+ TelephonyManager tm = (TelephonyManager)
+ sRil.mContext.getSystemService(Context.TELEPHONY_SERVICE);
+ int radioTech = tm.getDataNetworkType(phoneId);
+
+ if (radioTech == NETWORK_TYPE_UNKNOWN) {
+ radioTech = tm.getVoiceNetworkType(phoneId);
+ }
+
+ int[] threshRsrp = CarrierConfigManager.getDefaultConfig().getIntArray(
+ CarrierConfigManager.KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY);
+
+ if (sSignalCust != null && threshRsrp.length == 4) {
+ switch (radioTech) {
+ case NETWORK_TYPE_LTE_CA:
+ case NETWORK_TYPE_LTE:
+ if (lteRsrp > -44) { // None or Unknown
+ lteRsrp = -43;
+ lteRssnr = 301;
+ lteSignalStrength = 99;
+ } else if (lteRsrp >= sSignalCust[1][3]) { // Great
+ lteRsrp = threshRsrp[3];
+ lteRssnr = 130;
+ lteSignalStrength = 12;
+ } else if (lteRsrp >= sSignalCust[1][2]) { // Good
+ lteRsrp = threshRsrp[2];
+ lteRssnr = 45;
+ lteSignalStrength = 8;
+ } else if (lteRsrp >= sSignalCust[1][1]) { // Moderate
+ lteRsrp = threshRsrp[1];
+ lteRssnr = 10;
+ lteSignalStrength = 5;
+ } else if (lteRsrp >= sSignalCust[1][0]) { // Poor
+ lteRsrp = threshRsrp[0];
+ lteRssnr = -30;
+ lteSignalStrength = 0;
+ } else { // None or Unknown
+ lteRsrp = -140;
+ lteRssnr = -200;
+ lteSignalStrength = 99;
+ }
+ break;
+ case NETWORK_TYPE_HSPAP:
+ case NETWORK_TYPE_HSPA:
+ case NETWORK_TYPE_HSUPA:
+ case NETWORK_TYPE_HSDPA:
+ case NETWORK_TYPE_UMTS:
+ lteRsrp = (gsmSignalStrength & 0xFF) - 256;
+ if (lteRsrp > -20) { // None or Unknown
+ lteRsrp = -43;
+ lteRssnr = 301;
+ lteSignalStrength = 99;
+ } else if (lteRsrp >= sSignalCust[2][3]) { // Great
+ lteRsrp = threshRsrp[3];
+ lteRssnr = 130;
+ lteSignalStrength = 12;
+ } else if (lteRsrp >= sSignalCust[2][2]) { // Good
+ lteRsrp = threshRsrp[2];
+ lteRssnr = 45;
+ lteSignalStrength = 8;
+ } else if (lteRsrp >= sSignalCust[2][1]) { // Moderate
+ lteRsrp = threshRsrp[1];
+ lteRssnr = 10;
+ lteSignalStrength = 5;
+ } else if (lteRsrp >= sSignalCust[2][0]) { // Poor
+ lteRsrp = threshRsrp[0];
+ lteRssnr = -30;
+ lteSignalStrength = 0;
+ } else { // None or Unknown
+ lteRsrp = -140;
+ lteRssnr = -200;
+ lteSignalStrength = 99;
+ }
+ break;
+ default:
+ lteRsrp = (gsmSignalStrength & 0xFF) - 256;
+ if (lteRsrp > -20) { // None or Unknown
+ lteRsrp = -43;
+ lteRssnr = 301;
+ lteSignalStrength = 99;
+ } else if (lteRsrp >= sSignalCust[0][3]) { // Great
+ lteRsrp = threshRsrp[3];
+ lteRssnr = 130;
+ lteSignalStrength = 12;
+ } else if (lteRsrp >= sSignalCust[0][2]) { // Good
+ lteRsrp = threshRsrp[2];
+ lteRssnr = 45;
+ lteSignalStrength = 8;
+ } else if (lteRsrp >= sSignalCust[0][1]) { // Moderate
+ lteRsrp = threshRsrp[1];
+ lteRssnr = 10;
+ lteSignalStrength = 5;
+ } else if (lteRsrp >= sSignalCust[0][0]) { // Poor
+ lteRsrp = threshRsrp[0];
+ lteRssnr = -30;
+ lteSignalStrength = 0;
+ } else { // None or Unknown
+ lteRsrp = -140;
+ lteRssnr = -200;
+ lteSignalStrength = 99;
+ }
+ }
+ }
+
+ return new SignalStrength(gsmSignalStrength,
+ gsmSignalStrength,
+ cdmaDbm,
+ cdmaEcio,
+ evdoDbm,
+ evdoEcio,
+ evdoSnr,
+ lteSignalStrength,
+ lteRsrp,
+ lteRsrq,
+ lteRssnr,
+ lteCqi,
+ tdscdmaRscp_1_2);
+ }
+
/** Convert HAL 1.0 Signal Strength to android SignalStrength */
@VisibleForTesting
public static SignalStrength convertHalSignalStrength(
- android.hardware.radio.V1_0.SignalStrength signalStrength) {
+ android.hardware.radio.V1_0.SignalStrength signalStrength, int phoneId) {
+ Boolean prop = android.os.SystemProperties.getBoolean("ro.telephony.isHisiRIL", false);
+
+ if (prop && phoneId >= 0) {
+ return convertHalSignalStrengthHuawei(signalStrength, phoneId);
+ }
+
int tdscdmaRscp_1_2 = 255; // 255 is the value for unknown/unreported ASU.
// The HAL 1.0 range is 25..120; the ASU/ HAL 1.2 range is 0..96;
// yes, this means the range in 1.0 cannot express -24dBm = 96
@@ -5531,6 +5762,11 @@
tdscdmaRscp_1_2);
}
+ static SignalStrength convertHalSignalStrength(
+ android.hardware.radio.V1_0.SignalStrength signalStrength) {
+ return convertHalSignalStrength(signalStrength, -1);
+ }
+
/** Convert HAL 1.2 Signal Strength to android SignalStrength */
@VisibleForTesting
public static SignalStrength convertHalSignalStrength_1_2(
@@ -5552,4 +5788,8 @@
signalStrength.wcdma.base.signalStrength,
signalStrength.wcdma.rscp);
}
+
+ public boolean needsOldRilFeature(String feature) {
+ return mOldRilFeatures.contains(feature);
+ }
}
diff --git a/src/java/com/android/internal/telephony/RadioIndication.java b/src/java/com/android/internal/telephony/RadioIndication.java
index f7a7943..49b526c 100644
--- a/src/java/com/android/internal/telephony/RadioIndication.java
+++ b/src/java/com/android/internal/telephony/RadioIndication.java
@@ -228,7 +228,7 @@
android.hardware.radio.V1_0.SignalStrength signalStrength) {
mRil.processIndication(indicationType);
- SignalStrength ss = RIL.convertHalSignalStrength(signalStrength);
+ SignalStrength ss = RIL.convertHalSignalStrength(signalStrength, mRil.mPhoneId);
// Note this is set to "verbose" because it happens frequently
if (RIL.RILJ_LOGV) mRil.unsljLogvRet(RIL_UNSOL_SIGNAL_STRENGTH, ss);
diff --git a/src/java/com/android/internal/telephony/RadioResponse.java b/src/java/com/android/internal/telephony/RadioResponse.java
index e790ab6..5201f8b 100644
--- a/src/java/com/android/internal/telephony/RadioResponse.java
+++ b/src/java/com/android/internal/telephony/RadioResponse.java
@@ -1694,7 +1694,7 @@
RILRequest rr = mRil.processResponse(responseInfo);
if (rr != null) {
- SignalStrength ret = RIL.convertHalSignalStrength(signalStrength);
+ SignalStrength ret = RIL.convertHalSignalStrength(signalStrength, mRil.mPhoneId);
if (responseInfo.error == RadioError.NONE) {
sendMessageResponse(rr.mResult, ret);
}
diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java
index 04241c8..6355627 100644
--- a/src/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -146,7 +146,7 @@
* expected responses in this pollingContext.
*/
@VisibleForTesting
- public int[] mPollingContext;
+ protected int[] mPollingContext;
private boolean mDesiredPowerState;
/**
@@ -287,7 +287,7 @@
int subId = mPhone.getSubId();
ServiceStateTracker.this.mPrevSubId = mPreviousSubId.get();
if (mPreviousSubId.getAndSet(subId) != subId) {
- if (SubscriptionManager.isValidSubscriptionId(subId)) {
+ if (mSubscriptionController.isActiveSubId(subId)) {
Context context = mPhone.getContext();
mPhone.notifyPhoneStateChanged();
@@ -346,7 +346,7 @@
};
//Common
- private final GsmCdmaPhone mPhone;
+ protected final GsmCdmaPhone mPhone;
public CellLocation mCellLoc;
private CellLocation mNewCellLoc;
@@ -1792,7 +1792,7 @@
return cdmaRoaming && !isSameOperatorNameFromSimAndSS(s);
}
- void handlePollStateResultMessage(int what, AsyncResult ar) {
+ protected void handlePollStateResultMessage(int what, AsyncResult ar) {
int ints[];
switch (what) {
case EVENT_POLL_STATE_REGISTRATION: {
diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java
index fd12273..2437a8d 100644
--- a/src/java/com/android/internal/telephony/SubscriptionController.java
+++ b/src/java/com/android/internal/telephony/SubscriptionController.java
@@ -85,8 +85,8 @@
*/
public class SubscriptionController extends ISub.Stub {
static final String LOG_TAG = "SubscriptionController";
- static final boolean DBG = true;
- static final boolean VDBG = false;
+ protected static final boolean DBG = true;
+ protected static final boolean VDBG = false;
static final boolean DBG_CACHE = false;
static final int MAX_LOCAL_LOG_LINES = 500; // TODO: Reduce to 100 when 17678050 is fixed
private static final int DEPRECATED_SETTING = -1;
@@ -147,7 +147,7 @@
protected final Object mLock = new Object();
/** The singleton instance. */
- private static SubscriptionController sInstance = null;
+ protected static SubscriptionController sInstance = null;
protected static Phone[] sPhones;
protected Context mContext;
protected TelephonyManager mTelephonyManager;
@@ -158,8 +158,8 @@
// FIXME: Does not allow for multiple subs in a slot and change to SparseArray
private static Map<Integer, Integer> sSlotIndexToSubId =
new ConcurrentHashMap<Integer, Integer>();
- private static int mDefaultFallbackSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
- private static int mDefaultPhoneId = SubscriptionManager.DEFAULT_PHONE_INDEX;
+ protected static int mDefaultFallbackSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ protected static int mDefaultPhoneId = SubscriptionManager.DEFAULT_PHONE_INDEX;
private int[] colorArr;
private long mLastISubServiceRegTime;
@@ -233,7 +233,7 @@
if (DBG) logdl("[SubscriptionController] init by Phone");
}
- private void enforceModifyPhoneState(String message) {
+ protected void enforceModifyPhoneState(String message) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.MODIFY_PHONE_STATE, message);
}
@@ -895,6 +895,19 @@
*/
@Override
public int addSubInfoRecord(String iccId, int slotIndex) {
+ String fullIccId;
+ Phone phone = PhoneFactory.getPhone(slotIndex);
+ UiccCard uiccCard = UiccController.getInstance().getUiccCardForSlot(slotIndex);
+ if (phone != null && uiccCard != null) {
+ fullIccId = phone.getFullIccSerialNumber();
+ if (TextUtils.isEmpty(fullIccId)) {
+ fullIccId = iccId;
+ }
+ } else {
+ if (DBG) logdl("[addSubInfoRecord]- null fullIccId");
+ return -1;
+ }
+
if (DBG) logdl("[addSubInfoRecord]+ iccId:" + SubscriptionInfo.givePrintableIccid(iccId) +
" slotIndex:" + slotIndex);
@@ -913,8 +926,10 @@
new String[]{SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID,
SubscriptionManager.SIM_SLOT_INDEX, SubscriptionManager.NAME_SOURCE,
SubscriptionManager.ICC_ID, SubscriptionManager.CARD_ID},
- SubscriptionManager.ICC_ID + "=?" + " OR " + SubscriptionManager.ICC_ID + "=?",
- new String[]{iccId, IccUtils.getDecimalSubstring(iccId)}, null);
+ SubscriptionManager.ICC_ID + "=?" + " OR " + SubscriptionManager.ICC_ID + "=?"
+ + " OR " + SubscriptionManager.ICC_ID + "=?" + " collate nocase",
+ new String[]{iccId, IccUtils.getDecimalSubstring(iccId), fullIccId},
+ null);
boolean setDisplayName = false;
try {
@@ -938,8 +953,9 @@
setDisplayName = true;
}
- if (oldIccId != null && oldIccId.length() < iccId.length()
- && (oldIccId.equals(IccUtils.getDecimalSubstring(iccId)))) {
+ if (oldIccId != null && oldIccId.length() != iccId.length()
+ && (oldIccId.equals(IccUtils.getDecimalSubstring(iccId))
+ || iccId.equalsIgnoreCase(IccUtils.stripTrailingFs(oldIccId)))) {
value.put(SubscriptionManager.ICC_ID, iccId);
}
@@ -955,9 +971,6 @@
resolver.update(SubscriptionManager.CONTENT_URI, value,
SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID +
"=" + Long.toString(subId), null);
-
- // Refresh the Cache of Active Subscription Info List
- refreshCachedActiveSubscriptionInfoList();
}
if (DBG) logdl("[addSubInfoRecord] Record already exists");
@@ -1000,7 +1013,7 @@
// Set the default sub if not set or if single sim device
if (!SubscriptionManager.isValidSubscriptionId(defaultSubId)
- || subIdCountMax == 1) {
+ || (subIdCountMax == 1) || (!isActiveSubId(defaultSubId))) {
setDefaultFallbackSubId(subId);
}
// If single sim device, set this subscription as the default for everything
@@ -1051,12 +1064,12 @@
SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID +
"=" + Long.toString(subId), null);
- // Refresh the Cache of Active Subscription Info List
- refreshCachedActiveSubscriptionInfoList();
-
if (DBG) logdl("[addSubInfoRecord] sim name = " + nameToSet);
}
+ // Refresh the Cache of Active Subscription Info List
+ refreshCachedActiveSubscriptionInfoList();
+
// Once the records are loaded, notify DcTracker
sPhones[slotIndex].updateDataConnectionTracker();
@@ -1100,9 +1113,6 @@
Uri uri = resolver.insert(SubscriptionManager.CONTENT_URI, value);
- // Refresh the Cache of Active Subscription Info List
- refreshCachedActiveSubscriptionInfoList();
-
return uri;
}
@@ -1536,7 +1546,7 @@
}
- private int[] getDummySubIds(int slotIndex) {
+ protected int[] getDummySubIds(int slotIndex) {
// FIXME: Remove notion of Dummy SUBSCRIPTION_ID.
// I tested this returning null as no one appears to care,
// but no connection came up on sprout with two sims.
@@ -1582,21 +1592,21 @@
}
}
- private void logvl(String msg) {
+ protected void logvl(String msg) {
logv(msg);
mLocalLog.log(msg);
}
- private void logv(String msg) {
+ protected void logv(String msg) {
Rlog.v(LOG_TAG, msg);
}
- private void logdl(String msg) {
+ protected void logdl(String msg) {
logd(msg);
mLocalLog.log(msg);
}
- private static void slogd(String msg) {
+ protected static void slogd(String msg) {
Rlog.d(LOG_TAG, msg);
}
@@ -1604,7 +1614,7 @@
Rlog.d(LOG_TAG, msg);
}
- private void logel(String msg) {
+ protected void logel(String msg) {
loge(msg);
mLocalLog.log(msg);
}
@@ -1758,7 +1768,7 @@
broadcastDefaultDataSubIdChanged(subId);
}
- private void updateAllDataConnectionTrackers() {
+ protected void updateAllDataConnectionTrackers() {
// Tell Phone Proxies to update data connection tracker
int len = sPhones.length;
if (DBG) logdl("[updateAllDataConnectionTrackers] sPhones.length=" + len);
@@ -1768,7 +1778,7 @@
}
}
- private void broadcastDefaultDataSubIdChanged(int subId) {
+ protected void broadcastDefaultDataSubIdChanged(int subId) {
// Broadcast an Intent for default data sub change
if (DBG) logdl("[broadcastDefaultDataSubIdChanged] subId=" + subId);
Intent intent = new Intent(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
@@ -1782,7 +1792,7 @@
* sub is set as default subId. If two or more sub's are active
* the first sub is set as default subscription
*/
- private void setDefaultFallbackSubId(int subId) {
+ protected void setDefaultFallbackSubId(int subId) {
if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
throw new RuntimeException("setDefaultSubId called with DEFAULT_SUB_ID");
}
@@ -1843,7 +1853,7 @@
}
}
- private boolean shouldDefaultBeCleared(List<SubscriptionInfo> records, int subId) {
+ protected boolean shouldDefaultBeCleared(List<SubscriptionInfo> records, int subId) {
if (DBG) logdl("[shouldDefaultBeCleared: subId] " + subId);
if (records == null) {
if (DBG) logdl("[shouldDefaultBeCleared] return true no records subId=" + subId);
@@ -2116,7 +2126,7 @@
return resultValue;
}
- private static void printStackTrace(String msg) {
+ protected static void printStackTrace(String msg) {
RuntimeException re = new RuntimeException();
slogd("StackTrace - " + msg);
StackTraceElement[] st = re.getStackTrace();
diff --git a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
index 1a4ed5b..4a40a9a 100644
--- a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
+++ b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
@@ -53,6 +53,7 @@
import com.android.internal.telephony.euicc.EuiccController;
import com.android.internal.telephony.uicc.IccRecords;
import com.android.internal.telephony.uicc.IccUtils;
+import com.android.internal.os.BackgroundThread;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -108,7 +109,7 @@
private static Phone[] mPhone;
private static Context mContext = null;
- private static String mIccId[] = new String[PROJECT_SIM_NUM];
+ protected static String mIccId[] = new String[PROJECT_SIM_NUM];
private static int[] mInsertSimState = new int[PROJECT_SIM_NUM];
private static int[] sSimCardState = new int[PROJECT_SIM_NUM];
private static int[] sSimApplicationState = new int[PROJECT_SIM_NUM];
@@ -142,6 +143,11 @@
initializeCarrierApps();
}
+ public SubscriptionInfoUpdater(Context context, Phone[] phone, CommandsInterface[] ci) {
+ this(BackgroundThread.get().getLooper(), context, phone, ci);
+
+ }
+
private void initializeCarrierApps() {
// Initialize carrier apps:
// -Now (on system startup)
@@ -201,7 +207,7 @@
}
}
- private boolean isAllIccIdQueryDone() {
+ protected boolean isAllIccIdQueryDone() {
for (int i = 0; i < PROJECT_SIM_NUM; i++) {
if (mIccId[i] == null) {
logd("Wait for SIM" + (i + 1) + " IccId");
@@ -302,7 +308,7 @@
sendMessage(obtainMessage(EVENT_REFRESH_EMBEDDED_SUBSCRIPTIONS, callback));
}
- private void handleSimLocked(int slotId, String reason) {
+ protected void handleSimLocked(int slotId, String reason) {
if (mIccId[slotId] != null && mIccId[slotId].equals(ICCID_STRING_FOR_NO_SIM)) {
logd("SIM" + (slotId + 1) + " hot plug in");
mIccId[slotId] = null;
@@ -355,7 +361,7 @@
}
}
- private void handleSimLoaded(int slotId) {
+ protected void handleSimLoaded(int slotId) {
logd("handleSimLoaded: slotId: " + slotId);
// The SIM should be loaded at this state, but it is possible in cases such as SIM being
@@ -382,12 +388,10 @@
updateSubscriptionInfoByIccId();
int[] subIds = mSubscriptionManager.getActiveSubscriptionIdList();
for (int subId : subIds) {
- TelephonyManager tm = TelephonyManager.getDefault();
-
- String operator = tm.getSimOperatorNumeric(subId);
slotId = SubscriptionController.getInstance().getPhoneId(subId);
+ String operator = mPhone[slotId].getOperatorNumeric();
- if (!TextUtils.isEmpty(operator)) {
+ if (operator != null && !TextUtils.isEmpty(operator)) {
if (subId == SubscriptionController.getInstance().getDefaultSubId()) {
MccTable.updateMccMncConfiguration(mContext, operator, false);
}
@@ -396,6 +400,7 @@
logd("EVENT_RECORDS_LOADED Operator name is null");
}
+ TelephonyManager tm = TelephonyManager.getDefault();
String msisdn = tm.getLine1Number(subId);
ContentResolver contentResolver = mContext.getContentResolver();
@@ -480,9 +485,9 @@
mCarrierServiceBindHelper.updateForPhoneId(slotId, simState);
}
- private void handleSimAbsent(int slotId) {
+ protected void handleSimAbsent(int slotId) {
if (mIccId[slotId] != null && !mIccId[slotId].equals(ICCID_STRING_FOR_NO_SIM)) {
- logd("SIM" + (slotId + 1) + " hot plug out");
+ logd("SIM" + (slotId + 1) + " hot plug out or error.");
}
mIccId[slotId] = ICCID_STRING_FOR_NO_SIM;
if (isAllIccIdQueryDone()) {
@@ -494,7 +499,7 @@
broadcastSimApplicationStateChanged(slotId, TelephonyManager.SIM_STATE_NOT_READY);
}
- private void handleSimError(int slotId) {
+ protected void handleSimError(int slotId) {
if (mIccId[slotId] != null && !mIccId[slotId].equals(ICCID_STRING_FOR_NO_SIM)) {
logd("SIM" + (slotId + 1) + " Error ");
}
@@ -513,7 +518,7 @@
* TODO: Simplify more, as no one is interested in what happened
* only what the current list contains.
*/
- synchronized private void updateSubscriptionInfoByIccId() {
+ synchronized protected void updateSubscriptionInfoByIccId() {
logd("updateSubscriptionInfoByIccId:+ Start");
for (int i = 0; i < PROJECT_SIM_NUM; i++) {
diff --git a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
index 8ad5720..4fc5ea8 100644
--- a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
+++ b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
@@ -23,6 +23,7 @@
import android.os.Looper;
import android.os.ServiceManager;
import android.telephony.AccessNetworkConstants.TransportType;
+import android.telephony.Rlog;
import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
import com.android.internal.telephony.cdma.EriManager;
@@ -30,9 +31,16 @@
import com.android.internal.telephony.imsphone.ImsExternalCallTracker;
import com.android.internal.telephony.imsphone.ImsPhone;
import com.android.internal.telephony.imsphone.ImsPhoneCallTracker;
+import com.android.internal.telephony.SubscriptionController;
import com.android.internal.telephony.uicc.IccCardStatus;
import com.android.internal.telephony.uicc.UiccCard;
import com.android.internal.telephony.uicc.UiccProfile;
+import com.android.internal.os.BackgroundThread;
+
+
+import dalvik.system.PathClassLoader;
+
+import java.lang.reflect.Constructor;
/**
* This class has one-line methods to instantiate objects only. The purpose is to make code
@@ -40,28 +48,49 @@
* this way makes it easier to mock them in tests.
*/
public class TelephonyComponentFactory {
+ protected static String LOG_TAG = "TelephonyComponentFactory";
private static TelephonyComponentFactory sInstance;
public static TelephonyComponentFactory getInstance() {
if (sInstance == null) {
- sInstance = new TelephonyComponentFactory();
+ String fullClsName = "com.qualcomm.qti.internal.telephony.QtiTelephonyComponentFactory";
+ String libPath = "/system/framework/qti-telephony-common.jar";
+
+ try {
+ PathClassLoader classLoader = new PathClassLoader(libPath,
+ ClassLoader.getSystemClassLoader());
+ Class<?> cls = Class.forName(fullClsName, false, classLoader);
+ Constructor custMethod = cls.getConstructor();
+ sInstance = (TelephonyComponentFactory) custMethod.newInstance();
+ Rlog.i(LOG_TAG, "Using QtiTelephonyComponentFactory");
+ } catch (NoClassDefFoundError | ClassNotFoundException e) {
+ Rlog.e(LOG_TAG, "QtiTelephonyComponentFactory not used - fallback to default");
+ sInstance = new TelephonyComponentFactory();
+ } catch (Exception e) {
+ Rlog.e(LOG_TAG, "Error loading QtiTelephonyComponentFactory - fallback to default");
+ sInstance = new TelephonyComponentFactory();
+ }
}
return sInstance;
}
public GsmCdmaCallTracker makeGsmCdmaCallTracker(GsmCdmaPhone phone) {
+ Rlog.d(LOG_TAG, "makeGsmCdmaCallTracker");
return new GsmCdmaCallTracker(phone);
}
public SmsStorageMonitor makeSmsStorageMonitor(Phone phone) {
+ Rlog.d(LOG_TAG, "makeSmsStorageMonitor");
return new SmsStorageMonitor(phone);
}
public SmsUsageMonitor makeSmsUsageMonitor(Context context) {
+ Rlog.d(LOG_TAG, "makeSmsUsageMonitor");
return new SmsUsageMonitor(context);
}
public ServiceStateTracker makeServiceStateTracker(GsmCdmaPhone phone, CommandsInterface ci) {
+ Rlog.d(LOG_TAG, "makeServiceStateTracker");
return new ServiceStateTracker(phone, ci);
}
@@ -77,6 +106,7 @@
}
public DcTracker makeDcTracker(Phone phone) {
+ Rlog.d(LOG_TAG, "makeDcTracker");
return new DcTracker(phone, TransportType.WWAN);
}
@@ -93,10 +123,12 @@
}
public IccPhoneBookInterfaceManager makeIccPhoneBookInterfaceManager(Phone phone) {
+ Rlog.d(LOG_TAG, "makeIccPhoneBookInterfaceManager");
return new IccPhoneBookInterfaceManager(phone);
}
public IccSmsInterfaceManager makeIccSmsInterfaceManager(Phone phone) {
+ Rlog.d(LOG_TAG, "makeIccSmsInterfaceManager");
return new IccSmsInterfaceManager(phone);
}
@@ -109,10 +141,12 @@
}
public EriManager makeEriManager(Phone phone, Context context, int eriFileSource) {
+ Rlog.d(LOG_TAG, "makeEriManager");
return new EriManager(phone, context, eriFileSource);
}
public WspTypeDecoder makeWspTypeDecoder(byte[] pdu) {
+ Rlog.d(LOG_TAG, "makeWspTypeDecoder");
return new WspTypeDecoder(pdu);
}
@@ -122,6 +156,7 @@
public InboundSmsTracker makeInboundSmsTracker(byte[] pdu, long timestamp, int destPort,
boolean is3gpp2, boolean is3gpp2WapPdu, String address, String displayAddr,
String messageBody) {
+ Rlog.d(LOG_TAG, "makeInboundSmsTracker");
return new InboundSmsTracker(pdu, timestamp, destPort, is3gpp2, is3gpp2WapPdu, address,
displayAddr, messageBody);
}
@@ -132,6 +167,7 @@
public InboundSmsTracker makeInboundSmsTracker(byte[] pdu, long timestamp, int destPort,
boolean is3gpp2, String address, String displayAddr, int referenceNumber, int sequenceNumber,
int messageCount, boolean is3gpp2WapPdu, String messageBody) {
+ Rlog.d(LOG_TAG, "makeInboundSmsTracker");
return new InboundSmsTracker(pdu, timestamp, destPort, is3gpp2, address, displayAddr,
referenceNumber, sequenceNumber, messageCount, is3gpp2WapPdu, messageBody);
}
@@ -140,10 +176,12 @@
* Create a tracker from a row of raw table
*/
public InboundSmsTracker makeInboundSmsTracker(Cursor cursor, boolean isCurrentFormat3gpp2) {
+ Rlog.d(LOG_TAG, "makeInboundSmsTracker");
return new InboundSmsTracker(cursor, isCurrentFormat3gpp2);
}
public ImsPhoneCallTracker makeImsPhoneCallTracker(ImsPhone imsPhone) {
+ Rlog.d(LOG_TAG, "makeImsPhoneCallTracker");
return new ImsPhoneCallTracker(imsPhone);
}
@@ -166,14 +204,61 @@
public CdmaSubscriptionSourceManager
getCdmaSubscriptionSourceManagerInstance(Context context, CommandsInterface ci, Handler h,
int what, Object obj) {
+ Rlog.d(LOG_TAG, "getCdmaSubscriptionSourceManagerInstance");
return CdmaSubscriptionSourceManager.getInstance(context, ci, h, what, obj);
}
public IDeviceIdleController getIDeviceIdleController() {
+ Rlog.d(LOG_TAG, "getIDeviceIdleController");
return IDeviceIdleController.Stub.asInterface(
ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
}
+ public Phone makePhone(Context context, CommandsInterface ci, PhoneNotifier notifier,
+ int phoneId, int precisePhoneType,
+ TelephonyComponentFactory telephonyComponentFactory) {
+ Rlog.d(LOG_TAG, "makePhone");
+ return new GsmCdmaPhone(context, ci, notifier, phoneId, precisePhoneType,
+ telephonyComponentFactory);
+ }
+
+ public SubscriptionController initSubscriptionController(Context c, CommandsInterface[] ci) {
+ Rlog.d(LOG_TAG, "initSubscriptionController");
+ return SubscriptionController.init(c, ci);
+ }
+
+ public SubscriptionInfoUpdater makeSubscriptionInfoUpdater(Context context,
+ Phone[] phones, CommandsInterface[] ci) {
+ Rlog.d(LOG_TAG, "makeSubscriptionInfoUpdater");
+ return new SubscriptionInfoUpdater(BackgroundThread.get().getLooper(), context, phones, ci);
+ }
+
+ public SubscriptionInfoUpdater makeSubscriptionInfoUpdater(Looper looper, Context context,
+ Phone[] phones, CommandsInterface[] ci) {
+ Rlog.d(LOG_TAG, "makeSubscriptionInfoUpdater");
+ return new SubscriptionInfoUpdater(looper, context, phones, ci);
+ }
+
+ public void makeExtTelephonyClasses(Context context,
+ Phone[] phones, CommandsInterface[] commandsInterfaces) {
+ Rlog.d(LOG_TAG, "makeExtTelephonyClasses");
+ }
+
+ public PhoneSwitcher makePhoneSwitcher(int maxActivePhones, int numPhones, Context context,
+ SubscriptionController subscriptionController, Looper looper, ITelephonyRegistry tr,
+ CommandsInterface[] cis, Phone[] phones) {
+ Rlog.d(LOG_TAG, "makePhoneSwitcher");
+ return new PhoneSwitcher(maxActivePhones,numPhones,
+ context, subscriptionController, looper, tr, cis,
+ phones);
+ }
+
+ public RIL makeRIL(Context context, int preferredNetworkType,
+ int cdmaSubscription, Integer instanceId) {
+ Rlog.d(LOG_TAG, "makeRIL");
+ return new RIL(context, preferredNetworkType, cdmaSubscription, instanceId);
+ }
+
public LocaleTracker makeLocaleTracker(Phone phone, Looper looper) {
return new LocaleTracker(phone, looper);
}
diff --git a/src/java/com/android/internal/telephony/UiccPhoneBookController.java b/src/java/com/android/internal/telephony/UiccPhoneBookController.java
index f3019f0..40a2f49 100644
--- a/src/java/com/android/internal/telephony/UiccPhoneBookController.java
+++ b/src/java/com/android/internal/telephony/UiccPhoneBookController.java
@@ -18,6 +18,7 @@
package com.android.internal.telephony;
+import android.content.ContentValues;
import android.os.ServiceManager;
import android.telephony.Rlog;
@@ -53,14 +54,13 @@
updateAdnRecordsInEfBySearchForSubscriber(int subId, int efid, String oldTag,
String oldPhoneNumber, String newTag, String newPhoneNumber,
String pin2) throws android.os.RemoteException {
- IccPhoneBookInterfaceManager iccPbkIntMgr =
- getIccPhoneBookInterfaceManager(subId);
+ IccPhoneBookInterfaceManager iccPbkIntMgr = getIccPhoneBookInterfaceManager(subId);
if (iccPbkIntMgr != null) {
return iccPbkIntMgr.updateAdnRecordsInEfBySearch(efid, oldTag,
oldPhoneNumber, newTag, newPhoneNumber, pin2);
} else {
Rlog.e(TAG,"updateAdnRecordsInEfBySearch iccPbkIntMgr is" +
- " null for Subscription:"+subId);
+ " null for Subscription:" + subId);
return false;
}
}
@@ -77,14 +77,13 @@
public boolean
updateAdnRecordsInEfByIndexForSubscriber(int subId, int efid, String newTag,
String newPhoneNumber, int index, String pin2) throws android.os.RemoteException {
- IccPhoneBookInterfaceManager iccPbkIntMgr =
- getIccPhoneBookInterfaceManager(subId);
+ IccPhoneBookInterfaceManager iccPbkIntMgr = getIccPhoneBookInterfaceManager(subId);
if (iccPbkIntMgr != null) {
return iccPbkIntMgr.updateAdnRecordsInEfByIndex(efid, newTag,
newPhoneNumber, index, pin2);
} else {
Rlog.e(TAG,"updateAdnRecordsInEfByIndex iccPbkIntMgr is" +
- " null for Subscription:"+subId);
+ " null for Subscription:" + subId);
return false;
}
}
@@ -127,6 +126,48 @@
}
}
+ @Override
+ public int[] getAdnRecordsCapacity() throws android.os.RemoteException {
+ return getAdnRecordsCapacityForSubscriber(getDefaultSubscription());
+ }
+
+ @Override
+ public int[] getAdnRecordsCapacityForSubscriber(int subId)
+ throws android.os.RemoteException {
+ IccPhoneBookInterfaceManager iccPbkIntMgr =
+ getIccPhoneBookInterfaceManager(subId);
+ if (iccPbkIntMgr != null) {
+ return iccPbkIntMgr.getAdnRecordsCapacity();
+ } else {
+ Rlog.e(TAG,"getAdnRecordsCapacity iccPbkIntMgr is" +
+ " null for Subscription:"+subId);
+ return null;
+ }
+ }
+
+ public boolean
+ updateAdnRecordsWithContentValuesInEfBySearch(int efid, ContentValues values,
+ String pin2) throws android.os.RemoteException {
+ return updateAdnRecordsWithContentValuesInEfBySearchUsingSubId(
+ getDefaultSubscription(), efid, values, pin2);
+ }
+
+ public boolean
+ updateAdnRecordsWithContentValuesInEfBySearchUsingSubId(int subId, int efid,
+ ContentValues values, String pin2)
+ throws android.os.RemoteException {
+ IccPhoneBookInterfaceManager iccPbkIntMgr =
+ getIccPhoneBookInterfaceManager(subId);
+ if (iccPbkIntMgr != null) {
+ return iccPbkIntMgr.updateAdnRecordsWithContentValuesInEfBySearch(
+ efid, values, pin2);
+ } else {
+ Rlog.e(TAG,"updateAdnRecordsWithContentValuesInEfBySearchUsingSubId " +
+ "iccPbkIntMgr is null for Subscription:"+subId);
+ return false;
+ }
+ }
+
/**
* get phone book interface manager object based on subscription.
**/
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
index ea6fa81..4b7fb49 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
@@ -75,7 +75,8 @@
import android.util.Pair;
import android.util.SparseArray;
import android.view.WindowManager;
-
+import com.android.internal.R;
+import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.CarrierActionAgent;
import com.android.internal.telephony.DctConstants;
@@ -113,8 +114,8 @@
* {@hide}
*/
public class DcTracker extends Handler {
- private static final String LOG_TAG = "DCT";
- private static final boolean DBG = true;
+ protected String LOG_TAG = "DCT";
+ protected static final boolean DBG = true;
private static final boolean VDBG = false; // STOPSHIP if true
private static final boolean VDBG_STALL = false; // STOPSHIP if true
private static final boolean RADIO_TESTS = false;
@@ -174,10 +175,10 @@
} );
/** allApns holds all apns */
- private ArrayList<ApnSetting> mAllApnSettings = null;
+ protected ArrayList<ApnSetting> mAllApnSettings = null;
/** preferred apn */
- private ApnSetting mPreferredApn = null;
+ protected ApnSetting mPreferredApn = null;
/** Is packet service restricted by network */
private boolean mIsPsRestricted = false;
@@ -186,7 +187,7 @@
private ApnSetting mEmergencyApn = null;
/* Once disposed dont handle any messages */
- private boolean mIsDisposed = false;
+ protected boolean mIsDisposed = false;
private ContentResolver mResolver;
@@ -292,11 +293,11 @@
if (DBG) log("SubscriptionListener.onSubscriptionInfoChanged");
// Set the network type, in case the radio does not restore it.
int subId = mPhone.getSubId();
- if (SubscriptionManager.isValidSubscriptionId(subId)) {
+ if (mSubscriptionManager.isActiveSubId(subId)) {
registerSettingsObserver();
}
if (mPreviousSubId.getAndSet(subId) != subId &&
- SubscriptionManager.isValidSubscriptionId(subId)) {
+ mSubscriptionManager.isActiveSubId(subId)) {
onRecordsLoadedOrSubIdChanged();
}
}
@@ -390,7 +391,7 @@
// Stop reconnect if not current subId is not correct.
// FIXME STOPSHIP - phoneSubId is coming up as -1 way after boot and failing this?
- if (!SubscriptionManager.isValidSubscriptionId(currSubId) || (currSubId != phoneSubId)) {
+ if (!mSubscriptionManager.isActiveSubId(currSubId) || (currSubId != phoneSubId)) {
log("receive ReconnectAlarm but subId incorrect, ignore");
return;
}
@@ -452,11 +453,11 @@
private RegistrantList mAllDataDisconnectedRegistrants = new RegistrantList();
// member variables
- private final Phone mPhone;
+ protected final Phone mPhone;
private final UiccController mUiccController;
- private final AtomicReference<IccRecords> mIccRecords = new AtomicReference<IccRecords>();
+ protected final AtomicReference<IccRecords> mIccRecords = new AtomicReference<IccRecords>();
private DctConstants.Activity mActivity = DctConstants.Activity.NONE;
- private DctConstants.State mState = DctConstants.State.IDLE;
+ protected DctConstants.State mState = DctConstants.State.IDLE;
private final Handler mDataConnectionTracker;
private long mTxPkts;
@@ -487,8 +488,8 @@
private PendingIntent mReconnectIntent = null;
// When false we will not auto attach and manually attaching is required.
- private boolean mAutoAttachOnCreationConfig = false;
- private AtomicBoolean mAutoAttachOnCreation = new AtomicBoolean(false);
+ protected boolean mAutoAttachOnCreationConfig = false;
+ protected AtomicBoolean mAutoAttachOnCreation = new AtomicBoolean(false);
// State of screen
// (TODO: Reconsider tying directly to screen, maybe this is
@@ -497,7 +498,7 @@
// Indicates if we found mvno-specific APNs in the full APN list.
// used to determine if we can accept mno-specific APN for tethering.
- private boolean mMvnoMatched = false;
+ protected boolean mMvnoMatched = false;
/** Allows the generation of unique Id's for DataConnection objects */
private AtomicInteger mUniqueIdGenerator = new AtomicInteger(0);
@@ -582,6 +583,10 @@
private final int mTransportType;
+ public DcTracker(Phone phone) {
+ this(phone, TransportType.WWAN);
+ }
+
//***** Constructor
public DcTracker(Phone phone, int transportType) {
super();
@@ -1230,6 +1235,15 @@
setupDataOnConnectableApns(Phone.REASON_DATA_ATTACHED);
}
+ protected boolean getAttachedStatus() {
+ return mAttached.get();
+ }
+
+ protected boolean isNvSubscription() {
+ int cdmaSubscriptionSource = CdmaSubscriptionSourceManager.getDefault(mPhone.getContext());
+ return cdmaSubscriptionSource == CdmaSubscriptionSourceManager.SUBSCRIPTION_FROM_NV;
+ }
+
/**
* Check if it is allowed to make a data connection (without checking APN context specific
* conditions).
@@ -1263,7 +1277,7 @@
// Step 1: Get all environment conditions.
final boolean internalDataEnabled = mDataEnabledSettings.isInternalDataEnabled();
- boolean attachedState = mAttached.get();
+ boolean attachedState = getAttachedStatus();
boolean desiredPowerState = mPhone.getServiceStateTracker().getDesiredPowerState();
boolean radioStateFromCarrier = mPhone.getServiceStateTracker().getPowerStateFromCarrier();
// TODO: Remove this hack added by ag/641832.
@@ -1326,7 +1340,7 @@
if (!(attachedState || mAutoAttachOnCreation.get())) {
reasons.add(DataDisallowedReasonType.NOT_ATTACHED);
}
- if (!recordsLoaded) {
+ if (!(recordsLoaded || isNvSubscription())) {
reasons.add(DataDisallowedReasonType.RECORD_NOT_LOADED);
}
if (phoneState != PhoneConstants.State.IDLE
@@ -1406,11 +1420,11 @@
ONLY_ON_CHANGE
};
- private void setupDataOnConnectableApns(String reason) {
+ protected void setupDataOnConnectableApns(String reason) {
setupDataOnConnectableApns(reason, RetryFailures.ALWAYS);
}
- private void setupDataOnConnectableApns(String reason, RetryFailures retryFailures) {
+ protected void setupDataOnConnectableApns(String reason, RetryFailures retryFailures) {
if (VDBG) log("setupDataOnConnectableApns: " + reason);
if (DBG && !VDBG) {
@@ -1538,7 +1552,7 @@
}
// Disabled apn's still need avail/unavail notifications - send them out
- private void notifyOffApnsOfAvailability(String reason) {
+ protected void notifyOffApnsOfAvailability(String reason) {
for (ApnContext apnContext : mApnContexts.values()) {
if (!mAttached.get() || !apnContext.isReady()) {
if (VDBG) log("notifyOffApnOfAvailability type:" + apnContext.getApnType());
@@ -1565,7 +1579,7 @@
* @return boolean - true if we did cleanup any connections, false if they
* were already all disconnected.
*/
- private boolean cleanUpAllConnections(boolean tearDown, String reason) {
+ protected boolean cleanUpAllConnections(boolean tearDown, String reason) {
if (DBG) log("cleanUpAllConnections: tearDown=" + tearDown + " reason=" + reason);
boolean didDisconnect = false;
boolean disableMeteredOnly = false;
@@ -1639,7 +1653,7 @@
sendMessage(msg);
}
- private void cleanUpConnection(boolean tearDown, ApnContext apnContext) {
+ protected void cleanUpConnection(boolean tearDown, ApnContext apnContext) {
if (apnContext == null) {
if (DBG) log("cleanUpConnection: apn context is null");
return;
@@ -1739,7 +1753,7 @@
}
int bearer = mPhone.getServiceState().getRilDataRadioTechnology();
IccRecords r = mIccRecords.get();
- String operator = (r != null) ? r.getOperatorNumeric() : "";
+ String operator = mPhone.getOperatorNumeric();
ArrayList<ApnSetting> dunCandidates = new ArrayList<ApnSetting>();
ArrayList<ApnSetting> retDunSettings = new ArrayList<ApnSetting>();
@@ -1900,7 +1914,7 @@
return apn;
}
- private ArrayList<ApnSetting> createApnList(Cursor cursor) {
+ protected ArrayList<ApnSetting> createApnList(Cursor cursor) {
ArrayList<ApnSetting> mnoApns = new ArrayList<ApnSetting>();
ArrayList<ApnSetting> mvnoApns = new ArrayList<ApnSetting>();
IccRecords r = mIccRecords.get();
@@ -2065,7 +2079,7 @@
return true;
}
- private void setInitialAttachApn() {
+ protected void setInitialAttachApn() {
ApnSetting iaApnSetting = null;
ApnSetting defaultApnSetting = null;
ApnSetting firstApnSetting = null;
@@ -2094,6 +2108,11 @@
}
}
+ if ((iaApnSetting == null) && (defaultApnSetting == null) &&
+ !allowInitialAttachForOperator()) {
+ log("Abort Initial attach");
+ return;
+ }
// The priority of apn candidates from highest to lowest is:
// 1) APN_TYPE_IA (Initial Attach)
// 2) mPreferredApn, i.e. the current preferred apn
@@ -2125,6 +2144,10 @@
}
}
+ protected boolean allowInitialAttachForOperator() {
+ return true;
+ }
+
/**
* Handles changes to the APN database.
*/
@@ -2305,7 +2328,7 @@
return mAutoAttachOnCreation.get();
}
- private void onRecordsLoadedOrSubIdChanged() {
+ protected void onRecordsLoadedOrSubIdChanged() {
if (DBG) log("onRecordsLoadedOrSubIdChanged: createAllApnList");
mAutoAttachOnCreationConfig = mPhone.getContext().getResources()
.getBoolean(com.android.internal.R.bool.config_auto_attach_data_on_creation);
@@ -3307,7 +3330,7 @@
notifyOffApnsOfAvailability(reason);
}
- private void setDataProfilesAsNeeded() {
+ protected void setDataProfilesAsNeeded() {
if (DBG) log("setDataProfilesAsNeeded");
if (mAllApnSettings != null && !mAllApnSettings.isEmpty()) {
ArrayList<DataProfile> dps = new ArrayList<DataProfile>();
@@ -3330,11 +3353,11 @@
* Based on the sim operator numeric, create a list for all possible
* Data Connections and setup the preferredApn.
*/
- private void createAllApnList() {
+ protected void createAllApnList() {
mMvnoMatched = false;
mAllApnSettings = new ArrayList<>();
IccRecords r = mIccRecords.get();
- String operator = (r != null) ? r.getOperatorNumeric() : "";
+ String operator = mPhone.getOperatorNumeric();
if (operator != null) {
String selection = Telephony.Carriers.NUMERIC + " = '" + operator + "'";
// query only enabled apn.
@@ -3377,7 +3400,7 @@
setDataProfilesAsNeeded();
}
- private void dedupeApnSettings() {
+ protected void dedupeApnSettings() {
ArrayList<ApnSetting> resultApns = new ArrayList<ApnSetting>();
// coalesce APNs if they are similar enough to prevent
@@ -3486,8 +3509,7 @@
}
}
- IccRecords r = mIccRecords.get();
- String operator = (r != null) ? r.getOperatorNumeric() : "";
+ String operator = mPhone.getOperatorNumeric();
// This is a workaround for a bug (7305641) where we don't failover to other
// suitable APNs if our preferred APN fails. On prepaid ATT sims we need to
@@ -3510,7 +3532,7 @@
+ " canSetPreferApn=" + mCanSetPreferApn
+ " mPreferredApn=" + mPreferredApn
+ " operator=" + operator + " radioTech=" + radioTech
- + " IccRecords r=" + r);
+ + " IccRecords r=" + mIccRecords);
}
if (usePreferred && mCanSetPreferApn && mPreferredApn != null &&
@@ -3605,7 +3627,7 @@
return result.toString();
}
- private void setPreferredApn(int pos) {
+ protected void setPreferredApn(int pos) {
if (!mCanSetPreferApn) {
log("setPreferredApn: X !canSEtPreferApn");
return;
@@ -3625,7 +3647,7 @@
}
}
- private ApnSetting getPreferredApn() {
+ protected ApnSetting getPreferredApn() {
if (mAllApnSettings == null || mAllApnSettings.isEmpty()) {
log("getPreferredApn: mAllApnSettings is " + ((mAllApnSettings == null)?"null":"empty"));
return null;
@@ -3676,7 +3698,7 @@
// If onRecordsLoadedOrSubIdChanged() is not called here, it should be called on
// onSubscriptionsChanged() when a valid subId is available.
int subId = mPhone.getSubId();
- if (SubscriptionManager.isValidSubscriptionId(subId)) {
+ if (mSubscriptionManager.isActiveSubId(subId)) {
onRecordsLoadedOrSubIdChanged();
} else {
log("Ignoring EVENT_RECORDS_LOADED as subId is not valid: " + subId);
@@ -4063,7 +4085,7 @@
return;
}
- IccRecords newIccRecords = getUiccRecords(UiccController.APP_FAM_3GPP);
+ IccRecords newIccRecords = mPhone.getIccRecords();
IccRecords r = mIccRecords.get();
if (r != newIccRecords) {
@@ -4073,7 +4095,7 @@
mIccRecords.set(null);
}
if (newIccRecords != null) {
- if (SubscriptionManager.isValidSubscriptionId(mPhone.getSubId())) {
+ if (mSubscriptionManager.isActiveSubId(mPhone.getSubId())) {
log("New records found.");
mIccRecords.set(newIccRecords);
newIccRecords.registerForRecordsLoaded(
@@ -4184,7 +4206,7 @@
return true;
}
- private void log(String s) {
+ protected void log(String s) {
Rlog.d(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s);
}
@@ -4355,7 +4377,7 @@
/**
* Add the Emergency APN settings to APN settings list
*/
- private void addEmergencyApnSetting() {
+ protected void addEmergencyApnSetting() {
if(mEmergencyApn != null) {
if(mAllApnSettings == null) {
mAllApnSettings = new ArrayList<ApnSetting>();
@@ -4394,7 +4416,7 @@
return true;
}
- private void cleanUpConnectionsOnUpdatedApns(boolean tearDown, String reason) {
+ protected void cleanUpConnectionsOnUpdatedApns(boolean tearDown, String reason) {
if (DBG) log("cleanUpConnectionsOnUpdatedApns: tearDown=" + tearDown);
if (mAllApnSettings != null && mAllApnSettings.isEmpty()) {
cleanUpAllConnections(tearDown, Phone.REASON_APN_CHANGED);
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
index 3333697..f789bf2 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
@@ -45,6 +45,7 @@
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.net.NetworkStats;
import android.net.Uri;
import android.os.AsyncResult;
@@ -70,8 +71,10 @@
import android.telephony.ims.ImsCallProfile;
import android.telephony.ims.ImsReasonInfo;
import android.telephony.ims.ImsSsInfo;
+import android.telephony.ims.ImsStreamMediaProfile;
import android.text.TextUtils;
+import com.android.ims.ImsCall;
import com.android.ims.ImsEcbm;
import com.android.ims.ImsEcbmStateListener;
import com.android.ims.ImsException;
@@ -98,6 +101,9 @@
import com.android.internal.telephony.uicc.IccRecords;
import com.android.internal.telephony.util.NotificationChannelController;
+import org.codeaurora.ims.QtiCallConstants;
+import org.codeaurora.ims.utils.QtiImsExtUtils;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -282,6 +288,14 @@
mDefaultPhone.registerForServiceStateChanged(this, EVENT_SERVICE_STATE_CHANGED, null);
// Force initial roaming state update later, on EVENT_CARRIER_CONFIG_CHANGED.
// Settings provider or CarrierConfig may not be loaded now.
+
+ // Register receiver for sending RTT text message and
+ // for receving RTT Operation
+ // .i.e.Upgrade Initiate, Upgrade accept, Upgrade reject
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(QtiCallConstants.ACTION_SEND_RTT_TEXT);
+ filter.addAction(QtiCallConstants.ACTION_RTT_OPERATION);
+ mDefaultPhone.getContext().registerReceiver(mRttReceiver, filter);
}
//todo: get rid of this function. It is not needed since parentPhone obj never changes
@@ -301,6 +315,7 @@
mDefaultPhone.getServiceStateTracker().
unregisterForDataRegStateOrRatChanged(this);
mDefaultPhone.unregisterForServiceStateChanged(this);
+ mDefaultPhone.getContext().unregisterReceiver(mRttReceiver);
}
}
@@ -1829,6 +1844,198 @@
return tm.isNetworkRoaming();
}
+ private BroadcastReceiver mRttReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (QtiCallConstants.ACTION_SEND_RTT_TEXT.equals(intent.getAction())) {
+ Rlog.d(LOG_TAG, "RTT: Received ACTION_SEND_RTT_TEXT");
+ String data = intent.getStringExtra(QtiCallConstants.RTT_TEXT_VALUE);
+ sendRttMessage(data);
+ } else if (QtiCallConstants.ACTION_RTT_OPERATION.equals(intent.getAction())) {
+ Rlog.d(LOG_TAG, "RTT: Received ACTION_RTT_OPERATION");
+ int data = intent.getIntExtra(QtiCallConstants.RTT_OPERATION_TYPE, 0);
+ checkIfModifyRequestOrResponse(data);
+ } else {
+ Rlog.d(LOG_TAG, "RTT: unknown intent");
+ }
+ }
+ };
+
+ /**
+ * Sends Rtt message
+ * Rtt Message can be sent only when -
+ * operating mode is RTT_FULL and for non-VT calls only based on config
+ *
+ * @param data The Rtt text to be sent
+ */
+ public void sendRttMessage(String data) {
+ if (!canProcessRttRequest() || !isFgCallActive()) {
+ return;
+ }
+
+ // Check for empty message
+ if (TextUtils.isEmpty(data)) {
+ Rlog.d(LOG_TAG, "RTT: Text null");
+ return;
+ }
+
+ ImsCall imsCall = getForegroundCall().getImsCall();
+ if (imsCall == null) {
+ Rlog.d(LOG_TAG, "RTT: imsCall null");
+ return;
+ }
+
+ if (!isRttVtCallAllowed(imsCall)) {
+ Rlog.d(LOG_TAG, "RTT: InCorrect mode");
+ return;
+ }
+
+ Rlog.d(LOG_TAG, "RTT: sendRttMessage");
+ imsCall.sendRttMessage(data);
+ }
+
+ /**
+ * Sends RTT Upgrade request
+ *
+ * @param to: expected profile
+ */
+ public void sendRttModifyRequest(ImsCallProfile to) {
+ Rlog.d(LOG_TAG, "RTT: sendRttModifyRequest");
+ ImsCall imsCall = getForegroundCall().getImsCall();
+ if (imsCall == null) {
+ Rlog.d(LOG_TAG, "RTT: imsCall null");
+ return;
+ }
+
+ imsCall.sendRttModifyRequest();
+ }
+
+ /**
+ * Sends RTT Upgrade response
+ *
+ * @param data : response for upgrade
+ */
+ public void sendRttModifyResponse(int response) {
+ ImsCall imsCall = getForegroundCall().getImsCall();
+ if (imsCall == null) {
+ Rlog.d(LOG_TAG, "RTT: imsCall null");
+ return;
+ }
+
+ if (!isRttVtCallAllowed(imsCall)) {
+ Rlog.d(LOG_TAG, "RTT: Not allowed for VT");
+ return;
+ }
+
+ Rlog.d(LOG_TAG, "RTT: sendRttModifyResponse");
+ imsCall.sendRttModifyResponse(mapRequestToResponse(response));
+ }
+
+ // Utility to check if the value coming in intent is for upgrade initiate or upgrade response
+ private void checkIfModifyRequestOrResponse(int data) {
+ if (!canProcessRttRequest() || !isFgCallActive()) {
+ return;
+ }
+
+ Rlog.d(LOG_TAG, "RTT: checkIfModifyRequestOrResponse data = " + data);
+ switch (data) {
+ case QtiCallConstants.RTT_UPGRADE_INITIATE:
+ // Rtt Upgrade means enable Rtt
+ packRttModifyRequestToProfile(ImsStreamMediaProfile.RTT_MODE_FULL);
+ break;
+ case QtiCallConstants.RTT_DOWNGRADE_INITIATE:
+ // Rtt downrade means disable Rtt
+ packRttModifyRequestToProfile(ImsStreamMediaProfile.RTT_MODE_DISABLED);
+ break;
+ case QtiCallConstants.RTT_UPGRADE_CONFIRM:
+ case QtiCallConstants.RTT_UPGRADE_REJECT:
+ sendRttModifyResponse(data);
+ break;
+ }
+ }
+
+ private void packRttModifyRequestToProfile(int data) {
+ if (!canSendRttModifyRequest()) {
+ Rlog.d(LOG_TAG, "RTT: cannot send rtt modify request");
+ return;
+ }
+
+ ImsCallProfile fromProfile = getForegroundCall().getImsCall().getCallProfile();
+ ImsCallProfile toProfile = fromProfile;
+ toProfile.mMediaProfile = new ImsStreamMediaProfile(data);
+
+ Rlog.d(LOG_TAG, "RTT: packRttModifyRequestToProfile");
+ sendRttModifyRequest(toProfile);
+ }
+
+ private boolean canSendRttModifyRequest() {
+ ImsCall imsCall = getForegroundCall().getImsCall();
+ if (imsCall == null) {
+ Rlog.d(LOG_TAG, "RTT: imsCall null");
+ return false;
+ }
+
+ return true;
+ }
+
+ private boolean mapRequestToResponse(int response) {
+ switch (response) {
+ case QtiCallConstants.RTT_UPGRADE_CONFIRM:
+ return true;
+ case QtiCallConstants.RTT_UPGRADE_REJECT:
+ return false;
+ default:
+ return false;
+ }
+ }
+
+ /*
+ * Returns true if Mode is RTT_FULL, false otherwise
+ */
+ private boolean isInFullRttMode() {
+ int mode = QtiImsExtUtils.getRttOperatingMode(mContext);
+ Rlog.d(LOG_TAG, "RTT: isInFullRttMode mode = " + mode);
+ return (mode == QtiCallConstants.RTT_MODE_FULL);
+ }
+
+ /*
+ * Rtt for VT calls is not supported for certain operators
+ * Check the config and process the request
+ */
+ public boolean isRttVtCallAllowed(ImsCall call) {
+ int mode = QtiImsExtUtils.getRttOperatingMode(mContext);
+ Rlog.d(LOG_TAG, "RTT: isRttVtCallAllowed mode = " + mode);
+
+ if (call.getCallProfile().isVideoCall() &&
+ !QtiImsExtUtils.isRttSupportedOnVtCalls(mPhoneId, mContext)) {
+ return false;
+ }
+ return true;
+ }
+
+ public boolean canProcessRttRequest() {
+ // Process only if Carrier supports RTT and RTT is on
+ if (!(QtiImsExtUtils.isRttSupported(mPhoneId, mContext) &&
+ QtiImsExtUtils.isRttOn(mContext))) {
+ Rlog.d(LOG_TAG, "RTT: canProcessRttRequest RTT is not supported/off");
+ return false;
+ }
+ Rlog.d(LOG_TAG, "RTT: canProcessRttRequest rtt supported = " +
+ QtiImsExtUtils.isRttSupported(mPhoneId, mContext) + ", is Rtt on = " +
+ QtiImsExtUtils.isRttOn(mContext) + ", Rtt mode = " +
+ QtiImsExtUtils.getRttOperatingMode(mContext));
+ return true;
+ }
+
+ public boolean isFgCallActive() {
+ // process the request only if foreground is active
+ if (ImsPhoneCall.State.ACTIVE != getForegroundCall().getState()) {
+ Rlog.d(LOG_TAG, "RTT: isFgCallActive fg call not active");
+ return false;
+ }
+ return true;
+ }
+
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("ImsPhone extends:");
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
index a776816..725edfb 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
@@ -101,6 +101,9 @@
import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession.Event.ImsCommand;
import com.android.server.net.NetworkStatsService;
+import org.codeaurora.ims.QtiCallConstants;
+import org.codeaurora.ims.utils.QtiImsExtUtils;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -1213,6 +1216,7 @@
// being sent to the lower layers/to the network.
}
+ profile = setRttModeBasedOnOperator(profile);
ImsCall imsCall = mImsManager.makeCall(profile, callees, mImsCallListener);
conn.setImsCall(imsCall);
@@ -1245,6 +1249,7 @@
throw new CallStateException("cannot accept call");
}
+ ImsStreamMediaProfile mediaProfile = new ImsStreamMediaProfile();
if ((mRingingCall.getState() == ImsPhoneCall.State.WAITING)
&& mForegroundCall.getState().isAlive()) {
setMute(false);
@@ -1264,7 +1269,9 @@
// We need to disconnect the foreground call before answering the background call.
mForegroundCall.hangup();
try {
- ringingCall.accept(ImsCallProfile.getCallTypeFromVideoState(videoState));
+ mediaProfile = addRttAttributeIfRequired(ringingCall, mediaProfile);
+ ringingCall.accept(ImsCallProfile.getCallTypeFromVideoState(videoState),
+ mediaProfile);
} catch (ImsException e) {
throw new CallStateException("cannot accept call");
}
@@ -1278,7 +1285,9 @@
try {
ImsCall imsCall = mRingingCall.getImsCall();
if (imsCall != null) {
- imsCall.accept(ImsCallProfile.getCallTypeFromVideoState(videoState));
+ mediaProfile = addRttAttributeIfRequired(imsCall, mediaProfile);
+ imsCall.accept(ImsCallProfile.getCallTypeFromVideoState(videoState),
+ mediaProfile);
mMetrics.writeOnImsCommand(mPhone.getPhoneId(), imsCall.getSession(),
ImsCommand.IMS_CMD_ACCEPT);
} else {
@@ -1746,8 +1755,12 @@
//accept waiting call after holding background call
ImsCall imsCall = mRingingCall.getImsCall();
if (imsCall != null) {
+ ImsStreamMediaProfile mediaProfile = new ImsStreamMediaProfile();
+ mediaProfile = addRttAttributeIfRequired(imsCall, mediaProfile);
+
imsCall.accept(
- ImsCallProfile.getCallTypeFromVideoState(mPendingCallVideoState));
+ ImsCallProfile.getCallTypeFromVideoState(mPendingCallVideoState),
+ mediaProfile);
mMetrics.writeOnImsCommand(mPhone.getPhoneId(), imsCall.getSession(),
ImsCommand.IMS_CMD_ACCEPT);
}
@@ -3951,4 +3964,42 @@
public void setAlwaysPlayRemoteHoldTone(boolean shouldPlayRemoteHoldTone) {
mAlwaysPlayRemoteHoldTone = shouldPlayRemoteHoldTone;
}
+
+ // Update the Rtt attribute
+ private ImsCallProfile setRttModeBasedOnOperator(ImsCallProfile profile) {
+ if (!mPhone.canProcessRttRequest()) {
+ return profile;
+ }
+
+ int mode = QtiImsExtUtils.getRttOperatingMode(mPhone.getContext());
+
+ if (DBG) log("RTT: setRttModeBasedOnOperator mode = " + mode);
+
+ if (!QtiImsExtUtils.isRttSupportedOnVtCalls(mPhone.getPhoneId(), mPhone.getContext()) &&
+ profile.isVideoCall()) {
+ return profile;
+ }
+
+ profile.mMediaProfile.setRttMode(mode);
+ return profile;
+ }
+
+ // Accept the call as RTT if incoming call as RTT attribute set
+ private ImsStreamMediaProfile addRttAttributeIfRequired(ImsCall call,
+ ImsStreamMediaProfile mediaProfile) {
+
+ if (!mPhone.canProcessRttRequest()) {
+ return mediaProfile;
+ }
+
+ ImsCallProfile profile = call.getCallProfile();
+ if (profile.mMediaProfile != null && profile.mMediaProfile.isRttCall() &&
+ (mPhone.isRttVtCallAllowed(call))) {
+ if (DBG) log("RTT: addRttAttributeIfRequired = " + profile.mMediaProfile.isRttCall());
+ // If RTT UI option is on, then incoming RTT call should always be accepted
+ // as RTT, irrespective of Modes
+ mediaProfile.setRttMode(ImsStreamMediaProfile.RTT_MODE_FULL);
+ }
+ return mediaProfile;
+ }
}
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsRttTextHandler.java b/src/java/com/android/internal/telephony/imsphone/ImsRttTextHandler.java
index eff2499..b8dc76e 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsRttTextHandler.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsRttTextHandler.java
@@ -124,11 +124,19 @@
return;
}
mRttTextStream = (Connection.RttTextStream) msg.obj;
+ if (mRttTextStream == null) {
+ Rlog.e(LOG_TAG, "RTT text stream is null");
+ return;
+ }
mReaderThread = new InCallReaderThread(mRttTextStream);
mReaderThread.start();
break;
case SEND_TO_INCALL:
String messageToIncall = (String) msg.obj;
+ if (mRttTextStream == null) {
+ Rlog.e(LOG_TAG, "RTT text stream is null");
+ return;
+ }
try {
mRttTextStream.write(messageToIncall);
} catch (IOException e) {
diff --git a/src/java/com/android/internal/telephony/test/SimulatedCommandsVerifier.java b/src/java/com/android/internal/telephony/test/SimulatedCommandsVerifier.java
index f43cee0..2d7e814 100644
--- a/src/java/com/android/internal/telephony/test/SimulatedCommandsVerifier.java
+++ b/src/java/com/android/internal/telephony/test/SimulatedCommandsVerifier.java
@@ -1308,8 +1308,7 @@
}
@Override
- public void setUiccSubscription(int slotId, int appIndex, int subId, int subStatus,
- Message result) {
+ public void setUiccSubscription(int appIndex, boolean activate, Message result) {
}
diff --git a/src/java/com/android/internal/telephony/uicc/AdnRecord.java b/src/java/com/android/internal/telephony/uicc/AdnRecord.java
index 4414caf..acda8bd 100644
--- a/src/java/com/android/internal/telephony/uicc/AdnRecord.java
+++ b/src/java/com/android/internal/telephony/uicc/AdnRecord.java
@@ -42,6 +42,7 @@
String mAlphaTag = null;
String mNumber = null;
String[] mEmails;
+ String[] mAdditionalNumbers = null;
int mExtRecord = 0xff;
int mEfid; // or 0 if none
int mRecordNumber; // or 0 if none
@@ -80,14 +81,16 @@
String alphaTag;
String number;
String[] emails;
+ String[] additionalNumbers;
efid = source.readInt();
recordNumber = source.readInt();
alphaTag = source.readString();
number = source.readString();
emails = source.readStringArray();
+ additionalNumbers = source.readStringArray();
- return new AdnRecord(efid, recordNumber, alphaTag, number, emails);
+ return new AdnRecord(efid, recordNumber, alphaTag, number, emails, additionalNumbers);
}
@Override
@@ -116,12 +119,27 @@
this(0, 0, alphaTag, number, emails);
}
+ public AdnRecord(String alphaTag, String number, String[] emails, String[] additionalNumbers) {
+ this(0, 0, alphaTag, number, emails, additionalNumbers);
+ }
+
public AdnRecord (int efid, int recordNumber, String alphaTag, String number, String[] emails) {
this.mEfid = efid;
this.mRecordNumber = recordNumber;
this.mAlphaTag = alphaTag;
this.mNumber = number;
this.mEmails = emails;
+ this.mAdditionalNumbers = null;
+ }
+
+ public AdnRecord(int efid, int recordNumber, String alphaTag, String number, String[] emails,
+ String[] additionalNumbers) {
+ this.mEfid = efid;
+ this.mRecordNumber = recordNumber;
+ this.mAlphaTag = alphaTag;
+ this.mNumber = number;
+ this.mEmails = emails;
+ this.mAdditionalNumbers = additionalNumbers;
}
public AdnRecord(int efid, int recordNumber, String alphaTag, String number) {
@@ -130,6 +148,7 @@
this.mAlphaTag = alphaTag;
this.mNumber = number;
this.mEmails = null;
+ this.mAdditionalNumbers = null;
}
//***** Instance Methods
@@ -162,14 +181,32 @@
this.mEmails = emails;
}
+ public String[] getAdditionalNumbers() {
+ return mAdditionalNumbers;
+ }
+
+ public void setAdditionalNumbers(String[] additionalNumbers) {
+ this.mAdditionalNumbers = additionalNumbers;
+ }
+
+ public int getRecordNumber() {
+ return mRecordNumber;
+ }
+
+ public void setRecordNumber(int recNumber) {
+ mRecordNumber = recNumber;
+ }
+
@Override
public String toString() {
return "ADN Record '" + mAlphaTag + "' '" + Rlog.pii(LOG_TAG, mNumber) + " "
- + Rlog.pii(LOG_TAG, mEmails) + "'";
+ + Rlog.pii(LOG_TAG, mEmails) + " "
+ + Rlog.pii(LOG_TAG, mAdditionalNumbers) + "'";
}
public boolean isEmpty() {
- return TextUtils.isEmpty(mAlphaTag) && TextUtils.isEmpty(mNumber) && mEmails == null;
+ return TextUtils.isEmpty(mAlphaTag) && TextUtils.isEmpty(mNumber) && mEmails == null &&
+ mAdditionalNumbers == null;
}
public boolean hasExtendedRecord() {
@@ -190,11 +227,56 @@
return (s1.equals(s2));
}
+ /** Help function for ANR/EMAIL array compare. */
+ private static boolean arrayCompareNullEqualsEmpty(String s1[], String s2[]) {
+ if (s1 == s2) {
+ return true;
+ }
+
+ if (s1 == null) {
+ s1 = new String[1];
+ s1[0] = "";
+ }
+
+ if (s2 == null) {
+ s2 = new String[1];
+ s2[0] = "";
+ }
+
+ for (String str:s1) {
+ if (TextUtils.isEmpty(str)) {
+ continue;
+ } else {
+ if (Arrays.asList(s2).contains(str)) {
+ continue;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ for (String str:s2) {
+ if (TextUtils.isEmpty(str)) {
+ continue;
+ } else {
+ if (Arrays.asList(s1).contains(str)) {
+ continue;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
public boolean isEqual(AdnRecord adn) {
return ( stringCompareNullEqualsEmpty(mAlphaTag, adn.mAlphaTag) &&
stringCompareNullEqualsEmpty(mNumber, adn.mNumber) &&
- Arrays.equals(mEmails, adn.mEmails));
+ arrayCompareNullEqualsEmpty(mEmails, adn.mEmails) &&
+ arrayCompareNullEqualsEmpty(mAdditionalNumbers, adn.mAdditionalNumbers));
}
+
//***** Parcelable Implementation
@Override
@@ -209,6 +291,7 @@
dest.writeString(mAlphaTag);
dest.writeString(mNumber);
dest.writeStringArray(mEmails);
+ dest.writeStringArray(mAdditionalNumbers);
}
/**
@@ -231,11 +314,11 @@
adnString[i] = (byte) 0xFF;
}
- if (TextUtils.isEmpty(mNumber)) {
+ if (TextUtils.isEmpty(mNumber) && TextUtils.isEmpty(mAlphaTag)) {
Rlog.w(LOG_TAG, "[buildAdnString] Empty dialing number");
return adnString; // return the empty record (for delete)
- } else if (mNumber.length()
- > (ADN_DIALING_NUMBER_END - ADN_DIALING_NUMBER_START + 1) * 2) {
+ } else if (mNumber != null &&
+ mNumber.length() > (ADN_DIALING_NUMBER_END - ADN_DIALING_NUMBER_START + 1) * 2) {
Rlog.w(LOG_TAG,
"[buildAdnString] Max length of dialing number is 20");
return null;
@@ -248,14 +331,16 @@
Rlog.w(LOG_TAG, "[buildAdnString] Max length of tag is " + footerOffset);
return null;
} else {
- bcdNumber = PhoneNumberUtils.numberToCalledPartyBCD(
- mNumber, PhoneNumberUtils.BCD_EXTENDED_TYPE_EF_ADN);
+ if (!TextUtils.isEmpty(mNumber)) {
+ bcdNumber = PhoneNumberUtils.numberToCalledPartyBCD(
+ mNumber, PhoneNumberUtils.BCD_EXTENDED_TYPE_EF_ADN);
- System.arraycopy(bcdNumber, 0, adnString,
- footerOffset + ADN_TON_AND_NPI, bcdNumber.length);
+ System.arraycopy(bcdNumber, 0, adnString,
+ footerOffset + ADN_TON_AND_NPI, bcdNumber.length);
- adnString[footerOffset + ADN_BCD_NUMBER_LENGTH]
- = (byte) (bcdNumber.length);
+ adnString[footerOffset + ADN_BCD_NUMBER_LENGTH]
+ = (byte) (bcdNumber.length);
+ }
adnString[footerOffset + ADN_CAPABILITY_ID]
= (byte) 0xFF; // Capability Id
adnString[footerOffset + ADN_EXTENSION_ID]
@@ -340,12 +425,14 @@
mExtRecord = 0xff & record[record.length - 1];
mEmails = null;
+ mAdditionalNumbers = null;
} catch (RuntimeException ex) {
Rlog.w(LOG_TAG, "Error parsing AdnRecord", ex);
mNumber = "";
mAlphaTag = "";
mEmails = null;
+ mAdditionalNumbers = null;
}
}
}
diff --git a/src/java/com/android/internal/telephony/uicc/RuimRecords.java b/src/java/com/android/internal/telephony/uicc/RuimRecords.java
index 88ac071..9a9435a 100644
--- a/src/java/com/android/internal/telephony/uicc/RuimRecords.java
+++ b/src/java/com/android/internal/telephony/uicc/RuimRecords.java
@@ -84,8 +84,11 @@
+ " mHomeNetworkId=" + mHomeNetworkId;
}
+ // Constants
+ // MNC length in case of CSIM/RUIM IMSI is 2 as per spec C.S0065 section 5.2.2
+ private static final int CSIM_IMSI_MNC_LENGTH = 2;
+
// ***** Event Constants
- private static final int EVENT_GET_IMSI_DONE = 3;
private static final int EVENT_GET_DEVICE_IDENTITY_DONE = 4;
private static final int EVENT_GET_ICCID_DONE = 5;
private static final int EVENT_GET_CDMA_SUBSCRIPTION_DONE = 10;
@@ -203,16 +206,67 @@
}
}
- private int adjstMinDigits (int digits) {
+ private int decodeImsiDigits(int digits, int length) {
// Per C.S0005 section 2.3.1.
- digits += 111;
- digits = (digits % 10 == 0)?(digits - 10):digits;
- digits = ((digits / 10) % 10 == 0)?(digits - 100):digits;
- digits = ((digits / 100) % 10 == 0)?(digits - 1000):digits;
+ int constant = 0;
+ for (int i = 0; i < length; i++) {
+ constant = (constant * 10) + 1;
+ }
+
+ digits += constant;
+
+ for (int i = 0, denominator = 1; i < length; i++) {
+ digits = ((digits / denominator) % 10 == 0) ? (digits - (10 * denominator)) : digits;
+ denominator *= 10;
+ }
return digits;
}
/**
+ * Decode utility to decode IMSI from data read from EF_IMSIM
+ * Please refer to
+ * // C.S0065 section 5.2.2 for IMSI_M encoding
+ * // C.S0005 section 2.3.1 for MIN encoding in IMSI_M.
+ */
+ private String decodeImsi(byte[] data) {
+ // Retrieve the MCC and digits 11 and 12
+ int mcc_data = ((0x03 & data[9]) << 8) | (0xFF & data[8]);
+ int mcc = decodeImsiDigits(mcc_data, 3);
+ int digits_11_12_data = data[6] & 0x7f;
+ int digits_11_12 = decodeImsiDigits(digits_11_12_data, 2);
+
+ // Retrieve 10 MIN digits
+ int first3digits = ((0x03 & data[2]) << 8) + (0xFF & data[1]);
+ int second3digits = (((0xFF & data[5]) << 8) | (0xFF & data[4])) >> 6;
+ int digit7 = 0x0F & (data[4] >> 2);
+ if (digit7 > 0x09) digit7 = 0;
+ int last3digits = ((0x03 & data[4]) << 8) | (0xFF & data[3]);
+
+ first3digits = decodeImsiDigits(first3digits, 3);
+ second3digits = decodeImsiDigits(second3digits, 3);
+ last3digits = decodeImsiDigits(last3digits, 3);
+
+ StringBuilder builder = new StringBuilder();
+ builder.append(String.format(Locale.US, "%03d", mcc));
+ builder.append(String.format(Locale.US, "%02d", digits_11_12));
+ builder.append(String.format(Locale.US, "%03d", first3digits));
+ builder.append(String.format(Locale.US, "%03d", second3digits));
+ builder.append(String.format(Locale.US, "%d", digit7));
+ builder.append(String.format(Locale.US, "%03d", last3digits));
+ return builder.toString();
+ }
+
+ /**
+ * Introduce Generic API returns the 5 or 6 digit MCC/MNC
+ * of the operator that provided the RUIM card.
+ * Returns null of RUIM is not yet ready
+ */
+ @Override
+ public String getOperatorNumeric() {
+ return getRUIMOperatorNumeric();
+ }
+
+ /**
* Returns the 5 or 6 digit MCC/MNC of the operator that
* provided the RUIM card. Returns null of RUIM is not yet ready
*/
@@ -229,11 +283,7 @@
return imsi.substring(0, 3 + mMncLength);
}
- // Guess the MNC length based on the MCC if we don't
- // have a valid value in ef[ad]
-
- int mcc = Integer.parseInt(imsi.substring(0, 3));
- return imsi.substring(0, 3 + MccTable.smallestDigitsMccForMnc(mcc));
+ return mImsi.substring(0, 3 + CSIM_IMSI_MNC_LENGTH);
}
// Refer to ETSI TS 102.221
@@ -378,31 +428,39 @@
@Override
public void onRecordLoaded(AsyncResult ar) {
byte[] data = (byte[]) ar.result;
+
+ if (data == null || data.length < 10) {
+ log("Invalid IMSI from EF_CSIM_IMSIM " + IccUtils.bytesToHexString(data));
+ mImsi = null;
+ mMin = null;
+ return;
+ }
if (VDBG) log("CSIM_IMSIM=" + IccUtils.bytesToHexString(data));
+
// C.S0065 section 5.2.2 for IMSI_M encoding
// C.S0005 section 2.3.1 for MIN encoding in IMSI_M.
boolean provisioned = ((data[7] & 0x80) == 0x80);
if (provisioned) {
- int first3digits = ((0x03 & data[2]) << 8) + (0xFF & data[1]);
- int second3digits = (((0xFF & data[5]) << 8) | (0xFF & data[4])) >> 6;
- int digit7 = 0x0F & (data[4] >> 2);
- if (digit7 > 0x09) digit7 = 0;
- int last3digits = ((0x03 & data[4]) << 8) | (0xFF & data[3]);
- first3digits = adjstMinDigits(first3digits);
- second3digits = adjstMinDigits(second3digits);
- last3digits = adjstMinDigits(last3digits);
+ mImsi = decodeImsi(data);
+ if (null != mImsi) {
+ mMin = mImsi.substring(5, 15);
+ }
+ if (DBG) log("IMSI: " + mImsi.substring(0, 5) + "xxxxxxxxx");
- StringBuilder builder = new StringBuilder();
- builder.append(String.format(Locale.US, "%03d", first3digits));
- builder.append(String.format(Locale.US, "%03d", second3digits));
- builder.append(String.format(Locale.US, "%d", digit7));
- builder.append(String.format(Locale.US, "%03d", last3digits));
- mMin = builder.toString();
- if (DBG) log("min present=" + mMin);
} else {
- if (DBG) log("min not present");
+ if (DBG) log("IMSI not provisioned in card");
}
+
+ // Update MccTable with the retrieved IMSI
+ String operatorNumeric = getOperatorNumeric();
+ if (operatorNumeric != null) {
+ if (operatorNumeric.length() <= 6) {
+ MccTable.updateMccMncConfiguration(mContext, operatorNumeric, false);
+ }
+ }
+
+ mImsiReadyRegistrants.notifyRegistrants();
}
}
@@ -618,43 +676,6 @@
log("Event EVENT_GET_DEVICE_IDENTITY_DONE Received");
break;
- /* IO events */
- case EVENT_GET_IMSI_DONE:
- isRecordLoadResponse = true;
-
- ar = (AsyncResult)msg.obj;
- if (ar.exception != null) {
- loge("Exception querying IMSI, Exception:" + ar.exception);
- break;
- }
-
- mImsi = (String) ar.result;
-
- // IMSI (MCC+MNC+MSIN) is at least 6 digits, but not more
- // than 15 (and usually 15).
- if (mImsi != null && (mImsi.length() < 6 || mImsi.length() > 15)) {
- loge("invalid IMSI " + mImsi);
- mImsi = null;
- }
-
- // FIXME: CSIM IMSI may not contain the MNC.
- if (false) {
- log("IMSI: " + mImsi.substring(0, 6) + "xxxxxxxxx");
-
- String operatorNumeric = getRUIMOperatorNumeric();
- if (operatorNumeric != null) {
- if (operatorNumeric.length() <= 6) {
- log("update mccmnc=" + operatorNumeric);
- MccTable.updateMccMncConfiguration(mContext, operatorNumeric, false);
- }
- }
- } else {
- String operatorNumeric = getRUIMOperatorNumeric();
- log("NO update mccmnc=" + operatorNumeric);
- }
-
- break;
-
case EVENT_GET_CDMA_SUBSCRIPTION_DONE:
ar = (AsyncResult)msg.obj;
String localTemp[] = (String[])ar.result;
@@ -844,9 +865,6 @@
if (DBG) log("fetchRuimRecords " + mRecordsToLoad);
- mCi.getIMSIForApp(mParentApp.getAid(), obtainMessage(EVENT_GET_IMSI_DONE));
- mRecordsToLoad++;
-
mFh.loadEFTransparent(EF_ICCID,
obtainMessage(EVENT_GET_ICCID_DONE));
mRecordsToLoad++;
diff --git a/src/java/com/android/internal/telephony/uicc/UiccProfile.java b/src/java/com/android/internal/telephony/uicc/UiccProfile.java
index 2910ff7..80248ea 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccProfile.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccProfile.java
@@ -55,6 +55,7 @@
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.PhoneFactory;
+import com.android.internal.telephony.RIL;
import com.android.internal.telephony.SubscriptionController;
import com.android.internal.telephony.cat.CatService;
import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType;
@@ -103,6 +104,7 @@
private final UiccCard mUiccCard; //parent
private CatService mCatService;
private UiccCarrierPrivilegeRules mCarrierPrivilegeRules;
+ private boolean mDefaultAppsActivated;
private boolean mDisposed = false;
private RegistrantList mCarrierPrivilegeRegistrants = new RegistrantList();
@@ -920,10 +922,59 @@
}
sanitizeApplicationIndexesLocked();
+
+ if (needsSimActivation()) {
+ if (ics.mCardState == CardState.CARDSTATE_PRESENT) {
+ if (!mDefaultAppsActivated) {
+ activateDefaultApps();
+ mDefaultAppsActivated = true;
+ }
+ } else {
+ // SIM removed, reset activation flag to make sure
+ // to re-run the activation at the next insertion
+ mDefaultAppsActivated = false;
+ }
+ }
+
updateIccAvailability(true);
}
}
+ private boolean needsSimActivation() {
+ if (mCi instanceof RIL) {
+ return ((RIL) mCi).needsOldRilFeature("simactivation");
+ }
+ return false;
+ }
+
+ private void activateDefaultApps() {
+ int gsmIndex = mGsmUmtsSubscriptionAppIndex;
+ int cdmaIndex = mCdmaSubscriptionAppIndex;
+
+ if (gsmIndex < 0 || cdmaIndex < 0) {
+ for (int i = 0; i < mUiccApplications.length; i++) {
+ if (mUiccApplications[i] == null) {
+ continue;
+ }
+
+ AppType appType = mUiccApplications[i].getType();
+ if (gsmIndex < 0 &&
+ (appType == AppType.APPTYPE_USIM || appType == AppType.APPTYPE_SIM)) {
+ gsmIndex = i;
+ } else if (cdmaIndex < 0 &&
+ (appType == AppType.APPTYPE_CSIM || appType == AppType.APPTYPE_RUIM)) {
+ cdmaIndex = i;
+ }
+ }
+ }
+ if (gsmIndex >= 0) {
+ mCi.setUiccSubscription(gsmIndex, true, null);
+ }
+ if (cdmaIndex >= 0) {
+ mCi.setUiccSubscription(cdmaIndex, true, null);
+ }
+ }
+
private void createAndUpdateCatServiceLocked() {
if (mUiccApplications.length > 0 && mUiccApplications[0] != null) {
// Initialize or Reinitialize CatService
diff --git a/src/java/com/android/internal/telephony/util/TelephonyExtUtils.java b/src/java/com/android/internal/telephony/util/TelephonyExtUtils.java
new file mode 100644
index 0000000..b4cd601
--- /dev/null
+++ b/src/java/com/android/internal/telephony/util/TelephonyExtUtils.java
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2018 The LineageOS 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.internal.telephony.util;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.telephony.SubscriptionManager;
+import android.util.Log;
+
+import com.android.internal.telephony.PhoneConstants;
+
+import org.codeaurora.internal.IExtTelephony;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public final class TelephonyExtUtils {
+ private static final boolean DEBUG = false;
+ private static final String TAG = "TelephonyExtUtils";
+
+ public static final String ACTION_UICC_MANUAL_PROVISION_STATUS_CHANGED =
+ "org.codeaurora.intent.action.ACTION_UICC_MANUAL_PROVISION_STATUS_CHANGED";
+
+ public static final String EXTRA_NEW_PROVISION_STATE = "newProvisionState";
+
+ // This is the list of possible values that
+ // IExtTelephony.getCurrentUiccCardProvisioningStatus() can return
+ public static final int CARD_NOT_PRESENT = -2;
+ public static final int INVALID_STATE = -1;
+ public static final int NOT_PROVISIONED = 0;
+ public static final int PROVISIONED = 1;
+
+ private boolean mNoServiceAvailable = false;
+ private IExtTelephony mExtTelephony;
+
+ private static TelephonyExtUtils sInstance;
+
+ private final List<ProvisioningChangedListener> mListeners = new ArrayList<>();
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
+ if (DEBUG) Log.d(TAG, "Boot completed, registering service");
+ mNoServiceAvailable = getService() == null;
+ } else if (ACTION_UICC_MANUAL_PROVISION_STATUS_CHANGED.equals(action)) {
+ int slotId = intent.getIntExtra(PhoneConstants.PHONE_KEY,
+ SubscriptionManager.INVALID_SIM_SLOT_INDEX);
+ boolean provisioned = intent.getIntExtra(EXTRA_NEW_PROVISION_STATE,
+ NOT_PROVISIONED) == PROVISIONED;
+ if (DEBUG) Log.d(TAG, "Received ACTION_UICC_MANUAL_PROVISION_STATUS_CHANGED"
+ + " on slotId: " + slotId + ", sub provisioned: " + provisioned);
+ notifyListeners(slotId, provisioned);
+ }
+ }
+ };
+
+ // This class is not supposed to be instantiated externally
+ private TelephonyExtUtils(Context context) {
+ if (DEBUG) Log.d(TAG, "Registering listeners!");
+
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(ACTION_UICC_MANUAL_PROVISION_STATUS_CHANGED);
+ intentFilter.addAction(Intent.ACTION_BOOT_COMPLETED);
+ context.registerReceiver(mReceiver, intentFilter);
+ }
+
+ /**
+ * Get an existing instance of the utils or create a new one if not existant
+ *
+ * @return An instance of this class
+ */
+ public static TelephonyExtUtils getInstance(Context context) {
+ if (sInstance == null) {
+ sInstance = new TelephonyExtUtils(context.getApplicationContext());
+ }
+ return sInstance;
+ }
+
+ /**
+ * Determines whether the ITelephonyExt service is available on the device
+ * Any result of the methods in this class are only valid if this method returns true
+ *
+ * @return true on success
+ */
+ public boolean hasService() {
+ return getService() != null;
+ }
+
+ /**
+ * Determines whether the SIM associated with the given SubscriptionId is provisioned
+ *
+ * @return true if the SIM associated with the given subId is provisioned
+ */
+ public boolean isSubProvisioned(int subId) {
+ return isSlotProvisioned(SubscriptionManager.getSlotIndex(subId));
+ }
+
+ /**
+ * Determines whether the given SIM is provisioned
+ *
+ * @return true if the SIM is provisioned
+ */
+ public boolean isSlotProvisioned(int slotId) {
+ return getCurrentUiccCardProvisioningStatus(slotId) == PROVISIONED;
+ }
+
+ /**
+ * Get the current provisioning status for a given SIM slot
+ *
+ * @return The provisioning status from the extension or INVALID_STATE if not possible
+ */
+ public int getCurrentUiccCardProvisioningStatus(int slotId) {
+ IExtTelephony service = getService();
+ if (service != null && slotId != SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
+ try {
+ return mExtTelephony.getCurrentUiccCardProvisioningStatus(slotId);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Failed to get provisioning status for slotId: " + slotId, ex);
+ }
+ }
+ return INVALID_STATE;
+ }
+
+ /**
+ * Activate the SIM card with the given slotId
+ *
+ * @return The result of the activation or -1
+ */
+ public int activateUiccCard(int slotId) {
+ IExtTelephony service = getService();
+ if (service != null) {
+ try {
+ return mExtTelephony.activateUiccCard(slotId);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Activating sub failed for slotId: " + slotId);
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Deactivate the SIM card with the given slotId
+ *
+ * @return The result of the deactivation or -1
+ */
+ public int deactivateUiccCard(int slotId) {
+ IExtTelephony service = getService();
+ if (service != null) {
+ try {
+ return mExtTelephony.deactivateUiccCard(slotId);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Deactivating sub failed for slotId: " + slotId);
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Add a ProvisioningChangedListener to get notified in case of provisioning changes
+ */
+ public void addListener(ProvisioningChangedListener listener) {
+ if (listener != null) {
+ mListeners.remove(listener);
+ mListeners.add(listener);
+ }
+ }
+
+ /**
+ * Remove a ProvisioningChangedListener to not get notified of provisioning changes anymore
+ */
+ public void removeListener(ProvisioningChangedListener listener) {
+ if (listener != null) {
+ mListeners.remove(listener);
+ }
+ }
+
+ /**
+ * Notify all registered listeners about provisioning changes
+ */
+ private void notifyListeners(int slotId, boolean provisioned) {
+ for (ProvisioningChangedListener listener : mListeners) {
+ listener.onProvisioningChanged(slotId, provisioned);
+ }
+ }
+
+ /**
+ * Helper method to get an already instantiated service or instantiate it
+ *
+ * @return a valid service instance or null
+ */
+ private IExtTelephony getService() {
+ // We already tried to get the service but weren't successful, so just return null here
+ if (mNoServiceAvailable) {
+ if (DEBUG) Log.v(TAG, "Already tried to get a service without success, returning!");
+ return null;
+ }
+
+ if (DEBUG) Log.d(TAG, "Retrieving the service");
+
+ // Instead of getting a new service instance, return an already existing one here
+ if (mExtTelephony != null) {
+ if (DEBUG) Log.d(TAG, "Returning cached service instance");
+ return mExtTelephony;
+ }
+
+ synchronized(TelephonyExtUtils.class) {
+ try {
+ mExtTelephony =
+ IExtTelephony.Stub.asInterface(ServiceManager.getService("extphone"));
+ } catch (NoClassDefFoundError ex) {
+ // Ignore, device does not ship with telephony-ext
+ Log.d(TAG, "Failed to get telephony extension service!");
+ mNoServiceAvailable = true;
+ }
+ }
+
+ return mExtTelephony;
+ }
+
+ /**
+ * Interface definition so we can register callbacks to get the provisioning status
+ * whenever it changes
+ */
+ public interface ProvisioningChangedListener {
+ public void onProvisioningChanged(int slotId, boolean isProvisioned);
+ }
+}
\ No newline at end of file
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/IccPhoneBookInterfaceManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/IccPhoneBookInterfaceManagerTest.java
index 9510619..df9a436 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/uicc/IccPhoneBookInterfaceManagerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/IccPhoneBookInterfaceManagerTest.java
@@ -15,6 +15,7 @@
*/
package com.android.internal.telephony.uicc;
+import android.content.ContentValues;
import android.os.HandlerThread;
import android.os.Message;
import android.os.AsyncResult;
@@ -36,7 +37,9 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyString;
import java.util.Arrays;
import java.util.List;
@@ -115,4 +118,36 @@
//verify the previous read is not got affected
assertEquals(mAdnList, adnListResult);
}
+
+ @Test
+ @SmallTest
+ public void testUpdateAdnRecord() {
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Message response = (Message) invocation.getArguments()[4];
+ //set result for update ADN EF
+ AsyncResult.forMessage(response).exception = null;
+ response.sendToTarget();
+ return null;
+ }
+ }).when(mAdnRecordCache).updateAdnBySearch(anyInt(),
+ (AdnRecord) anyObject(), (AdnRecord) anyObject(),
+ anyString(), (Message) anyObject());
+
+ ContentValues values = new ContentValues();
+ values.put("tag", "");
+ values.put("number", "");
+ values.put("emails", "");
+ values.put("anrs", "");
+ values.put("newTag", "test");
+ values.put("newNumber", "123456");
+ values.put("newEmails", "");
+ values.put("newAnrs", "");
+
+ boolean result = mIccPhoneBookInterfaceMgr.updateAdnRecordsWithContentValuesInEfBySearch(
+ IccConstants.EF_ADN, values , null);
+
+ assertTrue(result);
+ }
}