aboutsummaryrefslogtreecommitdiff
path: root/ril/telephony
diff options
context:
space:
mode:
authorMister Oyster <oysterized@gmail.com>2017-02-05 19:57:35 +0100
committerMister Oyster <oysterized@gmail.com>2017-02-05 19:57:35 +0100
commit16e6bbbc2e3ddea8ec8d229767cc45121fd8cd82 (patch)
tree1ff10d387c0efab7ca16d3e8d9ad232823c33f33 /ril/telephony
initial commit
Diffstat (limited to 'ril/telephony')
-rw-r--r--ril/telephony/java/com/android/internal/telephony/MediaTekRIL.java517
-rwxr-xr-xril/telephony/java/com/android/internal/telephony/MtkEccList.java385
2 files changed, 902 insertions, 0 deletions
diff --git a/ril/telephony/java/com/android/internal/telephony/MediaTekRIL.java b/ril/telephony/java/com/android/internal/telephony/MediaTekRIL.java
new file mode 100644
index 0000000..1909338
--- /dev/null
+++ b/ril/telephony/java/com/android/internal/telephony/MediaTekRIL.java
@@ -0,0 +1,517 @@
+/*
+ * Copyright (C) 2016 The CyanogenMod 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;
+
+import static com.android.internal.telephony.RILConstants.*;
+
+import com.android.internal.telephony.dataconnection.DataCallResponse;
+import com.android.internal.telephony.uicc.IccRefreshResponse;
+
+import android.content.Context;
+import android.os.AsyncResult;
+import android.os.Message;
+import android.os.Parcel;
+import android.os.SystemProperties;
+
+import android.provider.Settings;
+import android.provider.Settings.Global;
+
+import android.telephony.TelephonyManager;
+
+import com.android.internal.telephony.MtkEccList;
+
+
+/**
+ * Custom wrapper for MTK requests
+ *
+ * {@hide}
+ */
+public class MediaTekRIL extends RIL implements CommandsInterface {
+ static final String LOG_TAG = "MediaTekRIL";
+
+ static final int RIL_REQUEST_VENDOR_BASE = 2000;
+ static final int RIL_REQUEST_MODEM_POWEROFF = (RIL_REQUEST_VENDOR_BASE + 10);
+// static final int RIL_REQUEST_DUAL_SIM_MODE_SWITCH = (RIL_REQUEST_VENDOR_BASE + 11);
+// static final int RIL_REQUEST_USIM_AUTHENTICATION = (RIL_REQUEST_VENDOR_BASE + 27);
+ static final int RIL_REQUEST_MODEM_POWERON = (RIL_REQUEST_VENDOR_BASE + 28);
+ static final int RIL_REQUEST_RESUME_REGISTRATION = (RIL_REQUEST_VENDOR_BASE + 65);
+// static final int RIL_REQUEST_SIM_INTERFACE_SWITCH = (RIL_REQUEST_VENDOR_BASE + 68);
+ static final int RIL_REQUEST_SET_CALL_INDICATION = (RIL_REQUEST_VENDOR_BASE + 86);
+ static final int RIL_REQUEST_EMERGENCY_DIAL = (RIL_REQUEST_VENDOR_BASE + 87);
+ static final int RIL_REQUEST_SET_ECC_SERVICE_CATEGORY = (RIL_REQUEST_VENDOR_BASE + 88);
+ static final int RIL_REQUEST_SET_ECC_LIST = (RIL_REQUEST_VENDOR_BASE + 89);
+ static final int RIL_REQUEST_GENERAL_SIM_AUTH = (RIL_REQUEST_VENDOR_BASE + 90);
+ static final int RIL_REQUEST_QUERY_AVAILABLE_NETWORK_WITH_ACT = (RIL_REQUEST_VENDOR_BASE + 95);
+ static final int RIL_REQUEST_SWITCH_CARD_TYPE = (RIL_REQUEST_VENDOR_BASE + 131);
+
+ static final int RIL_UNSOL_VENDOR_BASE = 3000;
+ static final int RIL_UNSOL_RESPONSE_PS_NETWORK_STATE_CHANGED = (RIL_UNSOL_VENDOR_BASE + 15);
+ static final int RIL_UNSOL_RESPONSE_REGISTRATION_SUSPENDED = (RIL_UNSOL_VENDOR_BASE + 24);
+ static final int RIL_UNSOL_INCOMING_CALL_INDICATION = (RIL_UNSOL_VENDOR_BASE + 42);
+ static final int RIL_UNSOL_CALL_INFO_INDICATION = (RIL_UNSOL_VENDOR_BASE + 49);
+ static final int RIL_UNSOL_MD_STATE_CHANGE = (RIL_UNSOL_VENDOR_BASE + 53);
+ static final int RIL_UNSOL_SET_ATTACH_APN = (RIL_UNSOL_VENDOR_BASE + 73);
+// static final int RIL_UNSOL_MAL_AT_INFO = (RIL_UNSOL_VENDOR_BASE + 74);
+// static final int RIL_UNSOL_MAIN_SIM_INFO = (RIL_UNSOL_VENDOR_BASE + 75);
+
+ private int[] dataCallCids = { -1, -1, -1, -1, -1 };
+
+ private Context mContext;
+ private TelephonyManager mTelephonyManager;
+ private MtkEccList mEccList;
+
+ //***** Constructors
+ public MediaTekRIL(Context context, int preferredNetworkType, int cdmaSubscription) {
+ super(context, preferredNetworkType, cdmaSubscription, null);
+ }
+
+ public MediaTekRIL(Context context, int preferredNetworkType,
+ int cdmaSubscription, Integer instanceId) {
+ super(context, preferredNetworkType, cdmaSubscription, instanceId);
+ mContext = context;
+ mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
+ mEccList = new MtkEccList();
+ }
+
+ private static String
+ localRequestToString(int request)
+ {
+ switch(request) {
+ case RIL_REQUEST_RESUME_REGISTRATION: return "RIL_REQUEST_RESUME_REGISTRATION";
+ case RIL_REQUEST_SET_CALL_INDICATION: return "RIL_REQUEST_SET_CALL_INDICATION";
+ case RIL_REQUEST_EMERGENCY_DIAL: return "RIL_REQUEST_EMERGENCY_DIAL";
+ case RIL_REQUEST_SET_ECC_SERVICE_CATEGORY: return "RIL_REQUEST_SET_ECC_SERVICE_CATEGORY";
+ case RIL_REQUEST_SET_ECC_LIST: return "RIL_REQUEST_SET_ECC_LIST";
+ case RIL_REQUEST_MODEM_POWEROFF: return "RIL_REQUEST_MODEM_POWEROFF";
+ case RIL_REQUEST_MODEM_POWERON: return "RIL_REQUEST_MODEM_POWERON";
+ default: return "<unknown response>";
+ }
+ }
+
+ @Override
+ protected void
+ processUnsolicited (Parcel p, int type) {
+ Object ret;
+ int dataPosition = p.dataPosition(); // save off position within the Parcel
+ int response = p.readInt();
+
+ switch(response) {
+ case RIL_UNSOL_RESPONSE_REGISTRATION_SUSPENDED: ret = responseRegSuspended(p); break;
+ case RIL_UNSOL_INCOMING_CALL_INDICATION: ret = responseIncomingCallIndication(p); break;
+ case RIL_UNSOL_CALL_INFO_INDICATION: ret = responseCallProgress(p); break;
+ case RIL_UNSOL_MD_STATE_CHANGE: ret = responseInts(p); break;
+ case RIL_UNSOL_SET_ATTACH_APN: ret = responseSetAttachApn(p); break;
+ case RIL_UNSOL_ON_USSD: ret = responseStrings(p); break;
+ case RIL_UNSOL_RESPONSE_PS_NETWORK_STATE_CHANGED: ret = responseInts(p); break;
+ default:
+ // Rewind the Parcel
+ p.setDataPosition(dataPosition);
+ // Forward responses that we are not overriding to the super class
+ super.processUnsolicited(p, type);
+ return;
+ }
+ switch(response) {
+ case RIL_UNSOL_INCOMING_CALL_INDICATION:
+ mCallStateRegistrants
+ .notifyRegistrants(new AsyncResult(null, null, null));
+ break;
+ case RIL_UNSOL_CALL_INFO_INDICATION:
+ if (ret == null) {
+ mCallStateRegistrants
+ .notifyRegistrants(new AsyncResult(null, null, null));
+ }
+ break;
+ case RIL_UNSOL_ON_USSD:
+ String[] resp = (String[])ret;
+
+ if (resp.length < 2) {
+ resp = new String[2];
+ resp[0] = ((String[])ret)[0];
+ resp[1] = null;
+ }
+ if (resp[0] != null &&
+ Integer.parseInt(resp[0]) >= 2 &&
+ Integer.parseInt(resp[0]) <=5 ) {
+ // support USSD_SESSION_END and USSD_HANDLED_BY_STK as normal finishes
+ resp[0] = "0";
+ }
+
+ if (RILJ_LOGD) unsljLogMore(response, resp[0]);
+ if (mUSSDRegistrant != null) {
+ mUSSDRegistrant.notifyRegistrant(
+ new AsyncResult (null, resp, null));
+ }
+ break;
+ case RIL_UNSOL_RESPONSE_PS_NETWORK_STATE_CHANGED:
+ if (((int[])ret)[0] != 4)
+ mVoiceNetworkStateRegistrants
+ .notifyRegistrants(new AsyncResult(null, null, null));
+ break;
+
+ }
+
+ }
+
+ protected Object
+ responseRegSuspended(Parcel p) {
+ int numInts;
+ int response[];
+
+ numInts = p.readInt();
+
+ response = new int[numInts];
+
+ for (int i = 0 ; i < numInts ; i++) {
+ response[i] = p.readInt();
+ }
+
+ RILRequest rr = RILRequest.obtain(RIL_REQUEST_RESUME_REGISTRATION, null);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + localRequestToString(rr.mRequest)
+ + " sessionId " + response[0]);
+
+ rr.mParcel.writeInt(1);
+ rr.mParcel.writeInt(response[0]);
+
+ send(rr);
+
+ return response;
+ }
+
+ protected Object
+ responseIncomingCallIndication(Parcel p) {
+ String response[];
+
+ response = p.readStringArray();
+
+ RILRequest rr = RILRequest.obtain(RIL_REQUEST_SET_CALL_INDICATION, null);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + localRequestToString(rr.mRequest));
+
+ rr.mParcel.writeInt(3);
+ rr.mParcel.writeInt(Integer.parseInt(response[3]));
+ rr.mParcel.writeInt(Integer.parseInt(response[0]));
+ rr.mParcel.writeInt(Integer.parseInt(response[4]));
+ send(rr);
+
+ return response;
+ }
+
+ protected Object
+ responseCallProgress(Parcel p) {
+ String response[];
+
+ response = p.readStringArray();
+
+ if (response.length >= 2) {
+ if (response[1].equals("129")) { // Call termination
+ return null;
+ }
+ }
+ return response;
+ }
+
+ @Override
+ public void setInitialAttachApn(String apn, String protocol, int authType, String username,
+ String password, Message result) {
+ RILRequest rr = RILRequest.obtain(RIL_REQUEST_SET_INITIAL_ATTACH_APN, null);
+
+ String operatorNumber = mTelephonyManager.getSimOperatorNumericForPhone(mInstanceId);
+ if (RILJ_LOGD) { riljLog("Set RIL_REQUEST_SET_INITIAL_ATTACH_APN"); }
+
+ rr.mParcel.writeString(apn);
+ rr.mParcel.writeString(protocol);
+ rr.mParcel.writeInt(authType);
+ rr.mParcel.writeString(username);
+ rr.mParcel.writeString(password);
+
+ rr.mParcel.writeString(operatorNumber);
+ rr.mParcel.writeInt(1);
+ rr.mParcel.writeStringArray(null);
+
+ if (RILJ_LOGD) { riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+ + ", apn:" + apn + ", protocol:" + protocol + ", authType:" + authType
+ + ", username:" + username + ", password:" + password + ", operator:" + operatorNumber);
+ }
+
+ send(rr);
+ }
+
+ protected Object
+ responseSetAttachApn(Parcel p) {
+ // The stack refuses to attach to LTE unless an IA APN was set, and
+ // will loop until it happens. Set an empty one to unblock.
+ setInitialAttachApn("","",0,"","",null);
+ return null;
+ }
+
+ @Override
+ protected Object
+ responseSimRefresh(Parcel p) {
+ IccRefreshResponse response = new IccRefreshResponse();
+
+ response.refreshResult = p.readInt();
+ String rawefId = p.readString();
+ response.efId = rawefId == null ? 0 : Integer.parseInt(rawefId);
+ response.aid = p.readString();
+
+ return response;
+ }
+
+ @Override
+ public void
+ setupDataCall(int radioTechnology, int profile, String apn,
+ String user, String password, int authType, String protocol,
+ Message result) {
+ int interfaceId=0;
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_SETUP_DATA_CALL, result);
+
+ rr.mParcel.writeInt(8); //bumped by one
+
+ rr.mParcel.writeString(Integer.toString(radioTechnology));
+ rr.mParcel.writeString(Integer.toString(profile));
+ rr.mParcel.writeString(apn);
+ rr.mParcel.writeString(user);
+ rr.mParcel.writeString(password);
+ rr.mParcel.writeString(Integer.toString(authType));
+ rr.mParcel.writeString(protocol);
+
+ /* Find the first available interfaceId */
+ for (int i=0; i < 4; i++) {
+ if (dataCallCids[i] < 0) {
+ interfaceId = i+1;
+ break;
+ }
+ }
+ rr.mParcel.writeString(interfaceId+"");
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> "
+ + requestToString(rr.mRequest) + " " + radioTechnology + " "
+ + profile + " " + apn + " " + user + " "
+ + password + " " + authType + " " + protocol + " " + interfaceId);
+
+ send(rr);
+ }
+
+ @Override
+ public void
+ deactivateDataCall(int cid, int reason, Message result) {
+ for (int i=0; i < 4; i++) {
+ if (dataCallCids[i] == cid) {
+ dataCallCids[i] = -1;
+ break;
+ }
+ }
+ super.deactivateDataCall(cid, reason, result);
+ }
+
+ @Override
+ public void
+ dial(String address, int clirMode, UUSInfo uusInfo, Message result) {
+ if (mEccList.isEmergencyNumberExt(address)) {
+ int serviceCategory = mEccList.getServiceCategoryFromEcc(address);
+
+ RILRequest rr = RILRequest.obtain(RIL_REQUEST_SET_ECC_SERVICE_CATEGORY, null);
+
+ rr.mParcel.writeInt(1);
+ rr.mParcel.writeInt(serviceCategory);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + localRequestToString(rr.mRequest)
+ + " " + serviceCategory);
+
+ send(rr);
+
+
+ rr = RILRequest.obtain(RIL_REQUEST_EMERGENCY_DIAL, result);
+ rr.mParcel.writeString(address);
+ rr.mParcel.writeInt(clirMode);
+ rr.mParcel.writeInt(0); // UUS information is absent
+
+ if (uusInfo == null) {
+ rr.mParcel.writeInt(0); // UUS information is absent
+ } else {
+ rr.mParcel.writeInt(1); // UUS information is present
+ rr.mParcel.writeInt(uusInfo.getType());
+ rr.mParcel.writeInt(uusInfo.getDcs());
+ rr.mParcel.writeByteArray(uusInfo.getUserData());
+ }
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + localRequestToString(rr.mRequest));
+
+ send(rr);
+
+ } else {
+ super.dial(address, clirMode, uusInfo, result);
+ }
+ }
+
+ private void refreshEmergencyList() {
+ if (mEccList != null) mEccList.updateEmergencyNumbersProperty();
+ }
+
+ @Override
+ public void
+ setRadioPower(boolean on, Message result) {
+ boolean isInApm = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
+ boolean wasInApm = SystemProperties.get("persist.radio.airplane.mode.on").equals("true");
+
+ SystemProperties.set("persist.radio.airplane.mode.on", isInApm ? "true" : "false");
+
+ if (on && wasInApm && !isInApm) {
+ SystemProperties.set("gsm.ril.eboot", "0");
+ RILRequest rr = RILRequest.obtain(RIL_REQUEST_MODEM_POWERON, result);
+ if (RILJ_LOGD) {
+ riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+ }
+ send(rr);
+ } else if (!on && isInApm) {
+ SystemProperties.set("gsm.ril.eboot", "1");
+ RILRequest rr = RILRequest.obtain(RIL_REQUEST_MODEM_POWEROFF, result);
+ if (RILJ_LOGD) {
+ riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+ }
+ send(rr);
+ } else {
+ super.setRadioPower(on, result);
+ }
+ }
+
+ // Solicited request handling
+ @Override
+ protected RILRequest
+ processSolicited (Parcel p, int type) {
+ int serial, error;
+ int dataPosition = p.dataPosition(); // save off position within the Parcel
+ serial = p.readInt();
+ error = p.readInt();
+
+ RILRequest rr = null;
+
+ /* Pre-process the reply before popping it */
+ synchronized (mRequestList) {
+ RILRequest tr = mRequestList.get(serial);
+ if (tr != null && tr.mSerial == serial) {
+ if (error == 0 || p.dataAvail() > 0) {
+ try {switch (tr.mRequest) {
+ /* Get those we're interested in */
+ case RIL_REQUEST_EMERGENCY_DIAL:
+ case RIL_REQUEST_SET_ECC_SERVICE_CATEGORY:
+ case RIL_REQUEST_DATA_REGISTRATION_STATE:
+ case RIL_REQUEST_SETUP_DATA_CALL:
+ case RIL_REQUEST_ALLOW_DATA:
+ rr = tr;
+ break;
+ // vendor ril refreshes the properties while generating this answer. Do our own updates afterwards
+ case RIL_REQUEST_GET_SIM_STATUS: refreshEmergencyList(); // no break, we want the superclass to process this
+ }} catch (Throwable thr) {
+ // Exceptions here usually mean invalid RIL responses
+ if (tr.mResult != null) {
+ AsyncResult.forMessage(tr.mResult, null, thr);
+ tr.mResult.sendToTarget();
+ }
+ return tr;
+ }
+ }
+ }
+ }
+
+ if (rr == null) {
+ /* Nothing we care about, go up */
+ p.setDataPosition(dataPosition);
+
+ // Forward responses that we are not overriding to the super class
+ return super.processSolicited(p, type);
+ }
+
+
+ rr = findAndRemoveRequestFromList(serial);
+
+ if (rr == null) {
+ return rr;
+ }
+
+ Object ret = null;
+
+ if (error == 0 || p.dataAvail() > 0) {
+ switch (rr.mRequest) {
+ case RIL_REQUEST_EMERGENCY_DIAL: ret = responseVoid(p); break;
+ case RIL_REQUEST_SET_ECC_SERVICE_CATEGORY: ret = responseVoid(p); break;
+ case RIL_REQUEST_DATA_REGISTRATION_STATE: ret = fixupPSBearerDataRegistration(p); break;
+ case RIL_REQUEST_SETUP_DATA_CALL: ret = fetchCidFromDataCall(p); break;
+ case RIL_REQUEST_ALLOW_DATA: ret = responseVoid(p); mVoiceNetworkStateRegistrants.notifyRegistrants(new AsyncResult(null, null, null)); break;
+ default:
+ throw new RuntimeException("Shouldn't be here: " + rr.mRequest);
+ }
+ //break;
+ }
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "< " + requestToString(rr.mRequest)
+ + " " + retToString(rr.mRequest, ret));
+
+ if (rr.mResult != null) {
+ AsyncResult.forMessage(rr.mResult, ret, null);
+ rr.mResult.sendToTarget();
+ }
+
+ return rr;
+ }
+
+ private Object
+ fixupPSBearerDataRegistration(Parcel p) {
+ int num;
+ String response[];
+
+ response = p.readStringArray();
+
+ if (response.length >= 4 &&
+ response[3] != null &&
+ Integer.parseInt(response[3]) >= 128) {
+ // extended values >= RIL_RADIO_TECHNOLOGY_MTK (128) == HSPAP (15)
+ response[3] = "15";
+ }
+
+ return response;
+ }
+
+ private Object
+ fetchCidFromDataCall(Parcel p) {
+ DataCallResponse ret = (DataCallResponse)super.responseSetupDataCall(p);
+
+ if (ret.cid >= 0) {
+ for (int i = 0; i < 4; i++) {
+ if (dataCallCids[i] < 0) {
+ dataCallCids[i] = ret.cid;
+ break;
+ }
+ }
+ }
+ return ret;
+ }
+
+ @Override
+ public void
+ iccIOForApp (int command, int fileid, String path, int p1, int p2, int p3,
+ String data, String pin2, String aid, Message result) {
+ if (command == 0xc0 && p3 == 0) {
+ riljLog("Override the size for the COMMAND_GET_RESPONSE 0 => 15");
+ p3 = 15;
+ }
+ super.iccIOForApp(command, fileid, path, p1, p2, p3, data, pin2, aid, result);
+ }
+}
diff --git a/ril/telephony/java/com/android/internal/telephony/MtkEccList.java b/ril/telephony/java/com/android/internal/telephony/MtkEccList.java
new file mode 100755
index 0000000..9358231
--- /dev/null
+++ b/ril/telephony/java/com/android/internal/telephony/MtkEccList.java
@@ -0,0 +1,385 @@
+/*
+ * Copyright (C) 2014 MediaTek Inc.
+ */
+
+/*
+ * Copyright (C) 2016 The CyanogenMod 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;
+
+import android.os.SystemProperties;
+
+import android.telephony.PhoneNumberUtils;
+import android.telephony.Rlog;
+
+import android.text.TextUtils;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParserFactory;
+import java.io.FileReader;
+import java.io.IOException;
+
+public class MtkEccList extends PhoneNumberUtils {
+
+ static final String LOG_TAG = "MtkEccList";
+
+ private static ArrayList<EccEntry> mCustomizedEccList = null;
+ private static HashMap<String, Integer> mHashMapForNetworkEccCategory = null;
+ private static boolean sIsCtaSet = true;
+
+ //***** Constructor
+ public MtkEccList() {
+ sIsCtaSet = "1".equals(SystemProperties.get("ro.mtk_cta_set"));
+ mCustomizedEccList = new ArrayList<EccEntry>();
+ parseEccList();
+ mHashMapForNetworkEccCategory = new HashMap<String, Integer>();
+ }
+
+ /** @hide */
+ public static class EccEntry {
+ public static final String ECC_LIST_PATH = "/system/etc/ecc_list.xml";
+ public static final String ECC_ENTRY_TAG = "EccEntry";
+ public static final String ECC_ATTR = "Ecc";
+ public static final String CATEGORY_ATTR = "Category";
+ public static final String CONDITION_ATTR = "Condition";
+
+ public static final String ECC_NO_SIM = "0";
+ public static final String ECC_ALWAYS = "1";
+ public static final String ECC_FOR_MMI = "2";
+
+ private String mEcc;
+ private String mCategory;
+ private String mCondition; // ECC_NO_SIM, ECC_ALWAYS, or ECC_FOR_MMI
+
+ public EccEntry() {
+ mEcc = new String("");
+ mCategory = new String("");
+ mCondition = new String("");
+ }
+
+ public void setEcc(String strEcc) {
+ mEcc = strEcc;
+ }
+ public void setCategory(String strCategory) {
+ mCategory = strCategory;
+ }
+ public void setCondition(String strCondition) {
+ mCondition = strCondition;
+ }
+
+ public String getEcc() {
+ return mEcc;
+ }
+ public String getCategory() {
+ return mCategory;
+ }
+ public String getCondition() {
+ return mCondition;
+ }
+
+ @Override
+ public String toString() {
+ return ("\n" + ECC_ATTR + "=" + getEcc() + ", " + CATEGORY_ATTR + "="
+ + getCategory() + ", " + CONDITION_ATTR + "=" + getCondition());
+ }
+ }
+
+ /**
+ * Parse Ecc List From XML File
+ *
+ * @param none.
+ * @return none.
+ * @hide
+ */
+ private static void parseEccList() {
+ mCustomizedEccList.clear();
+
+ // Parse GSM ECC list
+ try {
+ XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
+ XmlPullParser parser = factory.newPullParser();
+ if (parser == null) {
+ Rlog.d(LOG_TAG, "XmlPullParserFactory.newPullParser() return null");
+ return;
+ }
+ FileReader fileReader = new FileReader(EccEntry.ECC_LIST_PATH);
+ parser.setInput(fileReader);
+ int eventType = parser.getEventType();
+ EccEntry record = null;
+
+ while (eventType != XmlPullParser.END_DOCUMENT) {
+ switch (eventType) {
+ case XmlPullParser.START_TAG:
+ if (parser.getName().equals(EccEntry.ECC_ENTRY_TAG)) {
+ record = new EccEntry();
+ int attrNum = parser.getAttributeCount();
+ for (int i = 0; i < attrNum; ++i) {
+ String name = parser.getAttributeName(i);
+ String value = parser.getAttributeValue(i);
+ if (name.equals(EccEntry.ECC_ATTR))
+ record.setEcc(value);
+ else if (name.equals(EccEntry.CATEGORY_ATTR))
+ record.setCategory(value);
+ else if (name.equals(EccEntry.CONDITION_ATTR))
+ record.setCondition(value);
+ }
+ }
+ break;
+ case XmlPullParser.END_TAG:
+ if (parser.getName().equals(EccEntry.ECC_ENTRY_TAG) && record != null)
+ mCustomizedEccList.add(record);
+ break;
+ }
+ eventType = parser.next();
+ }
+ fileReader.close();
+
+ if (sIsCtaSet) {
+ String [] emergencyCTAList = {"120", "122", "110", "119"};
+ for (String emergencyNum : emergencyCTAList) {
+ record = new EccEntry();
+ record.setEcc(emergencyNum);
+ record.setCategory("0");
+ record.setCondition(EccEntry.ECC_FOR_MMI);
+
+ boolean bFound = false;
+ int nIndex = 0;
+ for (EccEntry eccEntry : mCustomizedEccList) {
+ String ecc = eccEntry.getEcc();
+ if (ecc.equals(emergencyNum)) {
+ bFound = true;
+ Rlog.d(LOG_TAG, "[parseEccList]"
+ + "CTA ecc match customized ecc list, ecc=" + ecc);
+ break;
+ }
+ nIndex++;
+ }
+
+ if (bFound)
+ mCustomizedEccList.set(nIndex, record);
+ else
+ mCustomizedEccList.add(record);
+ }
+ }
+ } catch (XmlPullParserException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static boolean isEmergencyNumberExt(String number) {
+ Rlog.d(LOG_TAG, "[isEmergencyNumberExt], number:" + number );
+ if (number == null) {
+ return false;
+ }
+ String numberPlus = null;
+ boolean bSIMInserted = false;
+
+ // Strip the separators from the number before comparing it
+ // to the list.
+ number = extractNetworkPortionAlt(number);
+
+ // 1. Check ECCs updated by network
+ mHashMapForNetworkEccCategory.clear();
+ String strEccCategoryList = SystemProperties.get("ril.ecc.service.category.list");
+ if (!TextUtils.isEmpty(strEccCategoryList)) {
+ for (String strEccCategory : strEccCategoryList.split(";")) {
+ if (!strEccCategory.isEmpty()) {
+ String[] strEccCategoryAry = strEccCategory.split(",");
+ if (2 == strEccCategoryAry.length) {
+ mHashMapForNetworkEccCategory.put(strEccCategoryAry[0],
+ Integer.parseInt(strEccCategoryAry[1]));
+ }
+ }
+ }
+ }
+ for (String emergencyNum : mHashMapForNetworkEccCategory.keySet()) {
+ numberPlus = emergencyNum + "+";
+ if (emergencyNum.equals(number)
+ || numberPlus.equals(number)) {
+ Rlog.d(LOG_TAG, "[isEmergencyNumberExt] match network ecc list");
+ return true;
+ }
+ }
+ // 2. Check ECCs stored at SIMs
+ // Read from SIM1
+ String numbers = SystemProperties.get("ril.ecclist");
+ Rlog.d(LOG_TAG, "[isEmergencyNumberExt] ril.ecclist: " + numbers);
+ if (!TextUtils.isEmpty(numbers)) {
+ // searches through the comma-separated list for a match,
+ // return true if one is found.
+ for (String emergencyNum : numbers.split(",")) {
+ numberPlus = emergencyNum + "+";
+ if (emergencyNum.equals(number)
+ || numberPlus.equals(number)) {
+ Rlog.d(LOG_TAG, "[isEmergencyNumberExt] match ril.ecclist");
+ return true;
+ }
+ }
+ bSIMInserted = true;
+ }
+
+ // Read from SIM2
+ numbers = SystemProperties.get("ril.ecclist1");
+ Rlog.d(LOG_TAG, "[isEmergencyNumberExt] ril.ecclist1: " + numbers);
+ if (!TextUtils.isEmpty(numbers)) {
+ // searches through the comma-separated list for a match,
+ // return true if one is found.
+ for (String emergencyNum : numbers.split(",")) {
+ numberPlus = emergencyNum + "+";
+ if (emergencyNum.equals(number)
+ || numberPlus.equals(number)) {
+ Rlog.d(LOG_TAG, "[isEmergencyNumberExt] match ril.ecclist1");
+ return true;
+ }
+ }
+ bSIMInserted = true;
+ }
+
+ // 3. Check ECCs customized by user
+ if (bSIMInserted) {
+ if (mCustomizedEccList != null) {
+ for (EccEntry eccEntry : mCustomizedEccList) {
+ if (!eccEntry.getCondition().equals(EccEntry.ECC_NO_SIM)) {
+ String ecc = eccEntry.getEcc();
+ numberPlus = ecc + "+";
+ if (ecc.equals(number)
+ || numberPlus.equals(number)) {
+ Rlog.d(LOG_TAG, "[isEmergencyNumberExt] match"
+ + " customized ecc list");
+ return true;
+ }
+ }
+ }
+ }
+ } else {
+ if (mCustomizedEccList != null) {
+ for (EccEntry eccEntry : mCustomizedEccList) {
+ String ecc = eccEntry.getEcc();
+ numberPlus = ecc + "+";
+ if (ecc.equals(number)
+ || numberPlus.equals(number)) {
+ Rlog.d(LOG_TAG, "[isEmergencyNumberExt] match"
+ + " customized ecc list when no sim");
+ return true;
+ }
+ }
+ }
+ }
+ Rlog.d(LOG_TAG, "[isEmergencyNumberExt] no match");
+ return false;
+ }
+
+ /**
+ * Get the service category for the given ECC number.
+ * @param number The ECC number.
+ * @return The service category for the given number.
+ * @hide
+ */
+ public static int getServiceCategoryFromEcc(String number) {
+ String numberPlus = null;
+
+ // 1. Get category from network
+ for (String emergencyNum : mHashMapForNetworkEccCategory.keySet()) {
+ numberPlus = emergencyNum + "+";
+ if (emergencyNum.equals(number)
+ || numberPlus.equals(number)) {
+ Integer nSC = mHashMapForNetworkEccCategory.get(emergencyNum);
+ if (nSC != null) {
+ Rlog.d(LOG_TAG, "[getServiceCategoryFromEcc] match network ecc list, "
+ + "Ecc= " + number + ", Category= " + nSC);
+ return nSC;
+ }
+ }
+ }
+
+ // 2. Get category from sim
+ // ToDo: EF_Ecc will convey service category later
+
+ // 3. Get category from user-customized
+ if (mCustomizedEccList != null) {
+ for (EccEntry eccEntry : mCustomizedEccList) {
+ String ecc = eccEntry.getEcc();
+ numberPlus = ecc + "+";
+ if (ecc.equals(number)
+ || numberPlus.equals(number)) {
+ Rlog.d(LOG_TAG, "[getServiceCategoryFromEcc] match customized ecc list, "
+ + "Ecc= " + ecc + ", Category= " + eccEntry.getCategory());
+ return Integer.parseInt(eccEntry.getCategory());
+ }
+ }
+ }
+
+ Rlog.d(LOG_TAG, "[getServiceCategoryFromEcc] no matched for Ecc =" + number + ", return 0");
+ return 0;
+ }
+
+ public static void updateEmergencyNumbersProperty() {
+ ArrayList<String> sim1List = new ArrayList<String>();
+ ArrayList<String> sim2List = new ArrayList<String>();
+ ArrayList<String> fixedList = new ArrayList<String>();
+ ArrayList<String> fixedListNoSim = new ArrayList<String>();
+
+ if (mCustomizedEccList != null) {
+ for (EccEntry eccEntry : mCustomizedEccList) {
+ String ecc = eccEntry.getEcc();
+ if (!eccEntry.getCondition().equals(EccEntry.ECC_NO_SIM)) {
+ fixedList.add(ecc);
+ } else if (!TextUtils.isEmpty(ecc)) {
+ fixedListNoSim.add(ecc);
+ }
+ }
+ }
+
+ // Read from SIM1
+ String numbers = SystemProperties.get("ril.ecclist");
+ for (String emergencyNum : numbers.split(",")) {
+ if (!TextUtils.isEmpty(emergencyNum))
+ sim1List.add(emergencyNum);
+ }
+ // dedupe
+ sim1List.removeAll(fixedList);
+ sim1List.addAll(fixedList);
+ if (TextUtils.isEmpty(numbers)) {
+ sim1List.removeAll(fixedListNoSim);
+ sim1List.addAll(fixedListNoSim);
+ }
+ SystemProperties.set("ril.ecclist",TextUtils.join(",", sim1List));
+
+ // Read from SIM2
+ numbers = SystemProperties.get("ril.ecclist1");
+ for (String emergencyNum : numbers.split(",")) {
+ if (!TextUtils.isEmpty(emergencyNum))
+ sim2List.add(emergencyNum);
+ }
+ // dedupe
+ sim2List.removeAll(fixedList);
+ sim2List.addAll(fixedList);
+ if (TextUtils.isEmpty(numbers)) {
+ sim2List.removeAll(fixedListNoSim);
+ sim2List.addAll(fixedListNoSim);
+ }
+ SystemProperties.set("ril.ecclist1",TextUtils.join(",", sim2List));
+
+ }
+
+}