From 0e37fe5ce25b1868831ddd865a19b0dcb4a1eb9a Mon Sep 17 00:00:00 2001 From: RGIB Date: Thu, 15 Dec 2016 18:44:48 +0100 Subject: i9305 : use custom smdk4x12QComRIL for opensource RIL Change-Id: I5b146df9d408a55c204f06632b0575b3b12c30ff --- BoardConfig.mk | 3 +- i9305.mk | 5 +- .../com/android/internal/telephony/Operators.java | 151 +++++ .../internal/telephony/smdk4x12QComRIL.java | 665 +++++++++++++++++++++ 4 files changed, 821 insertions(+), 3 deletions(-) create mode 100644 ril/telephony/java/com/android/internal/telephony/Operators.java create mode 100644 ril/telephony/java/com/android/internal/telephony/smdk4x12QComRIL.java diff --git a/BoardConfig.mk b/BoardConfig.mk index 664a3ee..013a89b 100644 --- a/BoardConfig.mk +++ b/BoardConfig.mk @@ -44,6 +44,7 @@ RECOVERY_FSTAB_VERSION := 2 # RIL BOARD_PROVIDES_LIBRIL := true BOARD_MODEM_TYPE := mdm9x35 +BOARD_RIL_CLASS := ../../../device/samsung/i9305/ril # assert TARGET_OTA_ASSERT_DEVICE := m3,m3xx,i9305,GT-I9305 @@ -53,4 +54,4 @@ TARGET_OTA_ASSERT_DEVICE := m3,m3xx,i9305,GT-I9305 # Selinux BOARD_SEPOLICY_DIRS += \ - device/samsung/i9305/selinux + device/samsung/i9305/selinux \ No newline at end of file diff --git a/i9305.mk b/i9305.mk index 77134aa..9cc54c6 100644 --- a/i9305.mk +++ b/i9305.mk @@ -58,7 +58,8 @@ PRODUCT_PACKAGES += \ libsecril-client-sap PRODUCT_PROPERTY_OVERRIDES += \ - mobiledata.interfaces=pdp0,gprs,ppp0,rmnet0,rmnet1 + mobiledata.interfaces=pdp0,gprs,ppp0,rmnet0,rmnet1 \ + ro.telephony.ril_class=smdk4x12QComRIL # Sensors PRODUCT_PACKAGES += \ @@ -97,4 +98,4 @@ $(call inherit-product, vendor/samsung/i9305/i9305-vendor.mk) # Include common makefile $(call inherit-product, device/samsung/smdk4412-common/common.mk) -$(call inherit-product, device/samsung/smdk4412-qcom-common/common.mk) +$(call inherit-product, device/samsung/smdk4412-qcom-common/common.mk) \ No newline at end of file diff --git a/ril/telephony/java/com/android/internal/telephony/Operators.java b/ril/telephony/java/com/android/internal/telephony/Operators.java new file mode 100644 index 0000000..51359ed --- /dev/null +++ b/ril/telephony/java/com/android/internal/telephony/Operators.java @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2013-2014 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 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 initList() { + HashMap init = new HashMap(); + //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 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 + // iin garbage collection routiene. + private Map unOptOperators = null; + // unoptimized version of operatorreplace for responseOperatorInfos + // this will provide a little more flexiblilty in a loop like sisuation + // same numbers of checks like 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/telephony/java/com/android/internal/telephony/smdk4x12QComRIL.java b/ril/telephony/java/com/android/internal/telephony/smdk4x12QComRIL.java new file mode 100644 index 0000000..8fbc6ef --- /dev/null +++ b/ril/telephony/java/com/android/internal/telephony/smdk4x12QComRIL.java @@ -0,0 +1,665 @@ +/* + * Copyright (C) 2012-2014 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 android.content.Context; +import android.media.AudioManager; +import android.os.AsyncResult; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.os.Message; +import android.os.Parcel; +import android.telephony.SmsMessage; +import android.os.SystemProperties; +import android.os.SystemClock; +import android.provider.Settings; +import android.text.TextUtils; +import android.telephony.Rlog; + +import android.telephony.SignalStrength; + +import android.telephony.PhoneNumberUtils; +import com.android.internal.telephony.RILConstants; +import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo; +import com.android.internal.telephony.cdma.CdmaInformationRecords; +import com.android.internal.telephony.cdma.CdmaInformationRecords.CdmaSignalInfoRec; +import com.android.internal.telephony.cdma.SignalToneUtil; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; + +import com.android.internal.telephony.uicc.IccCardApplicationStatus; +import com.android.internal.telephony.uicc.IccCardStatus; + +/** + * Qualcomm RIL for the Samsung family. + * Quad core Exynos4 with Qualcomm modem and later is supported + * Snapdragon S3 and later is supported + * This RIL is univerisal meaning it supports CDMA and GSM radio. + * Handles most GSM and CDMA cases. + * {@hide} + */ +public class smdk4x12QComRIL extends RIL implements CommandsInterface { + + private boolean setPreferredNetworkTypeSeen = false; + + private AudioManager mAudioManager; + + private Object mSMSLock = new Object(); + private boolean mIsSendingSMS = false; + protected boolean isGSM = false; + public static final long SEND_SMS_TIMEOUT_IN_MS = 30000; + + public smdk4x12QComRIL(Context context, int networkModes, int cdmaSubscription) { + this(context, networkModes, cdmaSubscription, null); + mAudioManager = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE); + } + + public smdk4x12QComRIL(Context context, int preferredNetworkType, + int cdmaSubscription, Integer instanceId) { + super(context, preferredNetworkType, cdmaSubscription, instanceId); + mAudioManager = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE); + } + + @Override + protected Object + responseIccCardStatus(Parcel p) { + IccCardApplicationStatus appStatus; + + IccCardStatus cardStatus = new IccCardStatus(); + cardStatus.setCardState(p.readInt()); + cardStatus.setUniversalPinState(p.readInt()); + cardStatus.mGsmUmtsSubscriptionAppIndex = p.readInt(); + cardStatus.mCdmaSubscriptionAppIndex = p.readInt(); + cardStatus.mImsSubscriptionAppIndex = p.readInt(); + + int numApplications = p.readInt(); + + // limit to maximum allowed applications + if (numApplications > IccCardStatus.CARD_MAX_APPS) { + numApplications = IccCardStatus.CARD_MAX_APPS; + } + cardStatus.mApplications = new IccCardApplicationStatus[numApplications]; + + appStatus = new IccCardApplicationStatus(); + for (int i = 0 ; i < numApplications ; i++) { + if (i!=0) { + appStatus = new IccCardApplicationStatus(); + } + appStatus.app_type = appStatus.AppTypeFromRILInt(p.readInt()); + appStatus.app_state = appStatus.AppStateFromRILInt(p.readInt()); + appStatus.perso_substate = appStatus.PersoSubstateFromRILInt(p.readInt()); + appStatus.aid = p.readString(); + appStatus.app_label = p.readString(); + appStatus.pin1_replaced = p.readInt(); + appStatus.pin1 = appStatus.PinStateFromRILInt(p.readInt()); + appStatus.pin2 = appStatus.PinStateFromRILInt(p.readInt()); + p.readInt(); // remaining_count_pin1 - pin1_num_retries + p.readInt(); // remaining_count_puk1 - puk1_num_retries + p.readInt(); // remaining_count_pin2 - pin2_num_retries + p.readInt(); // remaining_count_puk2 - puk2_num_retries + p.readInt(); // - perso_unblock_retries + cardStatus.mApplications[i] = appStatus; + } + if (numApplications==1 && !isGSM && appStatus.app_type == appStatus.AppTypeFromRILInt(2)) { + cardStatus.mApplications = new IccCardApplicationStatus[numApplications+2]; + cardStatus.mGsmUmtsSubscriptionAppIndex = 0; + cardStatus.mApplications[cardStatus.mGsmUmtsSubscriptionAppIndex]=appStatus; + cardStatus.mCdmaSubscriptionAppIndex = 1; + cardStatus.mImsSubscriptionAppIndex = 2; + IccCardApplicationStatus appStatus2 = new IccCardApplicationStatus(); + appStatus2.app_type = appStatus2.AppTypeFromRILInt(4); // csim state + appStatus2.app_state = appStatus.app_state; + appStatus2.perso_substate = appStatus.perso_substate; + appStatus2.aid = appStatus.aid; + appStatus2.app_label = appStatus.app_label; + appStatus2.pin1_replaced = appStatus.pin1_replaced; + appStatus2.pin1 = appStatus.pin1; + appStatus2.pin2 = appStatus.pin2; + cardStatus.mApplications[cardStatus.mCdmaSubscriptionAppIndex] = appStatus2; + IccCardApplicationStatus appStatus3 = new IccCardApplicationStatus(); + appStatus3.app_type = appStatus3.AppTypeFromRILInt(5); // ims state + appStatus3.app_state = appStatus.app_state; + appStatus3.perso_substate = appStatus.perso_substate; + appStatus3.aid = appStatus.aid; + appStatus3.app_label = appStatus.app_label; + appStatus3.pin1_replaced = appStatus.pin1_replaced; + appStatus3.pin1 = appStatus.pin1; + appStatus3.pin2 = appStatus.pin2; + cardStatus.mApplications[cardStatus.mImsSubscriptionAppIndex] = appStatus3; + } + return cardStatus; + } + + @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); + } + + 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 responseSignalStrength(Parcel p) { + int numInts = 12; + int response[]; + + // Get raw data + response = new int[numInts]; + for (int i = 0; i < numInts; i++) { + response[i] = p.readInt(); + } + //gsm + response[0] &= 0xff; + //cdma + response[2] %= 256; + response[4] %= 256; + response[7] &= 0xff; + + return new SignalStrength(response[0], response[1], response[2], response[3], response[4], response[5], response[6], response[7], response[8], response[9], response[10], response[11], true); + + } + + @Override + public void setPhoneType(int phoneType){ + super.setPhoneType(phoneType); + isGSM = (phoneType != RILConstants.CDMA_PHONE); + } + + protected Object + responseCallList(Parcel p) { + int num; + int voiceSettings; + ArrayList response; + DriverCall dc; + + num = p.readInt(); + response = new ArrayList(num); + + if (RILJ_LOGV) { + riljLog("responseCallList: num=" + num + + " mEmergencyCallbackModeRegistrant=" + mEmergencyCallbackModeRegistrant + + " mTestingEmergencyCall=" + mTestingEmergencyCall.get()); + } + for (int i = 0 ; i < num ; i++) { + dc = new DriverCall(); + + dc.state = DriverCall.stateFromCLCC(p.readInt()); + dc.index = p.readInt() & 0xff; + dc.TOA = p.readInt(); + dc.isMpty = (0 != p.readInt()); + dc.isMT = (0 != p.readInt()); + dc.als = p.readInt(); + voiceSettings = p.readInt(); +// if (isGSM){ +// p.readInt(); +// } + dc.isVoice = (0 == voiceSettings) ? false : true; + dc.isVoicePrivacy = (0 != p.readInt()); + if (isGSM) { + p.readInt(); + p.readInt(); + p.readString(); + } + dc.number = p.readString(); + int np = p.readInt(); + dc.numberPresentation = DriverCall.presentationFromCLIP(np); + dc.name = p.readString(); + dc.namePresentation = p.readInt(); + int uusInfoPresent = p.readInt(); + if (uusInfoPresent == 1) { + dc.uusInfo = new UUSInfo(); + dc.uusInfo.setType(p.readInt()); + dc.uusInfo.setDcs(p.readInt()); + byte[] userData = p.createByteArray(); + dc.uusInfo.setUserData(userData); + riljLogv(String.format("Incoming UUS : type=%d, dcs=%d, length=%d", + dc.uusInfo.getType(), dc.uusInfo.getDcs(), + dc.uusInfo.getUserData().length)); + riljLogv("Incoming UUS : data (string)=" + + new String(dc.uusInfo.getUserData())); + riljLogv("Incoming UUS : data (hex): " + + IccUtils.bytesToHexString(dc.uusInfo.getUserData())); + } else { + riljLogv("Incoming UUS : NOT present!"); + } + + // Make sure there's a leading + on addresses with a TOA of 145 + dc.number = PhoneNumberUtils.stringFromStringAndTOA(dc.number, dc.TOA); + + response.add(dc); + + if (dc.isVoicePrivacy) { + mVoicePrivacyOnRegistrants.notifyRegistrants(); + riljLog("InCall VoicePrivacy is enabled"); + } else { + mVoicePrivacyOffRegistrants.notifyRegistrants(); + riljLog("InCall VoicePrivacy is disabled"); + } + } + + Collections.sort(response); + + if ((num == 0) && mTestingEmergencyCall.getAndSet(false)) { + if (mEmergencyCallbackModeRegistrant != null) { + riljLog("responseCallList: call ended, testing emergency call," + + " notify ECM Registrants"); + mEmergencyCallbackModeRegistrant.notifyRegistrant(); + } + } + + return response; + } + + @Override + protected void + processUnsolicited (Parcel p) { + Object ret; + int dataPosition = p.dataPosition(); // save off position within the Parcel + int response = p.readInt(); + + switch(response) { + case RIL_UNSOL_RIL_CONNECTED: + ret = responseInts(p); + setRadioPower(false, null); + if (!setPreferredNetworkTypeSeen) { + Rlog.v(RILJ_LOG_TAG, "smdk4x12QComRIL: connected, setting network type to " + mPreferredNetworkType); + setPreferredNetworkType(mPreferredNetworkType, null); + } + setCdmaSubscriptionSource(mCdmaSubscription, null); + if(mRilVersion >= 8) + setCellInfoListRate(Integer.MAX_VALUE, null); + notifyRegistrantsRilConnectionChanged(((int[])ret)[0]); + break; + // SAMSUNG STATES + case 11010: // RIL_UNSOL_AM: + ret = responseString(p); + String amString = (String) ret; + Rlog.d(RILJ_LOG_TAG, "Executing AM: " + amString); + + try { + Runtime.getRuntime().exec("am " + amString); + } catch (IOException e) { + e.printStackTrace(); + Rlog.e(RILJ_LOG_TAG, "am " + amString + " could not be executed."); + } + break; + case 11021: // RIL_UNSOL_RESPONSE_HANDOVER: + ret = responseVoid(p); + break; + case 1036: + ret = responseVoid(p); + break; + case 11017: // RIL_UNSOL_WB_AMR_STATE: + ret = responseInts(p); + setWbAmr(((int[])ret)[0]); + break; + case 11055: // RIL_UNSOL_ON_SS: + p.setDataPosition(dataPosition); + p.writeInt(RIL_UNSOL_ON_SS); + // Do not break + default: + // Rewind the Parcel + p.setDataPosition(dataPosition); + + // Forward responses that we are not overriding to the super class + super.processUnsolicited(p); + return; + } + + } + + @Override + public void + acceptCall (Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_ANSWER, result); + + rr.mParcel.writeInt(1); + rr.mParcel.writeInt(0); + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + + send(rr); + } + + @Override + protected RILRequest + processSolicited (Parcel p) { + int serial, error; + boolean found = false; + 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_VOICE_REGISTRATION_STATE: + case RIL_REQUEST_DATA_REGISTRATION_STATE: + case RIL_REQUEST_OPERATOR: + rr = tr; + break; + }} 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); + } + rr = findAndRemoveRequestFromList(serial); + if (rr == null) { + return rr; + } + Object ret = null; + if (error == 0 || p.dataAvail() > 0) { + switch (rr.mRequest) { + 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); + } + //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 + operatorCheck(Parcel p) { + String response[] = (String[])responseStrings(p); + 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; + } + + /** + * Set audio parameter "wb_amr" for HD-Voice (Wideband AMR). + * + * @param state: 0 = unsupported, 1 = supported. + */ + private void setWbAmr(int state) { + if (state == 1) { + Rlog.d(RILJ_LOG_TAG, "setWbAmr(): setting audio parameter - wb_amr=on"); + mAudioManager.setParameters("wide_voice_enable=true"); + }else if (state == 0) { + Rlog.d(RILJ_LOG_TAG, "setWbAmr(): setting audio parameter - wb_amr=off"); + mAudioManager.setParameters("wide_voice_enable=false"); + } + } + + // 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); + } + + + + @Override + protected Object + responseSMS(Parcel p) { + // Notify that sendSMS() can send the next SMS + synchronized (mSMSLock) { + mIsSendingSMS = false; + mSMSLock.notify(); + } + + return super.responseSMS(p); + } + + @Override + public void + dial(String address, int clirMode, UUSInfo uusInfo, Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_DIAL, result); + + rr.mParcel.writeString(address); + rr.mParcel.writeInt(clirMode); + rr.mParcel.writeInt(0); + rr.mParcel.writeInt(1); + rr.mParcel.writeString(""); + + 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() + "> " + requestToString(rr.mRequest)); + + send(rr); + } + + //this method is used in the search network functionality. + // in mobile network setting-> network operators + @Override + protected Object + responseOperatorInfos(Parcel p) { + String strings[] = (String [])responseStrings(p); + ArrayList ret; + + if (strings.length % mQANElements != 0) { + throw new RuntimeException( + "RIL_REQUEST_QUERY_AVAILABLE_NETWORKS: invalid response. Got " + + strings.length + " strings, expected multiple of " + mQANElements); + } + + ret = new ArrayList(strings.length / mQANElements); + Operators init = null; + if (strings.length != 0) { + init = new Operators(); + } + for (int i = 0 ; i < strings.length ; i += mQANElements) { + String temp = init.unOptimizedOperatorReplace(strings[i+0]); + ret.add ( + new OperatorInfo( + temp, //operatorAlphaLong + temp,//operatorAlphaShort + strings[i+2],//operatorNumeric + strings[i+3]));//state + } + + return ret; + } + + @Override + public void getImsRegistrationState(Message result) { + if(mRilVersion >= 8) + super.getImsRegistrationState(result); + else { + if (result != null) { + CommandException ex = new CommandException( + CommandException.Error.REQUEST_NOT_SUPPORTED); + AsyncResult.forMessage(result, null, ex); + result.sendToTarget(); + } + } + } + + // This call causes ril to crash the socket, stopping further communication + @Override + public void + getHardwareConfig (Message result) { + riljLog("Ignoring call to 'getHardwareConfig'"); + if (result != null) { + CommandException ex = new CommandException( + CommandException.Error.REQUEST_NOT_SUPPORTED); + AsyncResult.forMessage(result, null, ex); + result.sendToTarget(); + } + } + + @Override + public void getRadioCapability(Message response) { + riljLog("getRadioCapability: returning static radio capability"); + if (response != null) { + Object ret = makeStaticRadioCapability(); + AsyncResult.forMessage(response, ret, null); + response.sendToTarget(); + } + } + + @Override + public void setPreferredNetworkType(int networkType , Message response) { + riljLog("setPreferredNetworkType: " + networkType); + + if (!setPreferredNetworkTypeSeen) { + setPreferredNetworkTypeSeen = true; + } + + super.setPreferredNetworkType(networkType, response); + } +} -- cgit v1.1