diff options
| author | Arne Coucheron <arco68@gmail.com> | 2017-10-24 10:36:46 +0200 |
|---|---|---|
| committer | doc HD <doc.divxm@gmail.com> | 2017-10-25 07:32:19 +0300 |
| commit | 659af83ca650cf3a94d18dd7d070517a7f50dc12 (patch) | |
| tree | 1e1c2c20b3e4c77bcf529cf20fe0ee9b78bd3187 | |
| parent | 13ccc9f190c5b0cd02bd90e40137d252ffc74733 (diff) | |
ril: Add CDMA support in custom RIL class
Shamelessly kanged from jf. No idea if everything is needed,
but tester says his phone is working with this.
Change-Id: Ie091de0160788ca86d88907ab0142a34a1bc42e2
| -rw-r--r-- | ril/Operators.java | 140 | ||||
| -rw-r--r-- | ril/SerranoRIL.java | 196 |
2 files changed, 318 insertions, 18 deletions
diff --git a/ril/Operators.java b/ril/Operators.java new file mode 100644 index 0000000..522e0bf --- /dev/null +++ b/ril/Operators.java @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2013-2016, The CyanogenMod Project + * Copyright (C) 2017, 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; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.util.Collections; +import java.util.Map; +import java.util.HashMap; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import android.os.Environment; +import android.telephony.Rlog; +import android.util.Xml; + +import com.android.internal.util.XmlUtils; + +public class Operators { + // Initialize list of Operator codes + // This will be taken care of when garbage collection starts. + private HashMap<String, String> initList() { + HashMap<String, String> init = new HashMap<String, String>(); + // Taken from spnOveride.java + FileReader spnReader; + final File spnFile = new File(Environment.getRootDirectory(), "etc/selective-spn-conf.xml"); + + try { + spnReader = new FileReader(spnFile); + } catch (FileNotFoundException e) { + Rlog.w("Operatorcheck", "Can not open " + + Environment.getRootDirectory() + "/etc/selective-spn-conf.xml"); + return init; + } + + try { + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(spnReader); + + XmlUtils.beginDocument(parser, "spnOverrides"); + + while (true) { + XmlUtils.nextElement(parser); + + String name = parser.getName(); + if (!"spnOverride".equals(name)) { + break; + } + + String numeric = parser.getAttributeValue(null, "numeric"); + String data = parser.getAttributeValue(null, "spn"); + + init.put(numeric, data); + } + } catch (XmlPullParserException e) { + Rlog.w("Operatorcheck", "Exception in spn-conf parser " + e); + } catch (IOException e) { + Rlog.w("Operatorcheck", "Exception in spn-conf parser " + e); + } + return init; + } + + // This will stay persistant in memory when called + private static String stored = null; + private static String storedOperators = null; + + public static String operatorReplace(String response) { + // Sanity checking if the value is actually not equal to the range apn Numerics + // If it is null, check your ril class. + if(response == null || (5 != response.length() && response.length() != 6)) { + return response; + } + // This will check if the stored value is equal to other. + // This uses a technique called last known of good value along with sanity checking. + if(storedOperators != null && stored != null && stored.equals(response)) { + return storedOperators; + } + stored = response; + try { + // This will find out if it a number then it will catch it based on invalid chars. + Integer.parseInt(response); + } catch(NumberFormatException E) { + // Not a number, pass it along to stored operator until the next round. + storedOperators = response; + return storedOperators; + } + // This code will be taking care of when garbage collection start + Operators init = new Operators(); + Map<String, String> operators = init.initList(); + storedOperators = operators.containsKey(response) ? operators.get(response) : response; + return storedOperators; + } + + // This will not stay persistant in memory, this will be taken care of in garbage collection + // routine. + private Map<String, String> unOptOperators = null; + // Unoptimized version of operatorReplace for responseOperatorInfos this will provide a little + // more flexiblilty in a loop like situation. + // Same numbers of checks as before. This is for the search network functionality + public String unOptimizedOperatorReplace(String response) { + // Sanity checking if the value is actually not equal to the range apn numerics. + // if it is null, check your ril class. + if(response == null || + (5 != response.length() && response.length() != 6)) { + return response; + } + + try { + // This will find out if it a number then it will catch it based on invalid chars. + Integer.parseInt(response); + } catch(NumberFormatException E) { + // An illegal char is found i.e a word + return response; + } + + if (unOptOperators == null) { + unOptOperators = initList(); + } + + return unOptOperators.containsKey(response) ? unOptOperators.get(response) : response; + } +} diff --git a/ril/SerranoRIL.java b/ril/SerranoRIL.java index 68fa0b4..2bef761 100644 --- a/ril/SerranoRIL.java +++ b/ril/SerranoRIL.java @@ -24,10 +24,15 @@ import android.telephony.Rlog; import android.os.AsyncResult; import android.os.Message; import android.os.Parcel; +import android.os.SystemClock; import android.os.SystemProperties; import android.telephony.ModemActivityInfo; import android.telephony.PhoneNumberUtils; import android.telephony.SignalStrength; +import com.android.internal.telephony.cdma.CdmaInformationRecords; +import com.android.internal.telephony.cdma.CdmaInformationRecords.CdmaSignalInfoRec; +import com.android.internal.telephony.cdma.SignalToneUtil; +import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo; import com.android.internal.telephony.uicc.IccCardApplicationStatus; import com.android.internal.telephony.uicc.IccCardStatus; import com.android.internal.telephony.uicc.IccUtils; @@ -35,7 +40,7 @@ import java.util.ArrayList; import java.util.Collections; /** - * RIL customization for Galaxy S4 Mini (GSM) devices + * RIL customization for Galaxy S4 Mini (GSM/CDMA) devices * * {@hide} */ @@ -51,6 +56,11 @@ public class SerranoRIL extends RIL { private static final int RIL_UNSOL_STK_CC_ALPHA_NOTIFY_SAMSUNG = 1041; private static final int RIL_UNSOL_UICC_SUBSCRIPTION_STATUS_CHANGED_SAMSUNG = 11031; + private Object mSMSLock = new Object(); + private boolean mIsSendingSMS = false; + public static final long SEND_SMS_TIMEOUT_IN_MS = 30000; + protected boolean isGSM = false; + public SerranoRIL(Context context, int preferredNetworkType, int cdmaSubscription) { this(context, preferredNetworkType, cdmaSubscription, null); } @@ -132,10 +142,58 @@ public class SerranoRIL extends RIL { } @Override + public void + sendCdmaSms(byte[] pdu, Message result) { + smsLock(); + super.sendCdmaSms(pdu, result); + } + + @Override + public void + sendSMS (String smscPDU, String pdu, Message result) { + smsLock(); + super.sendSMS(smscPDU, pdu, result); + } + + @Override + protected Object + responseSMS(Parcel p) { + // Notify that sendSMS() can send the next SMS + synchronized (mSMSLock) { + mIsSendingSMS = false; + mSMSLock.notify(); + } + + return super.responseSMS(p); + } + + private void smsLock(){ + // Do not send a new SMS until the response for the previous SMS has been received + // * for the error case where the response never comes back, time out after + // 30 seconds and just try the next SEND_SMS + synchronized (mSMSLock) { + long timeoutTime = SystemClock.elapsedRealtime() + SEND_SMS_TIMEOUT_IN_MS; + long waitTimeLeft = SEND_SMS_TIMEOUT_IN_MS; + while (mIsSendingSMS && (waitTimeLeft > 0)) { + Rlog.d(RILJ_LOG_TAG, "sendSMS() waiting for response of previous SEND_SMS"); + try { + mSMSLock.wait(waitTimeLeft); + } catch (InterruptedException ex) { + // ignore the interrupt and rewait for the remainder + } + waitTimeLeft = timeoutTime - SystemClock.elapsedRealtime(); + } + if (waitTimeLeft <= 0) { + Rlog.e(RILJ_LOG_TAG, "sendSms() timed out waiting for response of previous CDMA_SEND_SMS"); + } + mIsSendingSMS = true; + } + } + + @Override protected Object responseCallList(Parcel p) { int num; - int voiceSettings; ArrayList<DriverCall> response; DriverCall dc; @@ -156,12 +214,13 @@ public class SerranoRIL extends RIL { dc.isMpty = (0 != p.readInt()); dc.isMT = (0 != p.readInt()); dc.als = p.readInt(); - voiceSettings = p.readInt(); - dc.isVoice = (0 == voiceSettings) ? false : true; - boolean isVideo = (0 != p.readInt()); // Samsung CallDetails - int call_type = p.readInt(); // Samsung CallDetails - int call_domain = p.readInt(); // Samsung CallDetails - String csv = p.readString(); // Samsung CallDetails + dc.isVoice = (0 != p.readInt()); + if (isGSM) { + boolean isVideo = (0 != p.readInt()); // Samsung CallDetails + int call_type = p.readInt(); // Samsung CallDetails + int call_domain = p.readInt(); // Samsung CallDetails + String csv = p.readString(); // Samsung CallDetails + } dc.isVoicePrivacy = (0 != p.readInt()); dc.number = p.readString(); int np = p.readInt(); @@ -236,6 +295,12 @@ public class SerranoRIL extends RIL { } @Override + public void setPhoneType(int phoneType){ + super.setPhoneType(phoneType); + isGSM = (phoneType != RILConstants.CDMA_PHONE); + } + + @Override protected RILRequest processSolicited (Parcel p, int type) { int serial, error; @@ -251,7 +316,9 @@ public class SerranoRIL extends RIL { if (error == 0 || p.dataAvail() > 0) { try {switch (tr.mRequest) { /* Get those we're interested in */ + case RIL_REQUEST_VOICE_REGISTRATION_STATE: case RIL_REQUEST_DATA_REGISTRATION_STATE: + case RIL_REQUEST_OPERATOR: rr = tr; break; }} catch (Throwable thr) { @@ -278,7 +345,9 @@ public class SerranoRIL extends RIL { Object ret = null; if (error == 0 || p.dataAvail() > 0) { switch (rr.mRequest) { - case RIL_REQUEST_DATA_REGISTRATION_STATE: ret = responseDataRegistrationState(p); break; + case RIL_REQUEST_VOICE_REGISTRATION_STATE: ret = responseVoiceDataRegistrationState(p, false); break; + case RIL_REQUEST_DATA_REGISTRATION_STATE: ret = responseVoiceDataRegistrationState(p, true); break; + case RIL_REQUEST_OPERATOR: ret = operatorCheck(p); break; default: throw new RuntimeException("Unrecognized solicited response: " + rr.mRequest); } @@ -294,20 +363,45 @@ public class SerranoRIL extends RIL { } private Object - responseDataRegistrationState(Parcel p) { + operatorCheck(Parcel p) { String response[] = (String[])responseStrings(p); - /* DANGER WILL ROBINSON - * In some cases from Vodaphone we are receiving a RAT of 102 - * while in tunnels of the metro. Lets Assume that if we - * receive 102 we actually want a RAT of 2 for EDGE service */ - if (response.length > 4 && - response[0].equals("1") && - response[3].equals("102")) { - response[3] = "2"; + for(int i=0; i<2; i++){ + if (response[i]!= null){ + response[i] = Operators.operatorReplace(response[i]); + } } return response; } + private Object + responseVoiceDataRegistrationState(Parcel p, boolean data) { + String response[] = (String[])responseStrings(p); + if (isGSM){ + if (data && + response.length > 4 && + response[0].equals("1") && + response[3].equals("102")) { + response[3] = "2"; + } + return response; + } + if (response.length>=10){ + for(int i=6; i<=9; i++){ + if (response[i]== null){ + response[i]=Integer.toString(Integer.MAX_VALUE); + } else { + try { + Integer.parseInt(response[i]); + } catch(NumberFormatException e) { + response[i]=Integer.toString(Integer.parseInt(response[i],16)); + } + } + } + } + + return response; + } + private void fixNitz(Parcel p) { int dataPosition = p.dataPosition(); @@ -334,6 +428,15 @@ public class SerranoRIL extends RIL { int response = p.readInt(); switch(response) { + case RIL_UNSOL_RIL_CONNECTED: + ret = responseInts(p); + setRadioPower(false, null); + setPreferredNetworkType(mPreferredNetworkType, null); + setCdmaSubscriptionSource(mCdmaSubscription, null); + if(mRilVersion >= 8) + setCellInfoListRate(Integer.MAX_VALUE, null); + notifyRegistrantsRilConnectionChanged(((int[])ret)[0]); + break; case RIL_UNSOL_NITZ_TIME_RECEIVED: fixNitz(p); p.setDataPosition(dataPosition); @@ -376,6 +479,63 @@ public class SerranoRIL extends RIL { } } + // Workaround for Samsung CDMA "ring of death" bug: + // + // Symptom: As soon as the phone receives notice of an incoming call, an + // audible "old fashioned ring" is emitted through the earpiece and + // persists through the duration of the call, or until reboot if the call + // isn't answered. + // + // Background: The CDMA telephony stack implements a number of "signal info + // tones" that are locally generated by ToneGenerator and mixed into the + // voice call path in response to radio RIL_UNSOL_CDMA_INFO_REC requests. + // One of these tones, IS95_CONST_IR_SIG_IS54B_L, is requested by the + // radio just prior to notice of an incoming call when the voice call + // path is muted. CallNotifier is responsible for stopping all signal + // tones (by "playing" the TONE_CDMA_SIGNAL_OFF tone) upon receipt of a + // "new ringing connection", prior to unmuting the voice call path. + // + // Problem: CallNotifier's incoming call path is designed to minimize + // latency to notify users of incoming calls ASAP. Thus, + // SignalInfoTonePlayer requests are handled asynchronously by spawning a + // one-shot thread for each. Unfortunately the ToneGenerator API does + // not provide a mechanism to specify an ordering on requests, and thus, + // unexpected thread interleaving may result in ToneGenerator processing + // them in the opposite order that CallNotifier intended. In this case, + // playing the "signal off" tone first, followed by playing the "old + // fashioned ring" indefinitely. + // + // Solution: An API change to ToneGenerator is required to enable + // SignalInfoTonePlayer to impose an ordering on requests (i.e., drop any + // request that's older than the most recent observed). Such a change, + // or another appropriate fix should be implemented in AOSP first. + // + // Workaround: Intercept RIL_UNSOL_CDMA_INFO_REC requests from the radio, + // check for a signal info record matching IS95_CONST_IR_SIG_IS54B_L, and + // drop it so it's never seen by CallNotifier. If other signal tones are + // observed to cause this problem, they should be dropped here as well. + @Override + protected void notifyRegistrantsCdmaInfoRec(CdmaInformationRecords infoRec) { + final int response = RIL_UNSOL_CDMA_INFO_REC; + + if (infoRec.record instanceof CdmaSignalInfoRec) { + CdmaSignalInfoRec sir = (CdmaSignalInfoRec) infoRec.record; + if (sir != null + && sir.isPresent + && sir.signalType == SignalToneUtil.IS95_CONST_IR_SIGNAL_IS54B + && sir.alertPitch == SignalToneUtil.IS95_CONST_IR_ALERT_MED + && sir.signal == SignalToneUtil.IS95_CONST_IR_SIG_IS54B_L) { + + Rlog.d(RILJ_LOG_TAG, "Dropping \"" + responseToString(response) + " " + + retToString(response, sir) + + "\" to prevent \"ring of death\" bug."); + return; + } + } + + super.notifyRegistrantsCdmaInfoRec(infoRec); + } + private void dialEmergencyCall(String address, int clirMode, Message result) { RILRequest rr; |
