summaryrefslogtreecommitdiffstats
path: root/src/java/com/android/internal/telephony/SamsungQualcommRIL.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/java/com/android/internal/telephony/SamsungQualcommRIL.java')
-rw-r--r--src/java/com/android/internal/telephony/SamsungQualcommRIL.java329
1 files changed, 329 insertions, 0 deletions
diff --git a/src/java/com/android/internal/telephony/SamsungQualcommRIL.java b/src/java/com/android/internal/telephony/SamsungQualcommRIL.java
new file mode 100644
index 0000000..002d5ad
--- /dev/null
+++ b/src/java/com/android/internal/telephony/SamsungQualcommRIL.java
@@ -0,0 +1,329 @@
+/*
+ * Copyright (C) 2012 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.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.text.TextUtils;
+import android.util.Log;
+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.util.ArrayList;
+import java.util.Collections;
+
+/**
+ * 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 SamsungQualcommRIL extends RIL implements
+CommandsInterface {
+ private Object mSMSLock = new Object();
+ private boolean mIsSendingSMS = false;
+ private boolean isGSM = false;
+ public static final long SEND_SMS_TIMEOUT_IN_MS = 30000;
+
+ public SamsungQualcommRIL(Context context, int networkMode,
+ int cdmaSubscription) {
+ super(context, networkMode, cdmaSubscription);
+ }
+
+ @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];
+
+ for (int i = 0 ; i < numApplications ; i++) {
+ appStatus = new IccCardApplicationStatus();
+
+
+
+ appStatus.app_type = appStatus.AppTypeFromRILInt(p.readInt());
+ appStatus.app_state = appStatus.AppStateFromRILInt(p.readInt());
+ appStatus.perso_substate = appStatus.PersoSubstateFromRILInt(p.readInt());
+ if ((appStatus.app_state == IccCardApplicationStatus.AppState.APPSTATE_SUBSCRIPTION_PERSO) &&
+ ((appStatus.perso_substate == IccCardApplicationStatus.PersoSubState.PERSOSUBSTATE_READY) ||
+ (appStatus.perso_substate == IccCardApplicationStatus.PersoSubState.PERSOSUBSTATE_UNKNOWN))) {
+ // ridiculous hack for network SIM unlock pin
+ appStatus.app_state = IccCardApplicationStatus.AppState.APPSTATE_UNKNOWN;
+ Log.d(LOG_TAG, "ca.app_state == AppState.APPSTATE_SUBSCRIPTION_PERSO");
+ Log.d(LOG_TAG, "ca.perso_substate == PersoSubState.PERSOSUBSTATE_READY");
+ }
+ 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;
+ }
+ 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)) {
+ Log.d(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) {
+ Log.e(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[];
+
+ // This is a mashup of algorithms used in
+ // SamsungQualcommUiccRIL.java
+
+ // Get raw data
+ response = new int[numInts];
+ for (int i = 0; i < numInts; i++) {
+ response[i] = p.readInt();
+ }
+ //gsm
+ response[0] &= 0xff; //gsmDbm
+
+ //cdma
+ // Take just the least significant byte as the signal strength
+ response[2] %= 256;
+ response[4] %= 256;
+
+ // RIL_LTE_SignalStrength
+ if (response[7] == 99) {
+ // If LTE is not enabled, clear LTE results
+ // 7-11 must be -1 for GSM signal strength to be used (see
+ // frameworks/base/telephony/java/android/telephony/SignalStrength.java)
+ response[8] = SignalStrength.INVALID;
+ response[9] = SignalStrength.INVALID;
+ response[10] = SignalStrength.INVALID;
+ response[11] = SignalStrength.INVALID;
+ }else{ // lte is gsm on samsung/qualcomm cdma stack
+ 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], isGSM);
+
+ }
+
+
+ @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: // Fix for NV/RUIM setting on CDMA SIM devices
+ // skip getcdmascriptionsource as if qualcomm handles it in the ril binary
+ ret = responseInts(p);
+ setRadioPower(false, null);
+ setPreferredNetworkType(mPreferredNetworkType, null);
+ notifyRegistrantsRilConnectionChanged(((int[])ret)[0]);
+ samsungDriverCall = (needsOldRilFeature("newDriverCall") && !isGSM) || mRilVersion < 7 ? false : true;
+ isGSM = (mPhoneType != RILConstants.CDMA_PHONE);
+ break;
+ case RIL_UNSOL_NITZ_TIME_RECEIVED:
+ handleNitzTimeReceived(p);
+ break;
+ default:
+ // Rewind the Parcel
+ p.setDataPosition(dataPosition);
+
+ // Forward responses that we are not overriding to the super class
+ super.processUnsolicited(p);
+ return;
+ }
+
+ }
+
+ // 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) {
+
+ Log.d(LOG_TAG, "Dropping \"" + responseToString(response) + " "
+ + retToString(response, sir)
+ + "\" to prevent \"ring of death\" bug.");
+ return;
+ }
+ }
+
+ super.notifyRegistrantsCdmaInfoRec(infoRec);
+ }
+
+ private void
+ handleNitzTimeReceived(Parcel p) {
+ String nitz = (String)responseString(p);
+ //if (RILJ_LOGD) unsljLogRet(RIL_UNSOL_NITZ_TIME_RECEIVED, nitz);
+
+ // has bonus long containing milliseconds since boot that the NITZ
+ // time was received
+ long nitzReceiveTime = p.readLong();
+
+ Object[] result = new Object[2];
+
+ String fixedNitz = nitz;
+ String[] nitzParts = nitz.split(",");
+ if (nitzParts.length == 4) {
+ // 0=date, 1=time+zone, 2=dst, 3=garbage that confuses GsmServiceStateTracker (so remove it)
+ fixedNitz = nitzParts[0]+","+nitzParts[1]+","+nitzParts[2]+",";
+ }
+
+ result[0] = fixedNitz;
+ result[1] = Long.valueOf(nitzReceiveTime);
+
+ boolean ignoreNitz = SystemProperties.getBoolean(
+ TelephonyProperties.PROPERTY_IGNORE_NITZ, false);
+
+ if (ignoreNitz) {
+ if (RILJ_LOGD) riljLog("ignoring UNSOL_NITZ_TIME_RECEIVED");
+ } else {
+ if (mNITZTimeRegistrant != null) {
+ mNITZTimeRegistrant
+ .notifyRegistrant(new AsyncResult (null, result, null));
+ } else {
+ // in case NITZ time registrant isnt registered yet
+ mLastNITZTimeInfo = 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);
+ }
+}