From e6a4f7c28f343ffe30e325350595f139820a3261 Mon Sep 17 00:00:00 2001 From: Codenamedroid Date: Thu, 16 Aug 2012 01:17:38 -0500 Subject: [PATCH] import cm telephony and RIL support Full history: https://github.com/CyanogenMod/android_frameworks_base/commits/jellybean /telephony --- .../android/telephony/PhoneNumberUtils.java | 7 + .../android/internal/telephony/AdnRecord.java | 2 +- .../internal/telephony/CallManager.java | 25 + .../internal/telephony/CommandsInterface.java | 6 + .../internal/telephony/DataCallState.java | 2 +- .../internal/telephony/DataConnection.java | 17 +- .../telephony/DataConnectionTracker.java | 8 + .../internal/telephony/HTCQualcommRIL.java | 227 ++++ .../android/internal/telephony/IccUtils.java | 45 + .../internal/telephony/LGEQualcommRIL.java | 379 +++++++ .../telephony/LGEQualcommUiccRIL.java | 188 ++++ .../internal/telephony/MotoWrigley3GRIL.java | 137 +++ .../com/android/internal/telephony/Phone.java | 2 + .../android/internal/telephony/PhoneBase.java | 5 + .../internal/telephony/PhoneFactory.java | 17 +- .../internal/telephony/QualcommSharedRIL.java | 831 +++++++++++++++ .../com/android/internal/telephony/RIL.java | 211 ++-- .../internal/telephony/RILConstants.java | 2 +- .../telephony/SamsungCDMAQualcommRIL.java | 270 +++++ .../internal/telephony/SamsungHCRIL.java | 87 ++ .../telephony/SamsungQualcommD2RIL.java | 110 ++ .../telephony/SamsungQualcommUiccRIL.java | 301 ++++++ .../internal/telephony/SamsungRIL.java | 968 ++++++++++++++++++ .../android/internal/telephony/SemcRIL.java | 463 +++++++++ .../internal/telephony/SimRegionCache.java | 51 + .../internal/telephony/Smdk4210RIL.java | 808 +++++++++++++++ .../internal/telephony/SonyQualcommRIL.java | 440 ++++++++ .../cdma/CdmaLteServiceStateTracker.java | 2 +- .../telephony/cdma/CdmaSMSDispatcher.java | 72 +- .../telephony/cdma/sms/BearerData.java | 19 +- .../internal/telephony/gsm/GSMPhone.java | 4 + .../gsm/GsmDataConnectionTracker.java | 106 +- .../telephony/gsm/GsmServiceStateTracker.java | 3 +- .../internal/telephony/gsm/SmsMessage.java | 9 + .../telephony/sip/SipCommandInterface.java | 2 + .../telephony/test/SimulatedCommands.java | 2 + .../internal/telephony/AdnRecordTest.java | 12 + .../internal/telephony/SMSDispatcherTest.java | 21 + .../internal/telephony/SimUtilsTest.java | 24 + .../gsm/UsimDataDownloadCommands.java | 3 + 40 files changed, 5796 insertions(+), 92 deletions(-) create mode 100644 telephony/java/com/android/internal/telephony/HTCQualcommRIL.java create mode 100644 telephony/java/com/android/internal/telephony/LGEQualcommRIL.java create mode 100644 telephony/java/com/android/internal/telephony/LGEQualcommUiccRIL.java create mode 100644 telephony/java/com/android/internal/telephony/MotoWrigley3GRIL.java create mode 100644 telephony/java/com/android/internal/telephony/QualcommSharedRIL.java create mode 100644 telephony/java/com/android/internal/telephony/SamsungCDMAQualcommRIL.java create mode 100644 telephony/java/com/android/internal/telephony/SamsungHCRIL.java create mode 100644 telephony/java/com/android/internal/telephony/SamsungQualcommD2RIL.java create mode 100644 telephony/java/com/android/internal/telephony/SamsungQualcommUiccRIL.java create mode 100644 telephony/java/com/android/internal/telephony/SamsungRIL.java create mode 100644 telephony/java/com/android/internal/telephony/SemcRIL.java create mode 100644 telephony/java/com/android/internal/telephony/SimRegionCache.java create mode 100644 telephony/java/com/android/internal/telephony/Smdk4210RIL.java create mode 100644 telephony/java/com/android/internal/telephony/SonyQualcommRIL.java diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java index f740718619672..e5fb7ca7fb14c 100644 --- a/telephony/java/android/telephony/PhoneNumberUtils.java +++ b/telephony/java/android/telephony/PhoneNumberUtils.java @@ -1485,6 +1485,13 @@ public static String formatNumber( * @hide */ public static String normalizeNumber(String phoneNumber) { + // chop off CLIR prefix + if (phoneNumber.startsWith(CLIR_ON)) { + phoneNumber = phoneNumber.substring(CLIR_ON.length() - 1); + } else if (phoneNumber.startsWith(CLIR_OFF)) { + phoneNumber = phoneNumber.substring(CLIR_OFF.length() - 1); + } + StringBuilder sb = new StringBuilder(); int len = phoneNumber.length(); for (int i = 0; i < len; i++) { diff --git a/telephony/java/com/android/internal/telephony/AdnRecord.java b/telephony/java/com/android/internal/telephony/AdnRecord.java index 1bf2d3c61d502..a01b00d8b859e 100644 --- a/telephony/java/com/android/internal/telephony/AdnRecord.java +++ b/telephony/java/com/android/internal/telephony/AdnRecord.java @@ -283,7 +283,7 @@ public byte[] buildAdnString(int recordSize) { private void parseRecord(byte[] record) { try { - alphaTag = IccUtils.adnStringFieldToString( + alphaTag = IccUtils.adnStringFieldToStringKsc5601Support( record, 0, record.length - FOOTER_SIZE_BYTES); int footerOffset = record.length - FOOTER_SIZE_BYTES; diff --git a/telephony/java/com/android/internal/telephony/CallManager.java b/telephony/java/com/android/internal/telephony/CallManager.java index f825f31dd005f..948d670929934 100644 --- a/telephony/java/com/android/internal/telephony/CallManager.java +++ b/telephony/java/com/android/internal/telephony/CallManager.java @@ -417,6 +417,31 @@ public void setAudioMode() { } break; } + + // Set additional audio parameters needed for incall audio + String[] audioParams = context.getResources().getStringArray(com.android.internal.R.array.config_telephony_set_audioparameters); + String[] aPValues; + + for (String parameter : audioParams) { + aPValues = parameter.split("="); + + if(aPValues[1] == null || aPValues[1].length() == 0) { + aPValues[1] = "on"; + } + + if(aPValues[2] == null || aPValues[2].length() == 0) { + aPValues[2] = "off"; + } + + if (audioManager.getMode() == AudioManager.MODE_IN_CALL) { + Log.d(LOG_TAG, "setAudioMode(): " + aPValues[0] + "=" + aPValues[1]); + audioManager.setParameters(aPValues[0] + "=" + aPValues[1]); + } else if (audioManager.getMode() == AudioManager.MODE_NORMAL) { + Log.d(LOG_TAG, "setAudioMode(): " + aPValues[0] + "=" + aPValues[2]); + audioManager.setParameters(aPValues[0] + "=" + aPValues[2]); + } + } + } private Context getContext() { diff --git a/telephony/java/com/android/internal/telephony/CommandsInterface.java b/telephony/java/com/android/internal/telephony/CommandsInterface.java index f7757b3867e5e..94bd3e8b4e6f7 100644 --- a/telephony/java/com/android/internal/telephony/CommandsInterface.java +++ b/telephony/java/com/android/internal/telephony/CommandsInterface.java @@ -1576,4 +1576,10 @@ public void setupDataCall(String radioTechnology, String profile, * Notifiy that we are testing an emergency call */ public void testingEmergencyCall(); + + /** + * @hide + * CM-specific: Ask the RIL about the presence of back-compat flags + */ + public boolean needsOldRilFeature(String feature); } diff --git a/telephony/java/com/android/internal/telephony/DataCallState.java b/telephony/java/com/android/internal/telephony/DataCallState.java index efbf608d90205..a5a5965ed0853 100644 --- a/telephony/java/com/android/internal/telephony/DataCallState.java +++ b/telephony/java/com/android/internal/telephony/DataCallState.java @@ -81,7 +81,7 @@ public String toString() { .append(" retry=").append(suggestedRetryTime) .append(" cid=").append(cid) .append(" active=").append(active) - .append(" type=").append(type) + .append(" type='").append(type) .append("' ifname='").append(ifname); sb.append("' addresses=["); for (String addr : addresses) { diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java index 3f7e71e32d92c..16b9c7e7c9f3b 100644 --- a/telephony/java/com/android/internal/telephony/DataConnection.java +++ b/telephony/java/com/android/internal/telephony/DataConnection.java @@ -381,12 +381,27 @@ private void notifyDisconnectCompleted(DisconnectParams dp, boolean sendAll) { if (DBG) log("NotifyDisconnectCompleted DisconnectParams=" + dp); } + protected boolean needsOldRilFeature(String feature) { + String[] features = SystemProperties.get("ro.telephony.ril.v3", "").split(","); + for (String found: features) { + if (found.equals(feature)) + return true; + } + return false; + } + protected int getRilRadioTechnology(int defaultRilRadioTechnology) { int rilRadioTechnology; if (mRilVersion < 6) { rilRadioTechnology = defaultRilRadioTechnology; } else { - rilRadioTechnology = phone.getServiceState().getRilRadioTechnology() + 2; + if (needsOldRilFeature("usehcradio") ) { + rilRadioTechnology = phone.getServiceState().getRilRadioTechnology() - 2; + if (rilRadioTechnology != 1) // in reality if it is not 1 something is wrong for hc ?? + rilRadioTechnology = 1; + } + else + rilRadioTechnology = phone.getServiceState().getRilRadioTechnology() + 2; } return rilRadioTechnology; } diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java index 0dee7a1691f2a..135c479c3d80a 100644 --- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java @@ -155,6 +155,14 @@ public enum Activity { public static final int DISABLED = 0; public static final int ENABLED = 1; + /** + * Constants for the data connection activity: + * physical link down/up + */ + protected static final int DATA_CONNECTION_ACTIVE_PH_LINK_INACTIVE = 0; + protected static final int DATA_CONNECTION_ACTIVE_PH_LINK_DOWN = 1; + protected static final int DATA_CONNECTION_ACTIVE_PH_LINK_UP = 2; + public static final String APN_TYPE_KEY = "apnType"; /** Delay between APN attempts. diff --git a/telephony/java/com/android/internal/telephony/HTCQualcommRIL.java b/telephony/java/com/android/internal/telephony/HTCQualcommRIL.java new file mode 100644 index 0000000000000..de6ac856985fd --- /dev/null +++ b/telephony/java/com/android/internal/telephony/HTCQualcommRIL.java @@ -0,0 +1,227 @@ +/* + * 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.HandlerThread; +import android.os.Looper; +import android.os.Message; +import android.os.Parcel; +import android.text.TextUtils; +import android.util.Log; + +import java.util.ArrayList; + +/** + * Qualcomm RIL class for basebands that do not send the SIM status + * piggybacked in RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED. Instead, + * these radios will send radio state and we have to query for SIM + * status separately. + * + * {@hide} + */ +public class HTCQualcommRIL extends QualcommSharedRIL implements CommandsInterface { + private final int RIL_INT_RADIO_OFF = 0; + private final int RIL_INT_RADIO_UNAVAILABLE = 1; + private final int RIL_INT_RADIO_ON = 13; + + public HTCQualcommRIL(Context context, int networkMode, int cdmaSubscription) { + super(context, networkMode, cdmaSubscription); + } + + @Override + protected Object + responseIccCardStatus(Parcel p) { + IccCardApplication ca; + + // use old needsOldRilFeature method for feature. it would be redundant to make + // a new method just for naming sake. + boolean subscriptionFromSource = needsOldRilFeature("subscriptionFromSource"); + boolean oldRil = needsOldRilFeature("icccardstatus"); + + IccCardStatus status = new IccCardStatus(); + status.setCardState(p.readInt()); + status.setUniversalPinState(p.readInt()); + status.setGsmUmtsSubscriptionAppIndex(p.readInt()); + status.setCdmaSubscriptionAppIndex(p.readInt()); + + if (!oldRil) + status.setImsSubscriptionAppIndex(p.readInt()); + + int numApplications = p.readInt(); + + // limit to maximum allowed applications + if (numApplications > IccCardStatus.CARD_MAX_APPS) { + numApplications = IccCardStatus.CARD_MAX_APPS; + } + status.setNumApplications(numApplications); + + for (int i = 0 ; i < numApplications ; i++) { + ca = new IccCardApplication(); + ca.app_type = ca.AppTypeFromRILInt(p.readInt()); + ca.app_state = ca.AppStateFromRILInt(p.readInt()); + ca.perso_substate = ca.PersoSubstateFromRILInt(p.readInt()); + if ((ca.app_state == IccCardApplication.AppState.APPSTATE_SUBSCRIPTION_PERSO) && + ((ca.perso_substate == IccCardApplication.PersoSubState.PERSOSUBSTATE_READY) || + (ca.perso_substate == IccCardApplication.PersoSubState.PERSOSUBSTATE_UNKNOWN))) { + // ridiculous HTC hack + ca.app_state = IccCardApplication.AppState.APPSTATE_UNKNOWN; + Log.d(LOG_TAG, "ca.app_state == AppState.APPSTATE_SUBSCRIPTION_PERSO"); + Log.d(LOG_TAG, "ca.perso_substate == PersoSubState.PERSOSUBSTATE_READY"); + } + ca.aid = p.readString(); + ca.app_label = p.readString(); + ca.pin1_replaced = p.readInt(); + ca.pin1 = ca.PinStateFromRILInt(p.readInt()); + ca.pin2 = ca.PinStateFromRILInt(p.readInt()); + status.addApplication(ca); + } + + // use ril response to determine subscription source + if (subscriptionFromSource) + return status; + + int appIndex = -1; + if (mPhoneType == RILConstants.CDMA_PHONE) { + appIndex = status.getCdmaSubscriptionAppIndex(); + Log.d(LOG_TAG, "This is a CDMA PHONE " + appIndex); + } else { + appIndex = status.getGsmUmtsSubscriptionAppIndex(); + Log.d(LOG_TAG, "This is a GSM PHONE " + appIndex); + } + + mAid = status.getApplication(appIndex).aid; + + return status; + } + + @Override + protected Object + responseSignalStrength(Parcel p) { + int numInts = 14; + int response[]; + + /* HTC signal strength format: + * 0: GW_SignalStrength + * 1: GW_SignalStrength.bitErrorRate + * 2: CDMA_SignalStrength.dbm + * 3: CDMA_SignalStrength.ecio + * 4: EVDO_SignalStrength.dbm + * 5: EVDO_SignalStrength.ecio + * 6: EVDO_SignalStrength.signalNoiseRatio + * 7: ATT_SignalStrength.dbm + * 8: ATT_SignalStrength.ecno + * 9: LTE_SignalStrength.signalStrength + * 10: LTE_SignalStrength.rsrp + * 11: LTE_SignalStrength.rsrq + * 12: LTE_SignalStrength.rssnr + * 13: LTE_SignalStrength.cqi + */ + + response = new int[numInts]; + for (int i = 0; i < numInts; i++) { + if (i > 8) { + response[i-2] = p.readInt(); + response[i] = -1; + } else { + response[i] = p.readInt(); + } + } + + 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_RESPONSE_RADIO_STATE_CHANGED: ret = responseVoid(p); break; + case 21004: ret = responseVoid(p); break; // RIL_UNSOL_VOICE_RADIO_TECH_CHANGED + case 21005: ret = responseVoid(p); break; // RIL_UNSOL_IMS_NETWORK_STATE_CHANGED + case 21007: ret = responseVoid(p); break; // RIL_UNSOL_DATA_NETWORK_STATE_CHANGED + + default: + // Rewind the Parcel + p.setDataPosition(dataPosition); + + // Forward responses that we are not overriding to the super class + super.processUnsolicited(p); + return; + } + + switch(response) { + case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED: + int state = p.readInt(); + setRadioStateFromRILInt(state); + break; + case 21004: + case 21005: + case 21007: + if (RILJ_LOGD) unsljLogRet(response, ret); + + if (mExitEmergencyCallbackModeRegistrants != null) { + mExitEmergencyCallbackModeRegistrants.notifyRegistrants( + new AsyncResult (null, null, null)); + } + break; + } + } + + private void setRadioStateFromRILInt(int stateCode) { + CommandsInterface.RadioState radioState; + HandlerThread handlerThread; + Looper looper; + IccHandler iccHandler; + + switch (stateCode) { + case RIL_INT_RADIO_OFF: + radioState = CommandsInterface.RadioState.RADIO_OFF; + if (mIccHandler != null) { + mIccThread = null; + mIccHandler = null; + } + break; + case RIL_INT_RADIO_UNAVAILABLE: + radioState = CommandsInterface.RadioState.RADIO_UNAVAILABLE; + break; + case RIL_INT_RADIO_ON: + if (mIccHandler == null) { + handlerThread = new HandlerThread("IccHandler"); + mIccThread = handlerThread; + + mIccThread.start(); + + looper = mIccThread.getLooper(); + mIccHandler = new IccHandler(this,looper); + mIccHandler.run(); + } + radioState = CommandsInterface.RadioState.RADIO_ON; + break; + default: + throw new RuntimeException("Unrecognized RIL_RadioState: " + stateCode); + } + + setRadioState(radioState); + } +} diff --git a/telephony/java/com/android/internal/telephony/IccUtils.java b/telephony/java/com/android/internal/telephony/IccUtils.java index a966f7694f09e..2fb96fef6a136 100644 --- a/telephony/java/com/android/internal/telephony/IccUtils.java +++ b/telephony/java/com/android/internal/telephony/IccUtils.java @@ -176,6 +176,47 @@ public class IccUtils { */ public static String adnStringFieldToString(byte[] data, int offset, int length) { + String s = adnStringFieldToStringUcs2Helper(data, offset, length); + if (s == null) { + s = adnStringFieldToStringGsm8BitHelper(data, offset, length); + } + return s; + } + + /** + * Almost identical to the method {@link #adnStringFieldToString}. + * + * Exception: + * If the SIM is Korean (MCC equals "450"), KSC5601 encoding will be + * assumed (instead of GSM8Bit). This could lead to unintended consequences, + * if the ADN alphaTag was saved with GSM8Bit. This is considered an + * acceptable risk. + */ + public static String + adnStringFieldToStringKsc5601Support(byte[] data, int offset, int length) { + String s = adnStringFieldToStringUcs2Helper(data, offset, length); + + if (s == null) { + if (SimRegionCache.getRegion() == SimRegionCache.MCC_KOREAN) { + try { + int len = offset; + byte stop = (byte)0xFF; + while (len < length && data[len] != stop) { + len++; + } + return new String(data, offset, len, "KSC5601"); + } catch (UnsupportedEncodingException e) { + Log.e(LOG_TAG, "implausible UnsupportedEncodingException", e); + } + } + + return adnStringFieldToStringGsm8BitHelper(data, offset, length); + } + return s; + } + + private static String + adnStringFieldToStringUcs2Helper(byte[] data, int offset, int length) { if (length == 0) { return ""; } @@ -253,7 +294,11 @@ public class IccUtils { return ret.toString(); } + return null; + } + private static String + adnStringFieldToStringGsm8BitHelper(byte[] data, int offset, int length) { Resources resource = Resources.getSystem(); String defaultCharset = ""; try { diff --git a/telephony/java/com/android/internal/telephony/LGEQualcommRIL.java b/telephony/java/com/android/internal/telephony/LGEQualcommRIL.java new file mode 100644 index 0000000000000..f8bcc325aee48 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/LGEQualcommRIL.java @@ -0,0 +1,379 @@ +/* + * Copyright (C) 2011 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.Message; +import android.os.Parcel; +import android.os.SystemProperties; +import android.text.TextUtils; +import android.util.Log; + +/** + * Qualcomm RIL class for basebands that do not send the SIM status + * piggybacked in RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED. Instead, + * these radios will send radio state and we have to query for SIM + * status separately. + * Custom Qualcomm No SimReady RIL for LGE + * + * {@hide} + */ + +public class LGEQualcommRIL extends QualcommSharedRIL implements CommandsInterface { + protected int mPinState; + boolean RILJ_LOGV = true; + boolean RILJ_LOGD = true; + + public LGEQualcommRIL(Context context, int networkMode, int cdmaSubscription) { + super(context, networkMode, cdmaSubscription); + } + + @Override + public void + supplyIccPin(String pin, Message result) { + //Note: This RIL request has not been renamed to ICC, + // but this request is also valid for SIM and RUIM + RILRequest rr = RILRequest.obtain(RIL_REQUEST_ENTER_SIM_PIN, result); + + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + + rr.mp.writeString(mAid); + rr.mp.writeString(pin); + + send(rr); + } + + @Override + public void + supplyIccPuk(String puk, String newPin, Message result) { + //Note: This RIL request has not been renamed to ICC, + // but this request is also valid for SIM and RUIM + RILRequest rr = RILRequest.obtain(RIL_REQUEST_ENTER_SIM_PUK, result); + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + + rr.mp.writeString(mAid); + rr.mp.writeString(puk); + rr.mp.writeString(newPin); + + send(rr); + } + + @Override + public void + supplyIccPin2(String pin, Message result) { + //Note: This RIL request has not been renamed to ICC, + // but this request is also valid for SIM and RUIM + RILRequest rr = RILRequest.obtain(RIL_REQUEST_ENTER_SIM_PIN2, result); + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + + rr.mp.writeString(mAid); + rr.mp.writeString(pin); + + send(rr); + } + + @Override + public void + supplyIccPuk2(String puk, String newPin2, Message result) { + //Note: This RIL request has not been renamed to ICC, + // but this request is also valid for SIM and RUIM + RILRequest rr = RILRequest.obtain(RIL_REQUEST_ENTER_SIM_PUK2, result); + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + + rr.mp.writeString(mAid); + rr.mp.writeString(puk); + rr.mp.writeString(newPin2); + + send(rr); + } + + @Override + public void + changeIccPin(String oldPin, String newPin, Message result) { + //Note: This RIL request has not been renamed to ICC, + // but this request is also valid for SIM and RUIM + RILRequest rr = RILRequest.obtain(RIL_REQUEST_CHANGE_SIM_PIN, result); + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + + rr.mp.writeString(mAid); + rr.mp.writeString(oldPin); + rr.mp.writeString(newPin); + + send(rr); + } + + @Override + public void + changeIccPin2(String oldPin2, String newPin2, Message result) { + //Note: This RIL request has not been renamed to ICC, + // but this request is also valid for SIM and RUIM + RILRequest rr = RILRequest.obtain(RIL_REQUEST_CHANGE_SIM_PIN2, result); + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + + rr.mp.writeString(mAid); + rr.mp.writeString(oldPin2); + rr.mp.writeString(newPin2); + + send(rr); + } + + @Override + public void + getIMSI(Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_IMSI, result); + + rr.mp.writeString(mAid); + + if (RILJ_LOGD) riljLog(rr.serialString() + + "> getIMSI:RIL_REQUEST_GET_IMSI " + + RIL_REQUEST_GET_IMSI + + " aid: " + mAid + + " " + requestToString(rr.mRequest)); + + send(rr); + } + + @Override + public void + setupDataCall(String radioTechnology, String profile, String apn, + String user, String password, String authType, String ipVersion, + Message result) { + RILRequest rr + = RILRequest.obtain(RIL_REQUEST_SETUP_DATA_CALL, result); + + rr.mp.writeInt(7); + + rr.mp.writeString(radioTechnology); + rr.mp.writeString(profile); + rr.mp.writeString(apn); + rr.mp.writeString(user); + rr.mp.writeString(password); + rr.mp.writeString(authType); + rr.mp.writeString("IP"); // ipVersion + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + + requestToString(rr.mRequest) + " " + radioTechnology + " " + + profile + " " + apn + " " + user + " " + + password + " " + authType + " " + ipVersion); + + send(rr); + } + + @Override + public void + iccIO (int command, int fileid, String path, int p1, int p2, int p3, + String data, String pin2, Message result) { + //Note: This RIL request has not been renamed to ICC, + // but this request is also valid for SIM and RUIM + RILRequest rr + = RILRequest.obtain(RIL_REQUEST_SIM_IO, result); + + rr.mp.writeString(mAid); + rr.mp.writeInt(command); + rr.mp.writeInt(fileid); + rr.mp.writeString(path); + rr.mp.writeInt(p1); + rr.mp.writeInt(p2); + rr.mp.writeInt(p3); + rr.mp.writeString(data); + rr.mp.writeString(pin2); + + if (RILJ_LOGD) riljLog(rr.serialString() + "> iccIO: " + + " aid: " + mAid + " " + + requestToString(rr.mRequest) + + " 0x" + Integer.toHexString(command) + + " 0x" + Integer.toHexString(fileid) + " " + + " path: " + path + "," + + p1 + "," + p2 + "," + p3); + + send(rr); + } + + @Override + public void + queryFacilityLock (String facility, String password, int serviceClass, + Message response) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_QUERY_FACILITY_LOCK, response); + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + + " aid: " + mAid + " facility: " + facility); + + if (facility.equals("SC") && + SystemProperties.get("ro.cm.device").indexOf("e73") == 0) { + int [] iccstatus = new int[1]; + iccstatus[0] = mPinState; + AsyncResult.forMessage(response, iccstatus, null); + response.sendToTarget(); + } else { + // count strings + rr.mp.writeInt(4); + + rr.mp.writeString(mAid); + rr.mp.writeString(facility); + rr.mp.writeString(password); + + rr.mp.writeString(Integer.toString(serviceClass)); + + send(rr); + } + } + + @Override + public void + setFacilityLock (String facility, boolean lockState, String password, + int serviceClass, Message response) { + String lockString; + RILRequest rr + = RILRequest.obtain(RIL_REQUEST_SET_FACILITY_LOCK, response); + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + + " aid: " + mAid + " facility: " + facility + + " lockstate: " + lockState); + + // count strings + rr.mp.writeInt(5); + + rr.mp.writeString(mAid); + rr.mp.writeString(facility); + lockString = (lockState)?"1":"0"; + rr.mp.writeString(lockString); + rr.mp.writeString(password); + rr.mp.writeString(Integer.toString(serviceClass)); + + send(rr); + } + + @Override + protected Object + responseIccCardStatus(Parcel p) { + IccCardApplication ca; + + IccCardStatus status = new IccCardStatus(); + status.setCardState(p.readInt()); + status.setUniversalPinState(p.readInt()); + int gsmUmtsSubscriptionAppCount = p.readInt(); + for (int i = 0; i < gsmUmtsSubscriptionAppCount; i++) { + if (i == 0) + status.setGsmUmtsSubscriptionAppIndex(p.readInt()); + else + p.readInt(); + } + + int cdmaSubscriptionAppCount = p.readInt(); + for (int i = 0; i < cdmaSubscriptionAppCount; i++) { + if (i == 0) + status.setCdmaSubscriptionAppIndex(p.readInt()); + else + p.readInt(); + } + int numApplications = p.readInt(); + + // limit to maximum allowed applications + if (numApplications > IccCardStatus.CARD_MAX_APPS) { + numApplications = IccCardStatus.CARD_MAX_APPS; + } + status.setNumApplications(numApplications); + + for (int i = 0 ; i < numApplications ; i++) { + ca = new IccCardApplication(); + ca.app_type = ca.AppTypeFromRILInt(p.readInt()); + ca.app_state = ca.AppStateFromRILInt(p.readInt()); + ca.perso_substate = ca.PersoSubstateFromRILInt(p.readInt()); + ca.aid = p.readString(); + ca.app_label = p.readString(); + ca.pin1_replaced = p.readInt(); + ca.pin1 = ca.PinStateFromRILInt(p.readInt()); + ca.pin2 = ca.PinStateFromRILInt(p.readInt()); + status.addApplication(ca); + p.readInt(); + p.readInt(); + p.readInt(); + p.readInt(); + } + + int appIndex = -1; + if (mPhoneType == RILConstants.CDMA_PHONE) { + appIndex = status.getCdmaSubscriptionAppIndex(); + Log.d(LOG_TAG, "This is a CDMA PHONE " + appIndex); + } else { + appIndex = status.getGsmUmtsSubscriptionAppIndex(); + Log.d(LOG_TAG, "This is a GSM PHONE " + appIndex); + } + + IccCardApplication application = status.getApplication(appIndex); + mAid = application.aid; + mPinState = (application.pin1 == IccCardStatus.PinState.PINSTATE_DISABLED || + application.pin1 == IccCardStatus.PinState.PINSTATE_UNKNOWN) ? 0 : 1; + + return status; + } + + @Override + protected DataCallState getDataCallState(Parcel p, int version) { + DataCallState dataCall = new DataCallState(); + + boolean oldRil = needsOldRilFeature("datacall"); + + if (!oldRil) + return super.getDataCallState(p, version); + + dataCall.version = 3; // was dataCall.version = version; + dataCall.cid = p.readInt(); + dataCall.active = p.readInt(); + dataCall.type = p.readString(); + p.readString(); // apn + String addresses = p.readString(); + if (!TextUtils.isEmpty(addresses)) { + dataCall.addresses = addresses.split(" "); + } + dataCall.ifname = "rmnet0"; + p.readInt(); // RadioTechnology + p.readInt(); // inactiveReason + + dataCall.dnses = new String[2]; + dataCall.dnses[0] = SystemProperties.get("net."+dataCall.ifname+".dns1"); + dataCall.dnses[1] = SystemProperties.get("net."+dataCall.ifname+".dns2"); + + return dataCall; + } + + @Override + public void + getBasebandVersion (Message response) { + if (SystemProperties.get("ro.cm.device").indexOf("e73") == 0) { + /* This model wants a RIL_REQUEST_GET_MODEM_VERSION */ + RILRequest rr + = RILRequest.obtain(220, response); + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + + send(rr); + } else { + super.getBasebandVersion(response); + } + } + +} diff --git a/telephony/java/com/android/internal/telephony/LGEQualcommUiccRIL.java b/telephony/java/com/android/internal/telephony/LGEQualcommUiccRIL.java new file mode 100644 index 0000000000000..98fe3608f9e28 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/LGEQualcommUiccRIL.java @@ -0,0 +1,188 @@ +/* + * 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.Message; +import android.os.Parcel; +import android.os.SystemProperties; +import android.text.TextUtils; +import android.util.Log; + +import java.util.ArrayList; + +/** + * Custom Qualcomm No SimReady RIL for LGE using the latest Uicc stack + * + * {@hide} + */ +public class LGEQualcommUiccRIL extends QualcommSharedRIL implements CommandsInterface { + boolean RILJ_LOGV = true; + boolean RILJ_LOGD = true; + + public LGEQualcommUiccRIL(Context context, int networkMode, int cdmaSubscription) { + super(context, networkMode, cdmaSubscription); + } + + /* + @Override + public void + setupDataCall(String radioTechnology, String profile, String apn, + String user, String password, String authType, String protocol, + Message result) { + + RILRequest rrSPT = RILRequest.obtain( + 121, null); //121 - RIL_REQUEST_VSS_SET_PDN_TABLE + rrSPT.mp.writeInt(1); // pdnId + rrSPT.mp.writeInt(apn.length()); // apnLength + rrSPT.mp.writeString(apn); // apn + rrSPT.mp.writeInt(0); // ipType + rrSPT.mp.writeInt(0); // inactivityTime + rrSPT.mp.writeInt(1); // enable + send(rrSPT); + + + + RILRequest rr + = RILRequest.obtain(RIL_REQUEST_SETUP_DATA_CALL, result); + + rr.mp.writeInt(7); + + rr.mp.writeString(radioTechnology); + rr.mp.writeString(profile); + rr.mp.writeString(apn); + rr.mp.writeString(user); + rr.mp.writeString(password); + rr.mp.writeString(authType); + rr.mp.writeString(protocol); + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + + requestToString(rr.mRequest) + " " + radioTechnology + " " + + profile + " " + apn + " " + user + " " + + password + " " + authType + " " + protocol); + + send(rr); + } + */ + + @Override + protected Object + responseSetupDataCall(Parcel p) { + DataCallState dataCall; + + boolean oldRil = needsOldRilFeature("datacall"); + + if (!oldRil) + return super.responseSetupDataCall(p); + + p.readString(); + return super.responseSetupDataCall(p); + + } + @Override + protected Object + responseIccCardStatus(Parcel p) { + IccCardApplication ca; + + IccCardStatus status = new IccCardStatus(); + status.setCardState(p.readInt()); + status.setUniversalPinState(p.readInt()); + status.setGsmUmtsSubscriptionAppIndex(p.readInt()); + status.setCdmaSubscriptionAppIndex(p.readInt()); + + status.setImsSubscriptionAppIndex(p.readInt()); + + int numApplications = p.readInt(); + + // limit to maximum allowed applications + if (numApplications > IccCardStatus.CARD_MAX_APPS) { + numApplications = IccCardStatus.CARD_MAX_APPS; + } + status.setNumApplications(numApplications); + + for (int i = 0; i < numApplications; i++) { + ca = new IccCardApplication(); + ca.app_type = ca.AppTypeFromRILInt(p.readInt()); + ca.app_state = ca.AppStateFromRILInt(p.readInt()); + ca.perso_substate = ca.PersoSubstateFromRILInt(p.readInt()); + ca.aid = p.readString(); + ca.app_label = p.readString(); + ca.pin1_replaced = p.readInt(); + ca.pin1 = ca.PinStateFromRILInt(p.readInt()); + ca.pin2 = ca.PinStateFromRILInt(p.readInt()); + p.readInt(); //remaining_count_pin1 + p.readInt(); //remaining_count_puk1 + p.readInt(); //remaining_count_pin2 + p.readInt(); //remaining_count_puk2 + status.addApplication(ca); + } + int appIndex = -1; + if (mPhoneType == RILConstants.CDMA_PHONE) { + appIndex = status.getCdmaSubscriptionAppIndex(); + Log.d(LOG_TAG, "This is a CDMA PHONE " + appIndex); + } else { + appIndex = status.getGsmUmtsSubscriptionAppIndex(); + Log.d(LOG_TAG, "This is a GSM PHONE " + appIndex); + } + + if (numApplications > 0) { + IccCardApplication application = status.getApplication(appIndex); + mAid = application.aid; + mUSIM = application.app_type + == IccCardApplication.AppType.APPTYPE_USIM; + mSetPreferredNetworkType = mPreferredNetworkType; + + if (TextUtils.isEmpty(mAid)) + mAid = ""; + Log.d(LOG_TAG, "mAid " + mAid); + } + + return status; + } + + @Override + protected Object + responseSignalStrength(Parcel p) { + int numInts = 12; + int response[]; + + boolean oldRil = needsOldRilFeature("signalstrength"); + boolean noLte = false; + + /* TODO: Add SignalStrength class to match RIL_SignalStrength */ + response = new int[numInts]; + for (int i = 0 ; i < numInts ; i++) { + if ((oldRil || noLte) && i > 6 && i < 12) { + response[i] = -1; + } else { + response[i] = p.readInt(); + } + if (i == 7 && response[i] == 99) { + response[i] = -1; + noLte = true; + } + if (i == 8 && !(noLte || oldRil)) { + response[i] *= -1; + } + } + + return response; + } + +} diff --git a/telephony/java/com/android/internal/telephony/MotoWrigley3GRIL.java b/telephony/java/com/android/internal/telephony/MotoWrigley3GRIL.java new file mode 100644 index 0000000000000..4ad7433624fbb --- /dev/null +++ b/telephony/java/com/android/internal/telephony/MotoWrigley3GRIL.java @@ -0,0 +1,137 @@ +/* + * 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 android.content.Context; +import android.os.Parcel; +import android.telephony.PhoneNumberUtils; +import android.util.Log; + +import com.android.internal.telephony.gsm.SuppServiceNotification; + +import java.util.ArrayList; +import java.util.Collections; + +/** + * RIL class for Motorola Wrigley 3G RILs which need + * supplementary service notification post-processing + * + * {@hide} + */ +public class MotoWrigley3GRIL extends RIL { + + public MotoWrigley3GRIL(Context context, int networkMode, int cdmaSubscription) { + super(context, networkMode, cdmaSubscription); + } + + @Override + protected Object + responseSuppServiceNotification(Parcel p) { + SuppServiceNotification notification = new SuppServiceNotification(); + + notification.notificationType = p.readInt(); + notification.code = p.readInt(); + notification.index = p.readInt(); + notification.type = p.readInt(); + notification.number = p.readString(); + + /** + * Moto's RIL seems to confuse code2 0 ('forwarded call') and + * 10 ('additional incoming call forwarded') and sends 10 when an + * incoming call is forwarded and _no_ call is currently active. + * It never sends 10 where it would be appropriate, so it's safe + * to just convert every occurence of 10 to 0. + */ + if (notification.notificationType == 1) { + if (notification.code == SuppServiceNotification.MT_CODE_ADDITIONAL_CALL_FORWARDED) { + notification.code = SuppServiceNotification.MT_CODE_FORWARDED_CALL; + } + } + + return notification; + } + + @Override + protected Object + responseCallList(Parcel p) { + int num; + int voiceSettings; + ArrayList response; + DriverCall dc; + + num = p.readInt(); + response = new ArrayList(num); + + for (int i = 0 ; i < num ; i++) { + dc = new DriverCall(); + + dc.state = DriverCall.stateFromCLCC(p.readInt()); + dc.index = p.readInt(); + dc.TOA = p.readInt(); + dc.isMpty = (0 != p.readInt()); + dc.isMT = (0 != p.readInt()); + dc.als = p.readInt(); + voiceSettings = p.readInt(); + dc.isVoice = (0 == voiceSettings) ? false : true; + dc.isVoicePrivacy = (0 != p.readInt()); + dc.number = p.readString(); + int np = p.readInt(); + /** numberPresentation needs to be overriden for outgoing calls + in case of Moto Wrigley3G RIL under ICS, to prevent outgoing calls + to be identified as "Unknown" on InCallScreen and in the call logs + when CallerID option is set to "Network default" or "Hide number". **/ + if (!dc.isMT) np = 0; + 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); + + return response; + } +} diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java index d41ce4d928a69..1da6f6f889c5d 100644 --- a/telephony/java/com/android/internal/telephony/Phone.java +++ b/telephony/java/com/android/internal/telephony/Phone.java @@ -215,6 +215,8 @@ enum SuppService { int NT_MODE_CDMA_NO_EVDO = RILConstants.NETWORK_MODE_CDMA_NO_EVDO; int NT_MODE_EVDO_NO_CDMA = RILConstants.NETWORK_MODE_EVDO_NO_CDMA; int NT_MODE_GLOBAL = RILConstants.NETWORK_MODE_GLOBAL; + int NT_MODE_LTE_CDMA_EVDO = RILConstants.NETWORK_MODE_LTE_CDMA_EVDO; + int NT_MODE_LTE_CMDA_EVDO_GSM_WCDMA = RILConstants.NETWORK_MODE_LTE_CMDA_EVDO_GSM_WCDMA; int NT_MODE_LTE_ONLY = RILConstants.NETWORK_MODE_LTE_ONLY; int PREFERRED_NT_MODE = RILConstants.PREFERRED_NETWORK_MODE; diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java index 2ac936593a429..6a41a3fd38963 100644 --- a/telephony/java/com/android/internal/telephony/PhoneBase.java +++ b/telephony/java/com/android/internal/telephony/PhoneBase.java @@ -1034,6 +1034,11 @@ protected void notifyNewRingingConnectionP(Connection cn) { if (!mIsVoiceCapable) return; AsyncResult ar = new AsyncResult(null, cn, null); + if (SystemProperties.getBoolean( + "ro.telephony.call_ring.absent", true)) { + sendMessageDelayed( + obtainMessage(EVENT_CALL_RING_CONTINUE, mCallRingContinueToken, 0), mCallRingDelay); + } mNewRingingConnectionRegistrants.notifyRegistrants(ar); } diff --git a/telephony/java/com/android/internal/telephony/PhoneFactory.java b/telephony/java/com/android/internal/telephony/PhoneFactory.java index f495d7e5e87c0..b8177deb9c677 100644 --- a/telephony/java/com/android/internal/telephony/PhoneFactory.java +++ b/telephony/java/com/android/internal/telephony/PhoneFactory.java @@ -30,6 +30,8 @@ import com.android.internal.telephony.sip.SipPhone; import com.android.internal.telephony.sip.SipPhoneFactory; +import java.lang.reflect.Constructor; + /** * {@hide} */ @@ -135,7 +137,20 @@ public static void makeDefaultPhone(Context context) { Log.i(LOG_TAG, "Cdma Subscription set to " + cdmaSubscription); //reads the system properties and makes commandsinterface - sCommandsInterface = new RIL(context, networkMode, cdmaSubscription); + String sRILClassname = SystemProperties.get("ro.telephony.ril_class", "RIL"); + Log.i(LOG_TAG, "RILClassname is " + sRILClassname); + + // Use reflection to construct the RIL class (defaults to RIL) + try { + Class classDefinition = Class.forName("com.android.internal.telephony." + sRILClassname); + Constructor constructor = classDefinition.getConstructor(new Class[] {Context.class, int.class, int.class}); + sCommandsInterface = (RIL) constructor.newInstance(new Object[] {context, networkMode, cdmaSubscription}); + } catch (Exception e) { + // 6 different types of exceptions are thrown here that it's + // easier to just catch Exception as our "error handling" is the same. + Log.wtf(LOG_TAG, "Unable to construct command interface", e); + throw new RuntimeException(e); + } int phoneType = getPhoneType(networkMode); if (phoneType == Phone.PHONE_TYPE_GSM) { diff --git a/telephony/java/com/android/internal/telephony/QualcommSharedRIL.java b/telephony/java/com/android/internal/telephony/QualcommSharedRIL.java new file mode 100644 index 0000000000000..c69fc84e2eb31 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/QualcommSharedRIL.java @@ -0,0 +1,831 @@ +/* + * 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.text.TextUtils; +import android.util.Log; + +import com.android.internal.telephony.RILConstants; +import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo; +import com.android.internal.telephony.cdma.CdmaInformationRecords; + +import java.util.ArrayList; + +/** + * Custom Qualcomm No SimReady RIL using the latest Uicc stack + * + * {@hide} + */ +public class QualcommSharedRIL extends RIL implements CommandsInterface { + protected HandlerThread mIccThread; + protected IccHandler mIccHandler; + protected String mAid; + protected boolean mUSIM = false; + protected String[] mLastDataIface = new String[20]; + boolean RILJ_LOGV = true; + boolean RILJ_LOGD = true; + + private final int RIL_INT_RADIO_OFF = 0; + private final int RIL_INT_RADIO_UNAVALIABLE = 1; + private final int RIL_INT_RADIO_ON = 2; + private final int RIL_INT_RADIO_ON_NG = 10; + private final int RIL_INT_RADIO_ON_HTC = 13; + + + public QualcommSharedRIL(Context context, int networkMode, int cdmaSubscription) { + super(context, networkMode, cdmaSubscription); + mSetPreferredNetworkType = -1; + } + + @Override public void + supplyIccPin2(String pin, Message result) { + supplyIccPin2ForApp(pin, mAid, result); + } + + @Override public void + changeIccPin2(String oldPin2, String newPin2, Message result) { + changeIccPin2ForApp(oldPin2, newPin2, mAid, result); + } + + @Override public void + supplyIccPuk(String puk, String newPin, Message result) { + supplyIccPukForApp(puk, newPin, mAid, result); + } + + @Override public void + supplyIccPuk2(String puk2, String newPin2, Message result) { + supplyIccPuk2ForApp(puk2, newPin2, mAid, result); + } + + @Override + public void + queryFacilityLock(String facility, String password, int serviceClass, + Message response) { + queryFacilityLockForApp(facility, password, serviceClass, mAid, response); + } + + @Override + public void + setFacilityLock (String facility, boolean lockState, String password, + int serviceClass, Message response) { + setFacilityLockForApp(facility, lockState, password, serviceClass, mAid, response); + } + + @Override + public void + getIMSI(Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_IMSI, result); + + rr.mp.writeInt(1); + rr.mp.writeString(mAid); + + if (RILJ_LOGD) riljLog(rr.serialString() + + "> getIMSI:RIL_REQUEST_GET_IMSI " + + RIL_REQUEST_GET_IMSI + + " aid: " + mAid + + " " + requestToString(rr.mRequest)); + + send(rr); + } + + @Override + public void + iccIO (int command, int fileid, String path, int p1, int p2, int p3, + String data, String pin2, Message result) { + //Note: This RIL request has not been renamed to ICC, + // but this request is also valid for SIM and RUIM + RILRequest rr + = RILRequest.obtain(RIL_REQUEST_SIM_IO, result); + + if (mUSIM) + path = path.replaceAll("7F20$","7FFF"); + + rr.mp.writeInt(command); + rr.mp.writeInt(fileid); + rr.mp.writeString(path); + rr.mp.writeInt(p1); + rr.mp.writeInt(p2); + rr.mp.writeInt(p3); + rr.mp.writeString(data); + rr.mp.writeString(pin2); + rr.mp.writeString(mAid); + + if (RILJ_LOGD) riljLog(rr.serialString() + "> iccIO: " + + " aid: " + mAid + " " + + requestToString(rr.mRequest) + + " 0x" + Integer.toHexString(command) + + " 0x" + Integer.toHexString(fileid) + " " + + " path: " + path + "," + + p1 + "," + p2 + "," + p3); + + send(rr); + } + + @Override + protected Object + responseIccCardStatus(Parcel p) { + IccCardApplication ca; + + IccCardStatus status = new IccCardStatus(); + status.setCardState(p.readInt()); + status.setUniversalPinState(p.readInt()); + status.setGsmUmtsSubscriptionAppIndex(p.readInt()); + status.setCdmaSubscriptionAppIndex(p.readInt()); + + status.setImsSubscriptionAppIndex(p.readInt()); + + int numApplications = p.readInt(); + + // limit to maximum allowed applications + if (numApplications > IccCardStatus.CARD_MAX_APPS) { + numApplications = IccCardStatus.CARD_MAX_APPS; + } + status.setNumApplications(numApplications); + + for (int i = 0; i < numApplications; i++) { + ca = new IccCardApplication(); + ca.app_type = ca.AppTypeFromRILInt(p.readInt()); + ca.app_state = ca.AppStateFromRILInt(p.readInt()); + ca.perso_substate = ca.PersoSubstateFromRILInt(p.readInt()); + ca.aid = p.readString(); + ca.app_label = p.readString(); + ca.pin1_replaced = p.readInt(); + ca.pin1 = ca.PinStateFromRILInt(p.readInt()); + ca.pin2 = ca.PinStateFromRILInt(p.readInt()); + p.readInt(); //remaining_count_pin1 + p.readInt(); //remaining_count_puk1 + p.readInt(); //remaining_count_pin2 + p.readInt(); //remaining_count_puk2 + status.addApplication(ca); + } + int appIndex = -1; + if (mPhoneType == RILConstants.CDMA_PHONE) { + appIndex = status.getCdmaSubscriptionAppIndex(); + Log.d(LOG_TAG, "This is a CDMA PHONE " + appIndex); + } else { + appIndex = status.getGsmUmtsSubscriptionAppIndex(); + Log.d(LOG_TAG, "This is a GSM PHONE " + appIndex); + } + + if (numApplications > 0) { + IccCardApplication application = status.getApplication(appIndex); + mAid = application.aid; + mUSIM = application.app_type + == IccCardApplication.AppType.APPTYPE_USIM; + mSetPreferredNetworkType = mPreferredNetworkType; + + if (TextUtils.isEmpty(mAid)) + mAid = ""; + Log.d(LOG_TAG, "mAid " + mAid); + } + + return status; + } + + @Override + protected DataCallState getDataCallState(Parcel p, int version) { + DataCallState dataCall = new DataCallState(); + + boolean oldRil = needsOldRilFeature("datacall"); + + if (!oldRil && version < 5) { + return super.getDataCallState(p, version); + } else if (!oldRil) { + dataCall.version = version; + dataCall.status = p.readInt(); + dataCall.suggestedRetryTime = p.readInt(); + dataCall.cid = p.readInt(); + dataCall.active = p.readInt(); + dataCall.type = p.readString(); + dataCall.ifname = p.readString(); + if ((dataCall.status == DataConnection.FailCause.NONE.getErrorCode()) && + TextUtils.isEmpty(dataCall.ifname) && dataCall.active != 0) { + throw new RuntimeException("getDataCallState, no ifname"); + } + String addresses = p.readString(); + if (!TextUtils.isEmpty(addresses)) { + dataCall.addresses = addresses.split(" "); + } + String dnses = p.readString(); + if (!TextUtils.isEmpty(dnses)) { + dataCall.dnses = dnses.split(" "); + } + String gateways = p.readString(); + if (!TextUtils.isEmpty(gateways)) { + dataCall.gateways = gateways.split(" "); + } + } else { + dataCall.version = 4; // was dataCall.version = version; + dataCall.cid = p.readInt(); + dataCall.active = p.readInt(); + dataCall.type = p.readString(); + dataCall.ifname = mLastDataIface[dataCall.cid]; + p.readString(); // skip APN + + if (TextUtils.isEmpty(dataCall.ifname)) { + dataCall.ifname = mLastDataIface[0]; + } + + String addresses = p.readString(); + if (!TextUtils.isEmpty(addresses)) { + dataCall.addresses = addresses.split(" "); + } + p.readInt(); // RadioTechnology + p.readInt(); // inactiveReason + + dataCall.dnses = new String[2]; + dataCall.dnses[0] = SystemProperties.get("net."+dataCall.ifname+".dns1"); + dataCall.dnses[1] = SystemProperties.get("net."+dataCall.ifname+".dns2"); + } + + return dataCall; + } + + @Override + protected Object + responseSetupDataCall(Parcel p) { + DataCallState dataCall; + + boolean oldRil = needsOldRilFeature("datacall"); + + if (!oldRil) + return super.responseSetupDataCall(p); + + dataCall = new DataCallState(); + dataCall.version = 4; + + dataCall.cid = 0; // Integer.parseInt(p.readString()); + p.readString(); + dataCall.ifname = p.readString(); + if ((dataCall.status == DataConnection.FailCause.NONE.getErrorCode()) && + TextUtils.isEmpty(dataCall.ifname) && dataCall.active != 0) { + throw new RuntimeException( + "RIL_REQUEST_SETUP_DATA_CALL response, no ifname"); + } + /* Use the last digit of the interface id as the cid */ + if (!needsOldRilFeature("singlepdp")) { + dataCall.cid = + Integer.parseInt(dataCall.ifname.substring(dataCall.ifname.length() - 1)); + } + + mLastDataIface[dataCall.cid] = dataCall.ifname; + + + String addresses = p.readString(); + if (!TextUtils.isEmpty(addresses)) { + dataCall.addresses = addresses.split(" "); + } + + dataCall.dnses = new String[2]; + dataCall.dnses[0] = SystemProperties.get("net."+dataCall.ifname+".dns1"); + dataCall.dnses[1] = SystemProperties.get("net."+dataCall.ifname+".dns2"); + dataCall.active = 1; + dataCall.status = 0; + + return dataCall; + } + + @Override + public void getNeighboringCids(Message response) { + if (!getRadioState().isOn()) + return; + + RILRequest rr = RILRequest.obtain( + RILConstants.RIL_REQUEST_GET_NEIGHBORING_CELL_IDS, response); + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + + send(rr); + } + + @Override + public void setCurrentPreferredNetworkType() { + if (RILJ_LOGD) riljLog("setCurrentPreferredNetworkType: " + mSetPreferredNetworkType); + setPreferredNetworkType(mSetPreferredNetworkType, null); + } + + @Override + public void setPreferredNetworkType(int networkType , Message response) { + /** + * If not using a USIM, ignore LTE mode and go to 3G + */ + if (!mUSIM && networkType == RILConstants.NETWORK_MODE_LTE_GSM_WCDMA && + mSetPreferredNetworkType >= RILConstants.NETWORK_MODE_WCDMA_PREF) { + networkType = RILConstants.NETWORK_MODE_WCDMA_PREF; + } + mSetPreferredNetworkType = networkType; + + super.setPreferredNetworkType(networkType, response); + } + + @Override + protected Object + responseSignalStrength(Parcel p) { + int numInts = 12; + int response[]; + + boolean oldRil = needsOldRilFeature("signalstrength"); + boolean noLte = false; + + /* TODO: Add SignalStrength class to match RIL_SignalStrength */ + response = new int[numInts]; + for (int i = 0 ; i < numInts ; i++) { + if ((oldRil || noLte) && i > 6 && i < 12) { + response[i] = -1; + } else { + response[i] = p.readInt(); + } + if (i == 7 && response[i] == 99) { + response[i] = -1; + noLte = true; + } + if (i == 8 && !(noLte || oldRil)) { + response[i] *= -1; + } + } + + return response; + } + + @Override + protected void + processSolicited (Parcel p) { + int serial, error; + boolean found = false; + + serial = p.readInt(); + error = p.readInt(); + + RILRequest rr; + + rr = findAndRemoveRequestFromList(serial); + + if (rr == null) { + Log.w(LOG_TAG, "Unexpected solicited response! sn: " + + serial + " error: " + error); + return; + } + + Object ret = null; + + if (error == 0 || p.dataAvail() > 0) { + + /* Convert RIL_REQUEST_GET_MODEM_VERSION back */ + if (SystemProperties.get("ro.cm.device").indexOf("e73") == 0 && + rr.mRequest == 220) { + rr.mRequest = RIL_REQUEST_BASEBAND_VERSION; + } + + // either command succeeds or command fails but with data payload + try {switch (rr.mRequest) { + /* + cat libs/telephony/ril_commands.h \ + | egrep "^ *{RIL_" \ + | sed -re 's/\{([^,]+),[^,]+,([^}]+).+/case \1: ret = \2(p); break;/' + */ + case RIL_REQUEST_GET_SIM_STATUS: ret = responseIccCardStatus(p); break; + case RIL_REQUEST_ENTER_SIM_PIN: ret = responseInts(p); break; + case RIL_REQUEST_ENTER_SIM_PUK: ret = responseInts(p); break; + case RIL_REQUEST_ENTER_SIM_PIN2: ret = responseInts(p); break; + case RIL_REQUEST_ENTER_SIM_PUK2: ret = responseInts(p); break; + case RIL_REQUEST_CHANGE_SIM_PIN: ret = responseInts(p); break; + case RIL_REQUEST_CHANGE_SIM_PIN2: ret = responseInts(p); break; + case RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION: ret = responseInts(p); break; + case RIL_REQUEST_GET_CURRENT_CALLS: ret = responseCallList(p); break; + case RIL_REQUEST_DIAL: ret = responseVoid(p); break; + case RIL_REQUEST_GET_IMSI: ret = responseString(p); break; + case RIL_REQUEST_HANGUP: ret = responseVoid(p); break; + case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND: ret = responseVoid(p); break; + case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND: ret = responseVoid(p); break; + case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE: ret = responseVoid(p); break; + case RIL_REQUEST_CONFERENCE: ret = responseVoid(p); break; + case RIL_REQUEST_UDUB: ret = responseVoid(p); break; + case RIL_REQUEST_LAST_CALL_FAIL_CAUSE: ret = responseInts(p); break; + case RIL_REQUEST_SIGNAL_STRENGTH: ret = responseSignalStrength(p); break; + case RIL_REQUEST_VOICE_REGISTRATION_STATE: ret = responseStrings(p); break; + case RIL_REQUEST_DATA_REGISTRATION_STATE: ret = responseStrings(p); break; + case RIL_REQUEST_OPERATOR: ret = responseStrings(p); break; + case RIL_REQUEST_RADIO_POWER: ret = responseVoid(p); break; + case RIL_REQUEST_DTMF: ret = responseVoid(p); break; + case RIL_REQUEST_SEND_SMS: ret = responseSMS(p); break; + case RIL_REQUEST_SEND_SMS_EXPECT_MORE: ret = responseSMS(p); break; + case RIL_REQUEST_SETUP_DATA_CALL: ret = responseSetupDataCall(p); break; + case RIL_REQUEST_SIM_IO: ret = responseICC_IO(p); break; + case RIL_REQUEST_SEND_USSD: ret = responseVoid(p); break; + case RIL_REQUEST_CANCEL_USSD: ret = responseVoid(p); break; + case RIL_REQUEST_GET_CLIR: ret = responseInts(p); break; + case RIL_REQUEST_SET_CLIR: ret = responseVoid(p); break; + case RIL_REQUEST_QUERY_CALL_FORWARD_STATUS: ret = responseCallForward(p); break; + case RIL_REQUEST_SET_CALL_FORWARD: ret = responseVoid(p); break; + case RIL_REQUEST_QUERY_CALL_WAITING: ret = responseInts(p); break; + case RIL_REQUEST_SET_CALL_WAITING: ret = responseVoid(p); break; + case RIL_REQUEST_SMS_ACKNOWLEDGE: ret = responseVoid(p); break; + case RIL_REQUEST_GET_IMEI: ret = responseString(p); break; + case RIL_REQUEST_GET_IMEISV: ret = responseString(p); break; + case RIL_REQUEST_ANSWER: ret = responseVoid(p); break; + case RIL_REQUEST_DEACTIVATE_DATA_CALL: ret = responseVoid(p); break; + case RIL_REQUEST_QUERY_FACILITY_LOCK: ret = responseInts(p); break; + case RIL_REQUEST_SET_FACILITY_LOCK: ret = responseInts(p); break; + case RIL_REQUEST_CHANGE_BARRING_PASSWORD: ret = responseVoid(p); break; + case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE: ret = responseInts(p); break; + case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC: ret = responseVoid(p); break; + case RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL: ret = responseVoid(p); break; + case RIL_REQUEST_QUERY_AVAILABLE_NETWORKS : ret = responseOperatorInfos(p); break; + case RIL_REQUEST_DTMF_START: ret = responseVoid(p); break; + case RIL_REQUEST_DTMF_STOP: ret = responseVoid(p); break; + case RIL_REQUEST_BASEBAND_VERSION: ret = responseString(p); break; + case RIL_REQUEST_SEPARATE_CONNECTION: ret = responseVoid(p); break; + case RIL_REQUEST_SET_MUTE: ret = responseVoid(p); break; + case RIL_REQUEST_GET_MUTE: ret = responseInts(p); break; + case RIL_REQUEST_QUERY_CLIP: ret = responseInts(p); break; + case RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE: ret = responseInts(p); break; + case RIL_REQUEST_DATA_CALL_LIST: ret = responseDataCallList(p); break; + case RIL_REQUEST_RESET_RADIO: ret = responseVoid(p); break; + case RIL_REQUEST_OEM_HOOK_RAW: ret = responseRaw(p); break; + case RIL_REQUEST_OEM_HOOK_STRINGS: ret = responseStrings(p); break; + case RIL_REQUEST_SCREEN_STATE: ret = responseVoid(p); break; + case RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION: ret = responseVoid(p); break; + case RIL_REQUEST_WRITE_SMS_TO_SIM: ret = responseInts(p); break; + case RIL_REQUEST_DELETE_SMS_ON_SIM: ret = responseVoid(p); break; + case RIL_REQUEST_SET_BAND_MODE: ret = responseVoid(p); break; + case RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE: ret = responseInts(p); break; + case RIL_REQUEST_STK_GET_PROFILE: ret = responseString(p); break; + case RIL_REQUEST_STK_SET_PROFILE: ret = responseVoid(p); break; + case RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND: ret = responseString(p); break; + case RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE: ret = responseVoid(p); break; + case RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM: ret = responseInts(p); break; + case RIL_REQUEST_EXPLICIT_CALL_TRANSFER: ret = responseVoid(p); break; + case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE: ret = responseVoid(p); break; + case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE: ret = responseGetPreferredNetworkType(p); break; + case RIL_REQUEST_GET_NEIGHBORING_CELL_IDS: ret = responseCellList(p); break; + case RIL_REQUEST_SET_LOCATION_UPDATES: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE: ret = responseInts(p); break; + case RIL_REQUEST_SET_TTY_MODE: ret = responseVoid(p); break; + case RIL_REQUEST_QUERY_TTY_MODE: ret = responseInts(p); break; + case RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE: ret = responseInts(p); break; + case RIL_REQUEST_CDMA_FLASH: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_BURST_DTMF: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_SEND_SMS: ret = responseSMS(p); break; + case RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE: ret = responseVoid(p); break; + case RIL_REQUEST_GSM_GET_BROADCAST_CONFIG: ret = responseGmsBroadcastConfig(p); break; + case RIL_REQUEST_GSM_SET_BROADCAST_CONFIG: ret = responseVoid(p); break; + case RIL_REQUEST_GSM_BROADCAST_ACTIVATION: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_GET_BROADCAST_CONFIG: ret = responseCdmaBroadcastConfig(p); break; + case RIL_REQUEST_CDMA_SET_BROADCAST_CONFIG: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_BROADCAST_ACTIVATION: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_SUBSCRIPTION: ret = responseStrings(p); break; + case RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM: ret = responseInts(p); break; + case RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM: ret = responseVoid(p); break; + case RIL_REQUEST_DEVICE_IDENTITY: ret = responseStrings(p); break; + case RIL_REQUEST_GET_SMSC_ADDRESS: ret = responseString(p); break; + case RIL_REQUEST_SET_SMSC_ADDRESS: ret = responseVoid(p); break; + case RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE: ret = responseVoid(p); break; + case RIL_REQUEST_REPORT_SMS_MEMORY_STATUS: ret = responseVoid(p); break; + case RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING: ret = responseVoid(p); break; + case 104: ret = responseInts(p); break; // RIL_REQUEST_VOICE_RADIO_TECH + case 105: ret = responseInts(p); break; // RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE + case 106: ret = responseStrings(p); break; // RIL_REQUEST_CDMA_PRL_VERSION + case 107: ret = responseInts(p); break; // RIL_REQUEST_IMS_REGISTRATION_STATE + case RIL_REQUEST_VOICE_RADIO_TECH: ret = responseInts(p); break; + + default: + throw new RuntimeException("Unrecognized solicited response: " + rr.mRequest); + //break; + }} catch (Throwable tr) { + // Exceptions here usually mean invalid RIL responses + + Log.w(LOG_TAG, rr.serialString() + "< " + + requestToString(rr.mRequest) + + " exception, possible invalid RIL response", tr); + + if (rr.mResult != null) { + AsyncResult.forMessage(rr.mResult, null, tr); + rr.mResult.sendToTarget(); + } + rr.release(); + return; + } + } + + if (error != 0) { + rr.onError(error, ret); + rr.release(); + return; + } + + 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(); + } + + rr.release(); + } + + @Override + protected void + processUnsolicited (Parcel p) { + Object ret; + int dataPosition = p.dataPosition(); // save off position within the Parcel + int response = p.readInt(); + + /* Assume devices needing the "datacall" GB-compatibility flag are + * running GB RILs, so skip 1031-1034 for those */ + if (needsOldRilFeature("datacall")) { + switch(response) { + case 1031: + case 1032: + case 1033: + case 1034: + ret = responseVoid(p); + return; + } + } + + switch(response) { + //case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED: ret = responseVoid(p); break; + case RIL_UNSOL_RIL_CONNECTED: ret = responseInts(p); break; + case 1035: ret = responseVoid(p); break; // RIL_UNSOL_VOICE_RADIO_TECH_CHANGED + case 1036: ret = responseVoid(p); break; // RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED + case 1037: ret = responseVoid(p); break; // RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE + case 1038: ret = responseVoid(p); break; // RIL_UNSOL_DATA_NETWORK_STATE_CHANGED + + default: + // Rewind the Parcel + p.setDataPosition(dataPosition); + + // Forward responses that we are not overriding to the super class + super.processUnsolicited(p); + return; + } + + switch(response) { + case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED: + int state = p.readInt(); + setRadioStateFromRILInt(state); + break; + case RIL_UNSOL_RIL_CONNECTED: + if (RILJ_LOGD) unsljLogRet(response, ret); + + notifyRegistrantsRilConnectionChanged(((int[])ret)[0]); + break; + case 1035: + case 1036: + break; + case 1037: // RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE + if (RILJ_LOGD) unsljLogRet(response, ret); + + if (mExitEmergencyCallbackModeRegistrants != null) { + mExitEmergencyCallbackModeRegistrants.notifyRegistrants( + new AsyncResult (null, null, null)); + } + break; + case 1038: + break; + } + } + + /** + * Notify all registrants that the ril has connected or disconnected. + * + * @param rilVer is the version of the ril or -1 if disconnected. + */ + private void notifyRegistrantsRilConnectionChanged(int rilVer) { + mRilVersion = rilVer; + if (mRilConnectedRegistrants != null) { + mRilConnectedRegistrants.notifyRegistrants( + new AsyncResult (null, new Integer(rilVer), null)); + } + } + + private void setRadioStateFromRILInt (int stateCode) { + CommandsInterface.RadioState radioState; + HandlerThread handlerThread; + Looper looper; + IccHandler iccHandler; + + switch (stateCode) { + case RIL_INT_RADIO_OFF: + radioState = CommandsInterface.RadioState.RADIO_OFF; + if (mIccHandler != null) { + mIccThread = null; + mIccHandler = null; + } + break; + case RIL_INT_RADIO_UNAVALIABLE: + radioState = CommandsInterface.RadioState.RADIO_UNAVAILABLE; + break; + case RIL_INT_RADIO_ON: + case RIL_INT_RADIO_ON_NG: + case RIL_INT_RADIO_ON_HTC: + if (mIccHandler == null) { + handlerThread = new HandlerThread("IccHandler"); + mIccThread = handlerThread; + + mIccThread.start(); + + looper = mIccThread.getLooper(); + mIccHandler = new IccHandler(this,looper); + mIccHandler.run(); + } + radioState = CommandsInterface.RadioState.RADIO_ON; + break; + default: + throw new RuntimeException("Unrecognized RIL_RadioState: " + stateCode); + } + + setRadioState (radioState); + } + + class IccHandler extends Handler implements Runnable { + private static final int EVENT_RADIO_ON = 1; + private static final int EVENT_ICC_STATUS_CHANGED = 2; + private static final int EVENT_GET_ICC_STATUS_DONE = 3; + private static final int EVENT_RADIO_OFF_OR_UNAVAILABLE = 4; + + private RIL mRil; + private boolean mRadioOn = false; + + public IccHandler (RIL ril, Looper looper) { + super (looper); + mRil = ril; + } + + public void handleMessage (Message paramMessage) { + switch (paramMessage.what) { + case EVENT_RADIO_ON: + mRadioOn = true; + Log.d(LOG_TAG, "Radio on -> Forcing sim status update"); + sendMessage(obtainMessage(EVENT_ICC_STATUS_CHANGED)); + break; + case EVENT_GET_ICC_STATUS_DONE: + AsyncResult asyncResult = (AsyncResult) paramMessage.obj; + if (asyncResult.exception != null) { + Log.e (LOG_TAG, "IccCardStatusDone shouldn't return exceptions!", asyncResult.exception); + break; + } + IccCardStatus status = (IccCardStatus) asyncResult.result; + if (status.getNumApplications() == 0) { + if (!mRil.getRadioState().isOn()) { + break; + } + + mRil.setRadioState(CommandsInterface.RadioState.RADIO_ON); + } else { + int appIndex = -1; + if (mPhoneType == RILConstants.CDMA_PHONE) { + appIndex = status.getCdmaSubscriptionAppIndex(); + Log.d(LOG_TAG, "This is a CDMA PHONE " + appIndex); + } else { + appIndex = status.getGsmUmtsSubscriptionAppIndex(); + Log.d(LOG_TAG, "This is a GSM PHONE " + appIndex); + } + + IccCardApplication application = status.getApplication(appIndex); + IccCardApplication.AppState app_state = application.app_state; + IccCardApplication.AppType app_type = application.app_type; + + switch (app_state) { + case APPSTATE_PIN: + case APPSTATE_PUK: + switch (app_type) { + case APPTYPE_SIM: + case APPTYPE_USIM: + case APPTYPE_RUIM: + mRil.setRadioState(CommandsInterface.RadioState.RADIO_ON); + break; + default: + Log.e(LOG_TAG, "Currently we don't handle SIMs of type: " + app_type); + return; + } + break; + case APPSTATE_READY: + switch (app_type) { + case APPTYPE_SIM: + case APPTYPE_USIM: + case APPTYPE_RUIM: + mRil.setRadioState(CommandsInterface.RadioState.RADIO_ON); + break; + default: + Log.e(LOG_TAG, "Currently we don't handle SIMs of type: " + app_type); + return; + } + break; + default: + return; + } + } + break; + case EVENT_ICC_STATUS_CHANGED: + if (mRadioOn) { + Log.d(LOG_TAG, "Received EVENT_ICC_STATUS_CHANGED, calling getIccCardStatus"); + mRil.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE, paramMessage.obj)); + } else { + Log.d(LOG_TAG, "Received EVENT_ICC_STATUS_CHANGED while radio is not ON. Ignoring"); + } + break; + case EVENT_RADIO_OFF_OR_UNAVAILABLE: + mRadioOn = false; + // disposeCards(); // to be verified; + default: + Log.e(LOG_TAG, " Unknown Event " + paramMessage.what); + break; + } + } + + public void run () { + mRil.registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, null); + Message msg = obtainMessage(EVENT_RADIO_ON); + mRil.getIccCardStatus(msg); + } + } + + + @Override + public void + supplyNetworkDepersonalization(String netpin, Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION, result); + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + + rr.mp.writeInt(3); + rr.mp.writeString(netpin); + + send(rr); + } + + @Override + public void + setNetworkSelectionModeManual(String operatorNumeric, Message response) { + RILRequest rr + = RILRequest.obtain(RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL, + response); + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + + " " + operatorNumeric); + + rr.mp.writeInt(2); + rr.mp.writeString(operatorNumeric); + rr.mp.writeString("NOCHANGE"); + + send(rr); + } + + @Override + protected Object + responseOperatorInfos(Parcel p) { + String strings[] = (String [])responseStrings(p); + ArrayList ret; + + if (strings.length % 5 != 0) { + throw new RuntimeException( + "RIL_REQUEST_QUERY_AVAILABLE_NETWORKS: invalid response. Got " + + strings.length + " strings, expected multiple of 5"); + } + + ret = new ArrayList(strings.length / 5); + + for (int i = 0 ; i < strings.length ; i += 5) { + ret.add ( + new OperatorInfo( + strings[i+0], + strings[i+1], + strings[i+2], + strings[i+3])); + } + + return ret; + } + +} diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java index b14f6c8ea60fd..1ace990cd2dfe 100644 --- a/telephony/java/com/android/internal/telephony/RIL.java +++ b/telephony/java/com/android/internal/telephony/RIL.java @@ -29,6 +29,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.res.Resources; import android.net.ConnectivityManager; import android.net.LocalSocket; import android.net.LocalSocketAddress; @@ -200,7 +201,7 @@ private RILRequest() { * * {@hide} */ -public final class RIL extends BaseCommands implements CommandsInterface { +public class RIL extends BaseCommands implements CommandsInterface { static final String LOG_TAG = "RILJ"; static final boolean RILJ_LOGD = true; static final boolean RILJ_LOGV = false; // STOP SHIP if true @@ -616,6 +617,7 @@ public RIL(Context context, int preferredNetworkType, int cdmaSubscription) { } mCdmaSubscription = cdmaSubscription; mPreferredNetworkType = preferredNetworkType; + mSetPreferredNetworkType = preferredNetworkType; mPhoneType = RILConstants.NO_PHONE; PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); @@ -697,9 +699,13 @@ public void getVoiceRadioTechnology(Message result) { if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); - rr.mp.writeInt(2); + boolean oldRil = needsOldRilFeature("facilitylock"); + + rr.mp.writeInt(oldRil ? 1 : 2); rr.mp.writeString(pin); - rr.mp.writeString(aid); + + if (!oldRil) + rr.mp.writeString(aid); send(rr); } @@ -717,10 +723,14 @@ public void getVoiceRadioTechnology(Message result) { if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); - rr.mp.writeInt(3); + boolean oldRil = needsOldRilFeature("facilitylock"); + + rr.mp.writeInt(oldRil ? 2 : 3); rr.mp.writeString(puk); rr.mp.writeString(newPin); - rr.mp.writeString(aid); + + if (!oldRil) + rr.mp.writeString(aid); send(rr); } @@ -738,9 +748,13 @@ public void getVoiceRadioTechnology(Message result) { if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); - rr.mp.writeInt(2); + boolean oldRil = needsOldRilFeature("facilitylock"); + + rr.mp.writeInt(oldRil ? 1 : 2); rr.mp.writeString(pin); - rr.mp.writeString(aid); + + if (!oldRil) + rr.mp.writeString(aid); send(rr); } @@ -758,10 +772,14 @@ public void getVoiceRadioTechnology(Message result) { if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); - rr.mp.writeInt(3); + boolean oldRil = needsOldRilFeature("facilitylock"); + + rr.mp.writeInt(oldRil ? 2 : 3); rr.mp.writeString(puk); rr.mp.writeString(newPin2); - rr.mp.writeString(aid); + + if (!oldRil) + rr.mp.writeString(aid); send(rr); } @@ -779,10 +797,14 @@ public void getVoiceRadioTechnology(Message result) { if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); - rr.mp.writeInt(3); + boolean oldRil = needsOldRilFeature("facilitylock"); + + rr.mp.writeInt(oldRil ? 2 : 3); rr.mp.writeString(oldPin); rr.mp.writeString(newPin); - rr.mp.writeString(aid); + + if (!oldRil) + rr.mp.writeString(aid); send(rr); } @@ -800,10 +822,14 @@ public void getVoiceRadioTechnology(Message result) { if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); - rr.mp.writeInt(3); + boolean oldRil = needsOldRilFeature("facilitylock"); + + rr.mp.writeInt(oldRil ? 2 : 3); rr.mp.writeString(oldPin2); rr.mp.writeString(newPin2); - rr.mp.writeString(aid); + + if (!oldRil) + rr.mp.writeString(aid); send(rr); } @@ -1659,14 +1685,18 @@ private int translateStatus(int status) { if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + boolean oldRil = needsOldRilFeature("facilitylock"); + // count strings - rr.mp.writeInt(4); + rr.mp.writeInt(oldRil ? 3 : 4); rr.mp.writeString(facility); rr.mp.writeString(password); rr.mp.writeString(Integer.toString(serviceClass)); - rr.mp.writeString(appId); + + if (!oldRil) + rr.mp.writeString(appId); send(rr); } @@ -1688,15 +1718,19 @@ private int translateStatus(int status) { if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + boolean oldRil = needsOldRilFeature("facilitylock"); + // count strings - rr.mp.writeInt(5); + rr.mp.writeInt(oldRil ? 4 : 5); rr.mp.writeString(facility); lockString = (lockState)?"1":"0"; rr.mp.writeString(lockString); rr.mp.writeString(password); rr.mp.writeString(Integer.toString(serviceClass)); - rr.mp.writeString(appId); + + if (!oldRil) + rr.mp.writeString(appId); send(rr); @@ -1862,7 +1896,7 @@ public void setCurrentPreferredNetworkType() { if (RILJ_LOGD) riljLog("setCurrentPreferredNetworkType: " + mSetPreferredNetworkType); setPreferredNetworkType(mSetPreferredNetworkType, null); } - private int mSetPreferredNetworkType; + protected int mSetPreferredNetworkType; /** * {@inheritDoc} @@ -2026,7 +2060,7 @@ public void setGsmBroadcastActivation(boolean activate, Message response) { //***** Private Methods - private void sendScreenState(boolean on) { + protected void sendScreenState(boolean on) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_SCREEN_STATE, null); rr.mp.writeInt(1); rr.mp.writeInt(on ? 1 : 0); @@ -2047,7 +2081,7 @@ private void sendScreenState(boolean on) { sendScreenState(true); } - private RadioState getRadioStateFromInt(int stateInt) { + protected RadioState getRadioStateFromInt(int stateInt) { RadioState state; /* RIL_RadioState ril.h */ @@ -2063,7 +2097,7 @@ private RadioState getRadioStateFromInt(int stateInt) { return state; } - private void switchToRadioState(RadioState newState) { + protected void switchToRadioState(RadioState newState) { setRadioState(newState); } @@ -2100,7 +2134,7 @@ private void switchToRadioState(RadioState newState) { } } - private void + protected void send(RILRequest rr) { Message msg; @@ -2117,7 +2151,7 @@ private void switchToRadioState(RadioState newState) { msg.sendToTarget(); } - private void + protected void processResponse (Parcel p) { int type; @@ -2137,7 +2171,7 @@ private void switchToRadioState(RadioState newState) { * @param error is the RIL_Errno sent back * @param loggable true means to print all requests in mRequestslist */ - private void clearRequestsList(int error, boolean loggable) { + protected void clearRequestsList(int error, boolean loggable) { RILRequest rr; synchronized (mRequestsList) { int count = mRequestsList.size(); @@ -2161,7 +2195,7 @@ private void clearRequestsList(int error, boolean loggable) { } } - private RILRequest findAndRemoveRequestFromList(int serial) { + protected RILRequest findAndRemoveRequestFromList(int serial) { synchronized (mRequestsList) { for (int i = 0, s = mRequestsList.size() ; i < s ; i++) { RILRequest rr = mRequestsList.get(i); @@ -2178,10 +2212,9 @@ private RILRequest findAndRemoveRequestFromList(int serial) { return null; } - private void + protected void processSolicited (Parcel p) { int serial, error; - boolean found = false; serial = p.readInt(); error = p.readInt(); @@ -2359,7 +2392,7 @@ private RILRequest findAndRemoveRequestFromList(int serial) { rr.release(); } - private String + protected String retToString(int req, Object ret) { if (ret == null) return ""; switch (req) { @@ -2423,7 +2456,7 @@ private RILRequest findAndRemoveRequestFromList(int serial) { return s; } - private void + protected void processUnsolicited (Parcel p) { int response; Object ret; @@ -2468,7 +2501,7 @@ private RILRequest findAndRemoveRequestFromList(int serial) { case RIL_UNSOL_RINGBACK_TONE: ret = responseInts(p); break; case RIL_UNSOL_RESEND_INCALL_MUTE: ret = responseVoid(p); break; case RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED: ret = responseInts(p); break; - case RIL_UNSOl_CDMA_PRL_CHANGED: ret = responseInts(p); break; + case RIL_UNSOL_CDMA_PRL_CHANGED: ret = responseInts(p); break; case RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE: ret = responseVoid(p); break; case RIL_UNSOL_RIL_CONNECTED: ret = responseInts(p); break; case RIL_UNSOL_VOICE_RADIO_TECH_CHANGED: ret = responseInts(p); break; @@ -2598,6 +2631,10 @@ private RILRequest findAndRemoveRequestFromList(int serial) { case RIL_UNSOL_DATA_CALL_LIST_CHANGED: if (RILJ_LOGD) unsljLogRet(response, ret); + boolean oldRil = needsOldRilFeature("skipbrokendatacall"); + if (oldRil && "IP".equals(((ArrayList)ret).get(0).type)) + break; + mDataNetworkStateRegistrants.notifyRegistrants(new AsyncResult(null, ret, null)); break; @@ -2801,7 +2838,7 @@ private RILRequest findAndRemoveRequestFromList(int serial) { } break; - case RIL_UNSOl_CDMA_PRL_CHANGED: + case RIL_UNSOL_CDMA_PRL_CHANGED: if (RILJ_LOGD) unsljLogRet(response, ret); if (mCdmaPrlChangedRegistrants != null) { @@ -2845,7 +2882,7 @@ private void notifyRegistrantsRilConnectionChanged(int rilVer) { } } - private Object + protected Object responseInts(Parcel p) { int numInts; int response[]; @@ -2862,12 +2899,12 @@ private void notifyRegistrantsRilConnectionChanged(int rilVer) { } - private Object + protected Object responseVoid(Parcel p) { return null; } - private Object + protected Object responseCallForward(Parcel p) { int numInfos; CallForwardInfo infos[]; @@ -2890,7 +2927,7 @@ private void notifyRegistrantsRilConnectionChanged(int rilVer) { return infos; } - private Object + protected Object responseSuppServiceNotification(Parcel p) { SuppServiceNotification notification = new SuppServiceNotification(); @@ -2903,7 +2940,7 @@ private void notifyRegistrantsRilConnectionChanged(int rilVer) { return notification; } - private Object + protected Object responseCdmaSms(Parcel p) { SmsMessage sms; sms = SmsMessage.newFromParcel(p); @@ -2911,7 +2948,7 @@ private void notifyRegistrantsRilConnectionChanged(int rilVer) { return sms; } - private Object + protected Object responseString(Parcel p) { String response; @@ -2920,7 +2957,7 @@ private void notifyRegistrantsRilConnectionChanged(int rilVer) { return response; } - private Object + protected Object responseStrings(Parcel p) { int num; String response[]; @@ -2939,7 +2976,7 @@ private void notifyRegistrantsRilConnectionChanged(int rilVer) { return response; } - private Object + protected Object responseRaw(Parcel p) { int num; byte response[]; @@ -2949,7 +2986,7 @@ private void notifyRegistrantsRilConnectionChanged(int rilVer) { return response; } - private Object + protected Object responseSMS(Parcel p) { int messageRef, errorCode; String ackPDU; @@ -2964,7 +3001,7 @@ private void notifyRegistrantsRilConnectionChanged(int rilVer) { } - private Object + protected Object responseICC_IO(Parcel p) { int sw1, sw2; byte data[] = null; @@ -2983,16 +3020,31 @@ private void notifyRegistrantsRilConnectionChanged(int rilVer) { return new IccIoResult(sw1, sw2, s); } - private Object + @Override + public boolean needsOldRilFeature(String feature) { + String[] features = SystemProperties.get("ro.telephony.ril.v3", "").split(","); + for (String found: features) { + if (found.equals(feature)) + return true; + } + return false; + } + + protected Object responseIccCardStatus(Parcel p) { IccCardApplication ca; + boolean oldRil = needsOldRilFeature("icccardstatus"); + IccCardStatus status = new IccCardStatus(); status.setCardState(p.readInt()); status.setUniversalPinState(p.readInt()); status.setGsmUmtsSubscriptionAppIndex(p.readInt()); status.setCdmaSubscriptionAppIndex(p.readInt()); - status.setImsSubscriptionAppIndex(p.readInt()); + + if (!oldRil) + status.setImsSubscriptionAppIndex(p.readInt()); + int numApplications = p.readInt(); // limit to maximum allowed applications @@ -3016,7 +3068,7 @@ private void notifyRegistrantsRilConnectionChanged(int rilVer) { return status; } - private Object + protected Object responseSimRefresh(Parcel p) { IccRefreshResponse response = new IccRefreshResponse(); @@ -3026,7 +3078,7 @@ private void notifyRegistrantsRilConnectionChanged(int rilVer) { return response; } - private Object + protected Object responseCallList(Parcel p) { int num; int voiceSettings; @@ -3103,7 +3155,7 @@ private void notifyRegistrantsRilConnectionChanged(int rilVer) { return response; } - private DataCallState getDataCallState(Parcel p, int version) { + protected DataCallState getDataCallState(Parcel p, int version) { DataCallState dataCall = new DataCallState(); dataCall.version = version; @@ -3111,13 +3163,19 @@ private DataCallState getDataCallState(Parcel p, int version) { dataCall.cid = p.readInt(); dataCall.active = p.readInt(); dataCall.type = p.readString(); + p.readString(); // APN - not used String addresses = p.readString(); if (!TextUtils.isEmpty(addresses)) { dataCall.addresses = addresses.split(" "); } + // DataCallState needs an ifname. Since we don't have one use the name from the ThrottleService resource (default=rmnet0). + dataCall.ifname = Resources.getSystem().getString(com.android.internal.R.string.config_datause_iface); } else { dataCall.status = p.readInt(); - dataCall.suggestedRetryTime = p.readInt(); + if (needsOldRilFeature("usehcradio")) + dataCall.suggestedRetryTime = -1; + else + dataCall.suggestedRetryTime = p.readInt(); dataCall.cid = p.readInt(); dataCall.active = p.readInt(); dataCall.type = p.readString(); @@ -3142,11 +3200,11 @@ private DataCallState getDataCallState(Parcel p, int version) { return dataCall; } - private Object + protected Object responseDataCallList(Parcel p) { ArrayList response; - - int ver = p.readInt(); + boolean oldRil = needsOldRilFeature("datacall"); + int ver = (oldRil ? 3 : p.readInt()); int num = p.readInt(); riljLog("responseDataCallList ver=" + ver + " num=" + num); @@ -3158,9 +3216,10 @@ private DataCallState getDataCallState(Parcel p, int version) { return response; } - private Object + protected Object responseSetupDataCall(Parcel p) { - int ver = p.readInt(); + boolean oldRil = needsOldRilFeature("datacall"); + int ver = (oldRil ? 3 : p.readInt()); int num = p.readInt(); if (RILJ_LOGV) riljLog("responseSetupDataCall ver=" + ver + " num=" + num); @@ -3205,7 +3264,7 @@ private DataCallState getDataCallState(Parcel p, int version) { return dataCall; } - private Object + protected Object responseOperatorInfos(Parcel p) { String strings[] = (String [])responseStrings(p); ArrayList ret; @@ -3230,7 +3289,7 @@ private DataCallState getDataCallState(Parcel p, int version) { return ret; } - private Object + protected Object responseCellList(Parcel p) { int num, rssi; String location; @@ -3272,7 +3331,7 @@ private DataCallState getDataCallState(Parcel p, int version) { return response; } - private Object responseGetPreferredNetworkType(Parcel p) { + protected Object responseGetPreferredNetworkType(Parcel p) { int [] response = (int[]) responseInts(p); if (response.length >= 1) { @@ -3284,7 +3343,7 @@ private Object responseGetPreferredNetworkType(Parcel p) { return response; } - private Object responseGmsBroadcastConfig(Parcel p) { + protected Object responseGmsBroadcastConfig(Parcel p) { int num; ArrayList response; SmsBroadcastConfigInfo info; @@ -3306,7 +3365,7 @@ private Object responseGmsBroadcastConfig(Parcel p) { return response; } - private Object + protected Object responseCdmaBroadcastConfig(Parcel p) { int numServiceCategories; int response[]; @@ -3345,21 +3404,27 @@ private Object responseGmsBroadcastConfig(Parcel p) { return response; } - private Object + protected Object responseSignalStrength(Parcel p) { int numInts = 12; int response[]; + boolean oldRil = needsOldRilFeature("signalstrength"); + /* TODO: Add SignalStrength class to match RIL_SignalStrength */ response = new int[numInts]; for (int i = 0 ; i < numInts ; i++) { - response[i] = p.readInt(); + if (oldRil && i > 6 && i < 12) { + response[i] = -1; + } else { + response[i] = p.readInt(); + } } return response; } - private ArrayList + protected ArrayList responseCdmaInformationRecord(Parcel p) { int numberOfInfoRecs; ArrayList response; @@ -3379,7 +3444,7 @@ private Object responseGmsBroadcastConfig(Parcel p) { return response; } - private Object + protected Object responseCdmaCallWaiting(Parcel p) { CdmaCallWaitingNotification notification = new CdmaCallWaitingNotification(); @@ -3397,7 +3462,7 @@ private Object responseGmsBroadcastConfig(Parcel p) { return notification; } - private Object + protected Object responseCallRing(Parcel p){ char response[] = new char[4]; @@ -3409,7 +3474,7 @@ private Object responseGmsBroadcastConfig(Parcel p) { return response; } - private void + protected void notifyRegistrantsCdmaInfoRec(CdmaInformationRecords infoRec) { int response = RIL_UNSOL_CDMA_INFO_REC; if (infoRec.record instanceof CdmaInformationRecords.CdmaDisplayInfoRec) { @@ -3573,7 +3638,7 @@ private Object responseGmsBroadcastConfig(Parcel p) { case RIL_REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU: return "RIL_REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU"; case RIL_REQUEST_STK_SEND_ENVELOPE_WITH_STATUS: return "RIL_REQUEST_STK_SEND_ENVELOPE_WITH_STATUS"; case RIL_REQUEST_VOICE_RADIO_TECH: return "RIL_REQUEST_VOICE_RADIO_TECH"; - default: return ""; + default: return ""; } } @@ -3615,38 +3680,38 @@ private Object responseGmsBroadcastConfig(Parcel p) { case RIL_UNSOL_CDMA_OTA_PROVISION_STATUS: return "UNSOL_CDMA_OTA_PROVISION_STATUS"; case RIL_UNSOL_CDMA_INFO_REC: return "UNSOL_CDMA_INFO_REC"; case RIL_UNSOL_OEM_HOOK_RAW: return "UNSOL_OEM_HOOK_RAW"; - case RIL_UNSOL_RINGBACK_TONE: return "UNSOL_RINGBACK_TONG"; + case RIL_UNSOL_RINGBACK_TONE: return "UNSOL_RINGBACK_TONE"; case RIL_UNSOL_RESEND_INCALL_MUTE: return "UNSOL_RESEND_INCALL_MUTE"; case RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED: return "CDMA_SUBSCRIPTION_SOURCE_CHANGED"; - case RIL_UNSOl_CDMA_PRL_CHANGED: return "UNSOL_CDMA_PRL_CHANGED"; + case RIL_UNSOL_CDMA_PRL_CHANGED: return "UNSOL_CDMA_PRL_CHANGED"; case RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE: return "UNSOL_EXIT_EMERGENCY_CALLBACK_MODE"; case RIL_UNSOL_RIL_CONNECTED: return "UNSOL_RIL_CONNECTED"; case RIL_UNSOL_VOICE_RADIO_TECH_CHANGED: return "UNSOL_VOICE_RADIO_TECH_CHANGED"; - default: return ""; + default: return ""; } } - private void riljLog(String msg) { + protected void riljLog(String msg) { Log.d(LOG_TAG, msg); } - private void riljLogv(String msg) { + protected void riljLogv(String msg) { Log.v(LOG_TAG, msg); } - private void unsljLog(int response) { + protected void unsljLog(int response) { riljLog("[UNSL]< " + responseToString(response)); } - private void unsljLogMore(int response, String more) { + protected void unsljLogMore(int response, String more) { riljLog("[UNSL]< " + responseToString(response) + " " + more); } - private void unsljLogRet(int response, Object ret) { + protected void unsljLogRet(int response, Object ret) { riljLog("[UNSL]< " + responseToString(response) + " " + retToString(response, ret)); } - private void unsljLogvRet(int response, Object ret) { + protected void unsljLogvRet(int response, Object ret) { riljLogv("[UNSL]< " + responseToString(response) + " " + retToString(response, ret)); } diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java index f501b210709d6..c095b5d0ef2c4 100644 --- a/telephony/java/com/android/internal/telephony/RILConstants.java +++ b/telephony/java/com/android/internal/telephony/RILConstants.java @@ -293,7 +293,7 @@ class C */ int RIL_UNSOL_RINGBACK_TONE = 1029; int RIL_UNSOL_RESEND_INCALL_MUTE = 1030; int RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED = 1031; - int RIL_UNSOl_CDMA_PRL_CHANGED = 1032; + int RIL_UNSOL_CDMA_PRL_CHANGED = 1032; int RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE = 1033; int RIL_UNSOL_RIL_CONNECTED = 1034; int RIL_UNSOL_VOICE_RADIO_TECH_CHANGED = 1035; diff --git a/telephony/java/com/android/internal/telephony/SamsungCDMAQualcommRIL.java b/telephony/java/com/android/internal/telephony/SamsungCDMAQualcommRIL.java new file mode 100644 index 0000000000000..53135ec695e40 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/SamsungCDMAQualcommRIL.java @@ -0,0 +1,270 @@ +/* + * 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.text.TextUtils; +import android.util.Log; + +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; + +/** + * Samsung CDMA RIL doesn't send CDMA NV in RIUM infomation format which causes + * the CDMA RIL stack to crash and end up not being provisioned. Samsung put + * CDMA NV in GSM format. I forced the RIL stack to process CDMA NV request as a + * GSM SIM in CDMA mode. Custom Qualcomm No SimReady RIL using the latest Uicc + * stack + * + * {@hide} + */ +public class SamsungCDMAQualcommRIL extends QualcommSharedRIL implements +CommandsInterface { + + public SamsungCDMAQualcommRIL(Context context, int networkMode, + int cdmaSubscription) { + super(context, networkMode, cdmaSubscription); + } + + @Override + protected Object responseIccCardStatus(Parcel p) { + IccCardApplication ca; + + IccCardStatus status = new IccCardStatus(); + status.setCardState(p.readInt()); + status.setUniversalPinState(p.readInt()); + status.setGsmUmtsSubscriptionAppIndex(p.readInt()); + status.setCdmaSubscriptionAppIndex(p.readInt()); + + status.setImsSubscriptionAppIndex(p.readInt()); + + int numApplications = p.readInt(); + + // limit to maximum allowed applications + if (numApplications > IccCardStatus.CARD_MAX_APPS) { + numApplications = IccCardStatus.CARD_MAX_APPS; + } + status.setNumApplications(numApplications); + + for (int i = 0; i < numApplications; i++) { + ca = new IccCardApplication(); + ca.app_type = ca.AppTypeFromRILInt(p.readInt()); + ca.app_state = ca.AppStateFromRILInt(p.readInt()); + ca.perso_substate = ca.PersoSubstateFromRILInt(p.readInt()); + if ((ca.app_state == IccCardApplication.AppState.APPSTATE_SUBSCRIPTION_PERSO) && + ((ca.perso_substate == IccCardApplication.PersoSubState.PERSOSUBSTATE_READY) || + (ca.perso_substate == IccCardApplication.PersoSubState.PERSOSUBSTATE_UNKNOWN))) { + // ridiculous hack for network SIM unlock pin + ca.app_state = IccCardApplication.AppState.APPSTATE_UNKNOWN; + Log.d(LOG_TAG, "ca.app_state == AppState.APPSTATE_SUBSCRIPTION_PERSO"); + Log.d(LOG_TAG, "ca.perso_substate == PersoSubState.PERSOSUBSTATE_READY"); + } + ca.aid = p.readString(); + ca.app_label = p.readString(); + ca.pin1_replaced = p.readInt(); + ca.pin1 = ca.PinStateFromRILInt(p.readInt()); + ca.pin2 = ca.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 + status.addApplication(ca); + } + return status; + } + + @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(); + } + // 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[7] = -1; + response[8] = -1; + response[9] = -1; + response[10] = -1; + response[11] = -1; + } else { + response[8] *= -1; + } + + return response; + + } + + @Override + protected Object responseCallList(Parcel p) { + int num; + int voiceSettings; + ArrayList response; + DriverCall dc; + + num = p.readInt(); + response = new ArrayList(num); + + for (int i = 0; i < num; i++) { + dc = new DriverCall(); + + dc.state = DriverCall.stateFromCLCC(p.readInt()); + dc.index = p.readInt(); + dc.TOA = p.readInt(); + dc.isMpty = (0 != p.readInt()); + dc.isMT = (0 != p.readInt()); + dc.als = p.readInt(); + voiceSettings = p.readInt(); + dc.isVoice = (0 == voiceSettings) ? false : true; + dc.isVoicePrivacy = (0 != p.readInt()); + // Some Samsung magic data for Videocalls + // hack taken from smdk4210ril class + voiceSettings = p.readInt(); + // printing it to cosole for later investigation + Log.d(LOG_TAG, "Samsung magic = " + voiceSettings); + 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); + + return response; + } + + // 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); + } +} diff --git a/telephony/java/com/android/internal/telephony/SamsungHCRIL.java b/telephony/java/com/android/internal/telephony/SamsungHCRIL.java new file mode 100644 index 0000000000000..106de6fa82a28 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/SamsungHCRIL.java @@ -0,0 +1,87 @@ +package com.android.internal.telephony; + +import android.content.Context; +import android.os.Message; +import android.os.Parcel; +import android.os.SystemProperties; +import android.util.Log; +import static com.android.internal.telephony.RILConstants.*; + +public class SamsungHCRIL extends RIL implements CommandsInterface { + + private boolean mSignalbarCount = SystemProperties.getInt("ro.telephony.sends_barcount", 0) == 1 ? true : false; + + public SamsungHCRIL(Context context, int networkMode, int cdmaSubscription) { + super(context, networkMode, cdmaSubscription); + } + static final String LOG_TAG = "RILJ"; + //SAMSUNG SGS STATES + static final int RIL_UNSOL_STK_SEND_SMS_RESULT = 11002; + static final int RIL_UNSOL_O2_HOME_ZONE_INFO = 11007; + static final int RIL_UNSOL_DEVICE_READY_NOTI = 11008; + static final int RIL_UNSOL_SAMSUNG_UNKNOWN_MAGIC_REQUEST_3 = 11010; + static final int RIL_UNSOL_SAMSUNG_UNKNOWN_MAGIC_REQUEST_2 = 11011; + static final int RIL_UNSOL_HSDPA_STATE_CHANGED = 11016; + static final int RIL_UNSOL_SAMSUNG_UNKNOWN_MAGIC_REQUEST = 11012; + static final int RIL_REQUEST_DIAL_EMERGENCY = 10016; + + @Override + public void + setRadioPower(boolean on, Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_RADIO_POWER, result); + //samsung stuff for airplane mode + if (on) { + rr.mp.writeInt(1); + rr.mp.writeInt(1); + } else { + rr.mp.writeInt(2); + rr.mp.writeInt(0); + rr.mp.writeInt(0); + } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + + (on ? " on" : " off")); + } + send(rr); + } + + @Override + protected Object + responseSignalStrength(Parcel p) { + int numInts = 12; + int response[]; + + boolean oldRil = needsOldRilFeature("signalstrength"); + + /* TODO: Add SignalStrength class to match RIL_SignalStrength */ + response = new int[numInts]; + for (int i = 0 ; i < numInts ; i++) { + if (oldRil && i > 6 && i < 12) { + response[i] = -1; + } else { + response[i] = p.readInt(); + } + } + + /* Matching Samsung signal strength to asu. + Method taken from Samsungs cdma/gsmSignalStateTracker */ + if(mSignalbarCount) + { + //Samsung sends the count of bars that should be displayed instead of + //a real signal strength + response[0] = ((response[0] & 0xFF00) >> 8) * 3; //gsmDbm + } else { + response[0] = response[0] & 0xFF; //gsmDbm + } + response[1] = -1; //gsmEcio + response[2] = (response[2] < 0)?-120:-response[2]; //cdmaDbm + response[3] = (response[3] < 0)?-160:-response[3]; //cdmaEcio + response[4] = (response[4] < 0)?-120:-response[4]; //evdoRssi + response[5] = (response[5] < 0)?-1:-response[5]; //evdoEcio + if(response[6] < 0 || response[6] > 8) + response[6] = -1; + + return response; + } + +} diff --git a/telephony/java/com/android/internal/telephony/SamsungQualcommD2RIL.java b/telephony/java/com/android/internal/telephony/SamsungQualcommD2RIL.java new file mode 100644 index 0000000000000..bd7c1d558f1b6 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/SamsungQualcommD2RIL.java @@ -0,0 +1,110 @@ +/* + * 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.Parcel; +import android.os.SystemProperties; +import android.util.Log; +import com.android.internal.telephony.RILConstants; +import java.util.Collections; +import android.telephony.PhoneNumberUtils; + +import java.util.ArrayList; + +/** + * Custom RIL to handle unique behavior of D2 radio + * + * {@hide} + */ +public class SamsungQualcommD2RIL extends SamsungQualcommUiccRIL implements CommandsInterface { + public SamsungQualcommD2RIL(Context context, int networkMode, int cdmaSubscription) { + super(context, networkMode, cdmaSubscription); + } + + @Override + protected Object + responseCallList(Parcel p) { + int num; + int voiceSettings; + ArrayList response; + DriverCall dc; + + num = p.readInt(); + response = new ArrayList(num); + + for (int i = 0 ; i < num ; i++) { + dc = new DriverCall(); + + dc.state = DriverCall.stateFromCLCC(p.readInt()); + dc.index = p.readInt(); + dc.TOA = p.readInt(); + dc.isMpty = (0 != p.readInt()); + dc.isMT = (0 != p.readInt()); + dc.als = p.readInt(); + voiceSettings = p.readInt(); + dc.isVoice = (0 == voiceSettings) ? false : true; + dc.isVoicePrivacy = (0 != p.readInt()); + //Some Samsung magic data for Videocalls + // hack taken from smdk4210ril class + voiceSettings = p.readInt(); + //printing it to cosole for later investigation + Log.d(LOG_TAG, "Samsung magic = " + voiceSettings); + 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); + + return response; + } +} diff --git a/telephony/java/com/android/internal/telephony/SamsungQualcommUiccRIL.java b/telephony/java/com/android/internal/telephony/SamsungQualcommUiccRIL.java new file mode 100644 index 0000000000000..2c942ea2590a1 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/SamsungQualcommUiccRIL.java @@ -0,0 +1,301 @@ +/* + * 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.Message; +import android.os.Parcel; +import android.os.SystemProperties; +import android.os.AsyncResult; +import android.text.TextUtils; +import android.util.Log; +import com.android.internal.telephony.RILConstants; + +import java.util.ArrayList; + +/** + * Custom RIL to handle unique behavior of Hercules/Skyrocket/Note radio + * + * {@hide} + */ +public class SamsungQualcommUiccRIL extends QualcommSharedRIL implements CommandsInterface { + boolean RILJ_LOGV = true; + boolean RILJ_LOGD = true; + + public static final int INVALID_SNR = 0x7fffffff; + private boolean mSignalbarCount = SystemProperties.getBoolean("ro.telephony.sends_barcount", false); + + public SamsungQualcommUiccRIL(Context context, int networkMode, int cdmaSubscription) { + super(context, networkMode, cdmaSubscription); + } + + @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_NITZ_TIME_RECEIVED: + handleNitzTimeReceived(p); + return; + case 1038: ret = responseVoid(p); break; // RIL_UNSOL_DATA_NETWORK_STATE_CHANGED + + default: + // Rewind the Parcel + p.setDataPosition(dataPosition); + + // Forward responses that we are not overriding to the super class + super.processUnsolicited(p); + return; + } + + switch(response) { + case 1038: // RIL_UNSOL_DATA_NETWORK_STATE_CHANGED + if (RILJ_LOGD) unsljLog(response); + + // Notifying on voice state change since it just causes a + // GsmServiceStateTracker::pollState() like CAF RIL does. + mVoiceNetworkStateRegistrants + .notifyRegistrants(new AsyncResult(null, null, null)); + break; + } + } + + protected 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); + + if (mNITZTimeRegistrant != null) { + + mNITZTimeRegistrant + .notifyRegistrant(new AsyncResult (null, result, null)); + } else { + // in case NITZ time registrant isnt registered yet + mLastNITZTimeInfo = result; + } + } + + @Override + public void + setNetworkSelectionModeManual(String operatorNumeric, Message response) { + RILRequest rr + = RILRequest.obtain(RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL, + response); + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + + " " + operatorNumeric); + + rr.mp.writeString(operatorNumeric); + + send(rr); + } + + @Override + protected Object + responseOperatorInfos(Parcel p) { + String strings[] = (String [])responseStrings(p); + ArrayList ret; + + if (strings.length % 4 != 0) { + throw new RuntimeException( + "RIL_REQUEST_QUERY_AVAILABLE_NETWORKS: invalid response. Got " + + strings.length + " strings, expected multible of 4"); + } + + ret = new ArrayList(strings.length / 4); + + for (int i = 0 ; i < strings.length ; i += 4) { + ret.add ( + new OperatorInfo( + strings[i+0], + strings[i+1], + strings[i+2], + strings[i+3])); + } + + return ret; + } + + @Override + protected Object + responseIccCardStatus(Parcel p) { + IccCardApplication ca; + + IccCardStatus status = new IccCardStatus(); + status.setCardState(p.readInt()); + status.setUniversalPinState(p.readInt()); + status.setGsmUmtsSubscriptionAppIndex(p.readInt()); + status.setCdmaSubscriptionAppIndex(p.readInt() ); + + status.setImsSubscriptionAppIndex(p.readInt()); + + int numApplications = p.readInt(); + + // limit to maximum allowed applications + if (numApplications > IccCardStatus.CARD_MAX_APPS) { + numApplications = IccCardStatus.CARD_MAX_APPS; + } + status.setNumApplications(numApplications); + + for (int i = 0 ; i < numApplications ; i++) { + ca = new IccCardApplication(); + ca.app_type = ca.AppTypeFromRILInt(p.readInt()); + ca.app_state = ca.AppStateFromRILInt(p.readInt()); + ca.perso_substate = ca.PersoSubstateFromRILInt(p.readInt()); + ca.aid = p.readString(); + ca.app_label = p.readString(); + ca.pin1_replaced = p.readInt(); + ca.pin1 = ca.PinStateFromRILInt(p.readInt()); + ca.pin2 = ca.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 + status.addApplication(ca); + } + int appIndex = -1; + if (mPhoneType == RILConstants.CDMA_PHONE) { + appIndex = status.getCdmaSubscriptionAppIndex(); + Log.d(LOG_TAG, "This is a CDMA PHONE " + appIndex); + } else { + appIndex = status.getGsmUmtsSubscriptionAppIndex(); + Log.d(LOG_TAG, "This is a GSM PHONE " + appIndex); + } + + if (numApplications > 0) { + IccCardApplication application = status.getApplication(appIndex); + mAid = application.aid; + mUSIM = application.app_type + == IccCardApplication.AppType.APPTYPE_USIM; + mSetPreferredNetworkType = mPreferredNetworkType; + + if (TextUtils.isEmpty(mAid)) + mAid = ""; + Log.d(LOG_TAG, "mAid " + mAid + " mUSIM=" + mUSIM + " mSetPreferredNetworkType=" + mSetPreferredNetworkType); + } + + return status; + } + + @Override + protected Object + responseSignalStrength(Parcel p) { + int numInts = 12; + int response[]; + + // This is a mashup of algorithms used in + // LGEQualcommUiccRIL.java and SamsungHCRIL.java + + // Get raw data + response = new int[numInts]; + for (int i = 0 ; i < numInts ; i++) { + response[i] = p.readInt(); + } + Log.d(LOG_TAG, "responseSignalStength BEFORE: mode=" + (mSignalbarCount ? "bars" : "raw") + + " gsmDbm=" + response[0] + " gsmEcio=" + response[1] + + " lteSignalStrength=" + response[7] + " lteRsrp=" + response[8] + " lteRsrq=" + response[9] + + " lteRssnr=" + response[10] + " lteCqi=" + response[11]); + + // RIL_GW_SignalStrength + if (mSignalbarCount) { + //Samsung sends the count of bars that should be displayed instead of + //a real signal strength + int num_bars = (response[0] & 0xff00) >> 8; + + // Translate number of bars into something SignalStrength.java can understand + switch (num_bars) { + case 0 : response[0] = 1; break; // map to 0 bars + case 1 : response[0] = 3; break; // map to 1 bar + case 2 : response[0] = 5; break; // map to 2 bars + case 3 : response[0] = 8; break; // map to 3 bars + case 4 : response[0] = 12; break; // map to 4 bars + case 5 : response[0] = 15; break; // map to 4 bars but give an extra 10 dBm + default : response[0] &= 0xff; break; // no idea; just pass value through + } + } else { + response[0] &= 0xff; //gsmDbm + } + response[1] = -1; // gsmEcio + + // RIL_CDMA_SignalStrength (unused) + response[2] = -1; // cdmaDbm + response[3] = -1; // cdmaEcio + + // RIL_EVDO_SignalStrength (unused) + response[4] = -1; // evdoRssi + response[5] = -1; // evdoEcio + response[6] = -1; // evdoSNR + + // 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[7] = -1; // lteSignalStrength + response[8] = -1; // lteRsrp + response[9] = -1; // lteRsrq + response[10] = -1; // lteRssnr + response[11] = -1; // lteCqi + } else if (mSignalbarCount) { + int num_bars = (response[7] & 0xff00) >> 8; + response[7] &= 0xff; // remove the Samsung number of bars field + response[10] = INVALID_SNR; // mark lteRssnr invalid so it doesn't get used + + // Translate number of bars into something SignalStrength.java can understand + switch (num_bars) { + case 0 : response[8] = -1; break; // map to 0 bars + case 1 : response[8] = -116; break; // map to 1 bar + case 2 : response[8] = -115; break; // map to 2 bars + case 3 : response[8] = -105; break; // map to 3 bars + case 4 : response[8] = -95; break; // map to 4 bars + case 5 : response[8] = -85; break; // map to 4 bars but give an extra 10 dBm + default : response[8] *= -1; break; // no idea; just pass value through + } + } else { + response[7] &= 0xff; // remove the Samsung number of bars field + response[8] *= -1; + } + + Log.d(LOG_TAG, "responseSignalStength AFTER: mode=" + (mSignalbarCount ? "bars" : "raw") + + " gsmDbm=" + response[0] + " gsmEcio=" + response[1] + + " lteSignalStrength=" + response[7] + " lteRsrp=" + response[8] + " lteRsrq=" + response[9] + + " lteRssnr=" + response[10] + " lteCqi=" + response[11]); + return response; + } +} diff --git a/telephony/java/com/android/internal/telephony/SamsungRIL.java b/telephony/java/com/android/internal/telephony/SamsungRIL.java new file mode 100644 index 0000000000000..6d3ba413636fb --- /dev/null +++ b/telephony/java/com/android/internal/telephony/SamsungRIL.java @@ -0,0 +1,968 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * Copyright (C) 2011, 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 java.util.ArrayList; +import java.util.Collections; +import java.lang.Runtime; +import java.io.IOException; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.ConnectivityManager; +import android.os.Handler; +import android.os.Message; +import android.os.AsyncResult; +import android.os.Parcel; +import android.os.SystemProperties; +import android.telephony.PhoneNumberUtils; +import android.telephony.SmsManager; +import android.telephony.SmsMessage; +import static com.android.internal.telephony.RILConstants.*; + +import com.android.internal.telephony.CallForwardInfo; +import com.android.internal.telephony.CommandException; +import com.android.internal.telephony.DataCallState; +import com.android.internal.telephony.DataConnection.FailCause; +import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo; +import com.android.internal.telephony.gsm.SuppServiceNotification; +import com.android.internal.telephony.IccCardApplication; +import com.android.internal.telephony.IccCardStatus; +import com.android.internal.telephony.IccUtils; +import com.android.internal.telephony.RILConstants; +import com.android.internal.telephony.SmsResponse; +import com.android.internal.telephony.cdma.CdmaCallWaitingNotification; +import com.android.internal.telephony.cdma.CdmaInformationRecords; +import com.android.internal.telephony.cdma.CdmaInformationRecords.CdmaSignalInfoRec; +import com.android.internal.telephony.cdma.SignalToneUtil; + +import android.util.Log; + +public class SamsungRIL extends RIL implements CommandsInterface { + + private boolean mSignalbarCount = SystemProperties.getInt("ro.telephony.sends_barcount", 0) == 1 ? true : false; + private boolean mIsSamsungCdma = SystemProperties.getBoolean("ro.ril.samsung_cdma", false); + + public SamsungRIL(Context context, int networkMode, int cdmaSubscription) { + super(context, networkMode, cdmaSubscription); + } + + // SAMSUNG SGS STATES + static final int RIL_UNSOL_O2_HOME_ZONE_INFO = 11007; + static final int RIL_UNSOL_DEVICE_READY_NOTI = 11008; + static final int RIL_UNSOL_GPS_NOTI = 11009; + static final int RIL_UNSOL_AM = 11010; + static final int RIL_UNSOL_SAMSUNG_UNKNOWN_MAGIC_REQUEST = 11012; + static final int RIL_UNSOL_SAMSUNG_UNKNOWN_MAGIC_REQUEST_2 = 11011; + static final int RIL_UNSOL_HSDPA_STATE_CHANGED = 11016; + static final int RIL_REQUEST_DIAL_EMERGENCY = 10016; + + static String + requestToString(int request) { + switch (request) { + case RIL_REQUEST_DIAL_EMERGENCY: return "DIAL_EMERGENCY"; + default: return RIL.requestToString(request); + } + } + + @Override + public void + setRadioPower(boolean on, Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_RADIO_POWER, result); + + if (on) { + rr.mp.writeInt(1); + rr.mp.writeInt(1); + } else { + rr.mp.writeInt(2); + rr.mp.writeInt(0); + rr.mp.writeInt(0); + } + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + send(rr); + } + + @Override + protected void + processSolicited (Parcel p) { + int serial, error; + + serial = p.readInt(); + error = p.readInt(); + + Log.d(LOG_TAG, "Serial: " + serial); + Log.d(LOG_TAG, "Error: " + error); + + RILRequest rr; + + rr = findAndRemoveRequestFromList(serial); + + if (rr == null) { + Log.w(LOG_TAG, "Unexpected solicited response! sn: " + + serial + " error: " + error); + return; + } + + Object ret = null; + + if (error == 0 || p.dataAvail() > 0) { + // either command succeeds or command fails but with data payload + try {switch (rr.mRequest) { + /* + cat libs/telephony/ril_commands.h \ + | egrep "^ *{RIL_" \ + | sed -re 's/\{([^,]+),[^,]+,([^}]+).+/case \1: ret = \2(p); break;/' + */ + case RIL_REQUEST_GET_SIM_STATUS: ret = responseIccCardStatus(p); break; + case RIL_REQUEST_ENTER_SIM_PIN: ret = responseInts(p); break; + case RIL_REQUEST_ENTER_SIM_PUK: ret = responseInts(p); break; + case RIL_REQUEST_ENTER_SIM_PIN2: ret = responseInts(p); break; + case RIL_REQUEST_ENTER_SIM_PUK2: ret = responseInts(p); break; + case RIL_REQUEST_CHANGE_SIM_PIN: ret = responseInts(p); break; + case RIL_REQUEST_CHANGE_SIM_PIN2: ret = responseInts(p); break; + case RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION: ret = responseInts(p); break; + case RIL_REQUEST_GET_CURRENT_CALLS: ret = responseCallList(p); break; + case RIL_REQUEST_DIAL: ret = responseVoid(p); break; + case RIL_REQUEST_GET_IMSI: ret = responseString(p); break; + case RIL_REQUEST_HANGUP: ret = responseVoid(p); break; + case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND: ret = responseVoid(p); break; + case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND: ret = responseVoid(p); break; + case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE: ret = responseVoid(p); break; + case RIL_REQUEST_CONFERENCE: ret = responseVoid(p); break; + case RIL_REQUEST_UDUB: ret = responseVoid(p); break; + case RIL_REQUEST_LAST_CALL_FAIL_CAUSE: ret = responseLastCallFailCause(p); break; + case RIL_REQUEST_SIGNAL_STRENGTH: ret = responseSignalStrength(p); break; + case RIL_REQUEST_VOICE_REGISTRATION_STATE: ret = responseVoiceRegistrationState(p); break; + case RIL_REQUEST_DATA_REGISTRATION_STATE: ret = responseStrings(p); break; + case RIL_REQUEST_OPERATOR: ret = responseStrings(p); break; + case RIL_REQUEST_RADIO_POWER: ret = responseVoid(p); break; + case RIL_REQUEST_DTMF: ret = responseVoid(p); break; + case RIL_REQUEST_SEND_SMS: ret = responseSMS(p); break; + case RIL_REQUEST_SEND_SMS_EXPECT_MORE: ret = responseSMS(p); break; + case RIL_REQUEST_SETUP_DATA_CALL: ret = responseSetupDataCall(p); break; + case RIL_REQUEST_SIM_IO: ret = responseICC_IO(p); break; + case RIL_REQUEST_SEND_USSD: ret = responseVoid(p); break; + case RIL_REQUEST_CANCEL_USSD: ret = responseVoid(p); break; + case RIL_REQUEST_GET_CLIR: ret = responseInts(p); break; + case RIL_REQUEST_SET_CLIR: ret = responseVoid(p); break; + case RIL_REQUEST_QUERY_CALL_FORWARD_STATUS: ret = responseCallForward(p); break; + case RIL_REQUEST_SET_CALL_FORWARD: ret = responseVoid(p); break; + case RIL_REQUEST_QUERY_CALL_WAITING: ret = responseInts(p); break; + case RIL_REQUEST_SET_CALL_WAITING: ret = responseVoid(p); break; + case RIL_REQUEST_SMS_ACKNOWLEDGE: ret = responseVoid(p); break; + case RIL_REQUEST_GET_IMEI: ret = responseString(p); break; + case RIL_REQUEST_GET_IMEISV: ret = responseString(p); break; + case RIL_REQUEST_ANSWER: ret = responseVoid(p); break; + case RIL_REQUEST_DEACTIVATE_DATA_CALL: ret = responseVoid(p); break; + case RIL_REQUEST_QUERY_FACILITY_LOCK: ret = responseInts(p); break; + case RIL_REQUEST_SET_FACILITY_LOCK: ret = responseInts(p); break; + case RIL_REQUEST_CHANGE_BARRING_PASSWORD: ret = responseVoid(p); break; + case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE: ret = responseInts(p); break; + case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC: ret = responseVoid(p); break; + case RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL: ret = responseVoid(p); break; + case RIL_REQUEST_QUERY_AVAILABLE_NETWORKS : ret = responseOperatorInfos(p); break; + case RIL_REQUEST_DTMF_START: ret = responseVoid(p); break; + case RIL_REQUEST_DTMF_STOP: ret = responseVoid(p); break; + case RIL_REQUEST_BASEBAND_VERSION: ret = responseString(p); break; + case RIL_REQUEST_SEPARATE_CONNECTION: ret = responseVoid(p); break; + case RIL_REQUEST_SET_MUTE: ret = responseVoid(p); break; + case RIL_REQUEST_GET_MUTE: ret = responseInts(p); break; + case RIL_REQUEST_QUERY_CLIP: ret = responseInts(p); break; + case RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE: ret = responseInts(p); break; + case RIL_REQUEST_DATA_CALL_LIST: ret = responseDataCallList(p); break; + case RIL_REQUEST_RESET_RADIO: ret = responseVoid(p); break; + case RIL_REQUEST_OEM_HOOK_RAW: ret = responseRaw(p); break; + case RIL_REQUEST_OEM_HOOK_STRINGS: ret = responseStrings(p); break; + case RIL_REQUEST_SCREEN_STATE: ret = responseVoid(p); break; + case RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION: ret = responseVoid(p); break; + case RIL_REQUEST_WRITE_SMS_TO_SIM: ret = responseInts(p); break; + case RIL_REQUEST_DELETE_SMS_ON_SIM: ret = responseVoid(p); break; + case RIL_REQUEST_SET_BAND_MODE: ret = responseVoid(p); break; + case RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE: ret = responseInts(p); break; + case RIL_REQUEST_STK_GET_PROFILE: ret = responseString(p); break; + case RIL_REQUEST_STK_SET_PROFILE: ret = responseVoid(p); break; + case RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND: ret = responseString(p); break; + case RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE: ret = responseVoid(p); break; + case RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM: ret = responseInts(p); break; + case RIL_REQUEST_EXPLICIT_CALL_TRANSFER: ret = responseVoid(p); break; + case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE: ret = responseVoid(p); break; + case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE: ret = responseNetworkType(p); break; + case RIL_REQUEST_GET_NEIGHBORING_CELL_IDS: ret = responseCellList(p); break; + case RIL_REQUEST_SET_LOCATION_UPDATES: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE: ret = responseInts(p); break; + case RIL_REQUEST_SET_TTY_MODE: ret = responseVoid(p); break; + case RIL_REQUEST_QUERY_TTY_MODE: ret = responseInts(p); break; + case RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE: ret = responseInts(p); break; + case RIL_REQUEST_CDMA_FLASH: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_BURST_DTMF: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_SEND_SMS: ret = responseSMS(p); break; + case RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE: ret = responseVoid(p); break; + case RIL_REQUEST_GSM_GET_BROADCAST_CONFIG: ret = responseGmsBroadcastConfig(p); break; + case RIL_REQUEST_GSM_SET_BROADCAST_CONFIG: ret = responseVoid(p); break; + case RIL_REQUEST_GSM_BROADCAST_ACTIVATION: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_GET_BROADCAST_CONFIG: ret = responseCdmaBroadcastConfig(p); break; + case RIL_REQUEST_CDMA_SET_BROADCAST_CONFIG: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_BROADCAST_ACTIVATION: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_SUBSCRIPTION: ret = responseCdmaSubscription(p); break; + case RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM: ret = responseInts(p); break; + case RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM: ret = responseVoid(p); break; + case RIL_REQUEST_DEVICE_IDENTITY: ret = responseStrings(p); break; + case RIL_REQUEST_GET_SMSC_ADDRESS: ret = responseString(p); break; + case RIL_REQUEST_SET_SMSC_ADDRESS: ret = responseVoid(p); break; + case RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE: ret = responseVoid(p); break; + case RIL_REQUEST_REPORT_SMS_MEMORY_STATUS: ret = responseVoid(p); break; + case RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING: ret = responseVoid(p); break; + case RIL_REQUEST_DIAL_EMERGENCY: ret = responseVoid(p); break; + default: + throw new RuntimeException("Unrecognized solicited response: " + rr.mRequest); + //break; + }} catch (Throwable tr) { + // Exceptions here usually mean invalid RIL responses + + Log.w(LOG_TAG, rr.serialString() + "< " + + requestToString(rr.mRequest) + + " exception, possible invalid RIL response", tr); + + if (rr.mResult != null) { + AsyncResult.forMessage(rr.mResult, null, tr); + rr.mResult.sendToTarget(); + } + rr.release(); + return; + } + } + + if (error != 0) { + // Ugly fix for Samsung messing up SMS_SEND request fail in binary RIL + if (error == -1 && rr.mRequest == RIL_REQUEST_SEND_SMS) + { + try + { + ret = responseSMS(p); + } catch (Throwable tr) { + Log.w(LOG_TAG, rr.serialString() + "< " + + requestToString(rr.mRequest) + + " exception, Processing Samsung SMS fix ", tr); + rr.onError(error, ret); + rr.release(); + return; + } + } else { + rr.onError(error, ret); + rr.release(); + return; + } + } + + 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(); + } + + rr.release(); + } + + @Override + public void + dial(String address, int clirMode, UUSInfo uusInfo, Message result) { + RILRequest rr; + if (!mIsSamsungCdma && PhoneNumberUtils.isEmergencyNumber(address)) { + dialEmergencyCall(address, clirMode, result); + return; + } + + rr = RILRequest.obtain(RIL_REQUEST_DIAL, result); + rr.mp.writeString(address); + rr.mp.writeInt(clirMode); + rr.mp.writeInt(0); // UUS information is absent + + if (uusInfo == null) { + rr.mp.writeInt(0); // UUS information is absent + } else { + rr.mp.writeInt(1); // UUS information is present + rr.mp.writeInt(uusInfo.getType()); + rr.mp.writeInt(uusInfo.getDcs()); + rr.mp.writeByteArray(uusInfo.getUserData()); + } + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + + send(rr); + } + + public void + dialEmergencyCall(String address, int clirMode, Message result) { + RILRequest rr; + Log.v(LOG_TAG, "Emergency dial: " + address); + + rr = RILRequest.obtain(RIL_REQUEST_DIAL_EMERGENCY, result); + rr.mp.writeString(address + "/"); + rr.mp.writeInt(clirMode); + rr.mp.writeInt(0); + rr.mp.writeInt(0); + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + + send(rr); + } + + @Override + protected void + processUnsolicited (Parcel p) { + int response; + Object ret; + int dataPosition = p.dataPosition(); + + response = p.readInt(); + + switch(response) { + /* + cat libs/telephony/ril_unsol_commands.h \ + | egrep "^ *{RIL_" \ + | sed -re 's/\{([^,]+),[^,]+,([^}]+).+/case \1: \2(rr, p); break;/' + */ + + case RIL_UNSOL_NITZ_TIME_RECEIVED: ret = responseString(p); break; + case RIL_UNSOL_SIGNAL_STRENGTH: ret = responseSignalStrength(p); break; + case RIL_UNSOL_CDMA_INFO_REC: ret = responseCdmaInformationRecord(p); break; + case RIL_UNSOL_HSDPA_STATE_CHANGED: ret = responseInts(p); break; + + //fixing anoying Exceptions caused by the new Samsung states + //FIXME figure out what the states mean an what data is in the parcel + + case RIL_UNSOL_O2_HOME_ZONE_INFO: ret = responseVoid(p); break; + case RIL_UNSOL_DEVICE_READY_NOTI: ret = responseVoid(p); break; + case RIL_UNSOL_GPS_NOTI: ret = responseVoid(p); break; // Ignored in TW RIL. + case RIL_UNSOL_SAMSUNG_UNKNOWN_MAGIC_REQUEST: ret = responseVoid(p); break; + case RIL_UNSOL_SAMSUNG_UNKNOWN_MAGIC_REQUEST_2: ret = responseVoid(p); break; + case RIL_UNSOL_AM: ret = responseString(p); break; + + default: + // Rewind the Parcel + p.setDataPosition(dataPosition); + + // Forward responses that we are not overriding to the super class + super.processUnsolicited(p); + return; + } + + switch(response) { + case RIL_UNSOL_HSDPA_STATE_CHANGED: + if (RILJ_LOGD) unsljLog(response); + + boolean newHsdpa = ((int[])ret)[0] == 1; + String curState = SystemProperties.get(TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE); + boolean curHsdpa = false; + + if (curState.startsWith("HSDPA")) { + curHsdpa = true; + } else if (!curState.startsWith("UMTS")) { + // Don't send poll request if not on 3g + break; + } + + if (curHsdpa != newHsdpa) { + mVoiceNetworkStateRegistrants + .notifyRegistrants(new AsyncResult(null, null, null)); + } + break; + + case RIL_UNSOL_NITZ_TIME_RECEIVED: + if (RILJ_LOGD) unsljLogRet(response, ret); + + // has bonus long containing milliseconds since boot that the NITZ + // time was received + long nitzReceiveTime = p.readLong(); + + Object[] result = new Object[2]; + + String nitz = (String)ret; + if (RILJ_LOGD) riljLog(" RIL_UNSOL_NITZ_TIME_RECEIVED length = " + + nitz.split("[/:,+-]").length); + + // remove the tailing information that samsung added to the string + if(nitz.split("[/:,+-]").length >= 9) + nitz = nitz.substring(0,(nitz.lastIndexOf(","))); + + if (RILJ_LOGD) riljLog(" RIL_UNSOL_NITZ_TIME_RECEIVED striped nitz = " + + nitz); + + result[0] = nitz; + result[1] = Long.valueOf(nitzReceiveTime); + + if (mNITZTimeRegistrant != null) { + + mNITZTimeRegistrant + .notifyRegistrant(new AsyncResult (null, result, null)); + } else { + // in case NITZ time registrant isnt registered yet + mLastNITZTimeInfo = nitz; + } + break; + + case RIL_UNSOL_SIGNAL_STRENGTH: + // Note this is set to "verbose" because it happens + // frequently + if (RILJ_LOGV) unsljLogvRet(response, ret); + + if (mSignalStrengthRegistrant != null) { + mSignalStrengthRegistrant.notifyRegistrant( + new AsyncResult (null, ret, null)); + } + break; + + case RIL_UNSOL_CDMA_INFO_REC: + ArrayList listInfoRecs; + + try { + listInfoRecs = (ArrayList)ret; + } catch (ClassCastException e) { + Log.e(LOG_TAG, "Unexpected exception casting to listInfoRecs", e); + break; + } + + for (CdmaInformationRecords rec : listInfoRecs) { + if (RILJ_LOGD) unsljLogRet(response, rec); + notifyRegistrantsCdmaInfoRec(rec); + } + break; + + case RIL_UNSOL_AM: + String amString = (String) ret; + Log.d(LOG_TAG, "Executing AM: " + amString); + + try { + Runtime.getRuntime().exec("am " + amString); + } catch (IOException e) { + e.printStackTrace(); + Log.e(LOG_TAG, "am " + amString + " could not be executed."); + } + break; + } + } + + @Override + protected Object + responseCallList(Parcel p) { + int num; + boolean isVideo; + ArrayList response; + DriverCall dc; + int dataAvail = p.dataAvail(); + int pos = p.dataPosition(); + int size = p.dataSize(); + + Log.d(LOG_TAG, "Parcel size = " + size); + Log.d(LOG_TAG, "Parcel pos = " + pos); + Log.d(LOG_TAG, "Parcel dataAvail = " + dataAvail); + + num = p.readInt(); + response = new ArrayList(num); + + for (int i = 0 ; i < num ; i++) { + if (mIsSamsungCdma) + dc = new SamsungDriverCall(); + else + dc = new DriverCall(); + + dc.state = DriverCall.stateFromCLCC(p.readInt()); + dc.index = p.readInt(); + dc.TOA = p.readInt(); + dc.isMpty = (0 != p.readInt()); + dc.isMT = (0 != p.readInt()); + dc.als = p.readInt(); + dc.isVoice = (0 != p.readInt()); + isVideo = (0 != p.readInt()); + dc.isVoicePrivacy = (0 != p.readInt()); + 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(); + + Log.d(LOG_TAG, "state = " + dc.state); + Log.d(LOG_TAG, "index = " + dc.index); + Log.d(LOG_TAG, "state = " + dc.TOA); + Log.d(LOG_TAG, "isMpty = " + dc.isMpty); + Log.d(LOG_TAG, "isMT = " + dc.isMT); + Log.d(LOG_TAG, "als = " + dc.als); + Log.d(LOG_TAG, "isVoice = " + dc.isVoice); + Log.d(LOG_TAG, "isVideo = " + isVideo); + Log.d(LOG_TAG, "number = " + dc.number); + Log.d(LOG_TAG, "numberPresentation = " + np); + Log.d(LOG_TAG, "name = " + dc.name); + Log.d(LOG_TAG, "namePresentation = " + dc.namePresentation); + Log.d(LOG_TAG, "uusInfoPresent = " + uusInfoPresent); + + 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); + Log + .v(LOG_TAG, String.format("Incoming UUS : type=%d, dcs=%d, length=%d", + dc.uusInfo.getType(), dc.uusInfo.getDcs(), + dc.uusInfo.getUserData().length)); + Log.v(LOG_TAG, "Incoming UUS : data (string)=" + + new String(dc.uusInfo.getUserData())); + Log.v(LOG_TAG, "Incoming UUS : data (hex): " + + IccUtils.bytesToHexString(dc.uusInfo.getUserData())); + } else { + Log.v(LOG_TAG, "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(); + Log.d(LOG_TAG, "InCall VoicePrivacy is enabled"); + } else { + mVoicePrivacyOffRegistrants.notifyRegistrants(); + Log.d(LOG_TAG, "InCall VoicePrivacy is disabled"); + } + } + + Collections.sort(response); + + return response; + } + + protected Object + responseLastCallFailCause(Parcel p) { + int response[] = (int[])responseInts(p); + + if (mIsSamsungCdma && response.length > 0 && + response[0] == com.android.internal.telephony.cdma.CallFailCause.ERROR_UNSPECIFIED) { + + // Far-end hangup returns ERROR_UNSPECIFIED, which shows "Call Lost" dialog. + Log.d(LOG_TAG, "Overriding ERROR_UNSPECIFIED fail cause with NORMAL_CLEARING."); + response[0] = com.android.internal.telephony.cdma.CallFailCause.NORMAL_CLEARING; + } + + return response; + } + + @Override + protected Object + responseSignalStrength(Parcel p) { + // When SIM is PIN-unlocked, the RIL responds with APPSTATE_UNKNOWN and + // does not follow up with RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED. We + // notify the system here. + String state = SystemProperties.get(TelephonyProperties.PROPERTY_SIM_STATE); + if ("NOT_READY".equals(state) && mIccStatusChangedRegistrants != null) { + mIccStatusChangedRegistrants.notifyRegistrants(); + } + + int numInts = 12; + int response[]; + + /* TODO: Add SignalStrength class to match RIL_SignalStrength */ + response = new int[numInts]; + for (int i = 0 ; i < 7 ; i++) { + response[i] = p.readInt(); + } + // SamsungRIL is a v3 RIL, fill the rest with -1 + for (int i = 7; i < numInts; i++) { + response[i] = -1; + } + + if (mIsSamsungCdma){ + if(response[3] < 0){ + response[3] = -response[3]; + } + // Framework takes care of the rest for us. + return response; + } + /* Matching Samsung signal strength to asu. + Method taken from Samsungs cdma/gsmSignalStateTracker */ + if(mSignalbarCount) + { + // Samsung sends the count of bars that should be displayed instead of + // a real signal strength + response[0] = ((response[0] & 0xFF00) >> 8) * 3; // gsmDbm + } else { + response[0] = response[0] & 0xFF; // gsmDbm + } + response[1] = -1; // gsmEcio + response[2] = (response[2] < 0)?-120:-response[2]; // cdmaDbm + response[3] = (response[3] < 0)?-160:-response[3]; // cdmaEcio + response[4] = (response[4] < 0)?-120:-response[4]; // evdoRssi + response[5] = (response[5] < 0)?-1:-response[5]; // evdoEcio + if(response[6] < 0 || response[6] > 8) + response[6] = -1; + + return response; + } + + protected Object + responseVoiceRegistrationState(Parcel p) { + String response[] = (String[])responseStrings(p); + + if (mIsSamsungCdma && response.length > 6) { + // These values are provided in hex, convert to dec. + response[4] = Integer.toString(Integer.parseInt(response[4], 16)); // baseStationId + response[5] = Integer.toString(Integer.parseInt(response[5], 16)); // baseStationLatitude + response[6] = Integer.toString(Integer.parseInt(response[6], 16)); // baseStationLongitude + } + + return response; + } + + protected Object + responseNetworkType(Parcel p) { + int response[] = (int[]) responseInts(p); + + // When the modem responds Phone.NT_MODE_GLOBAL, it means Phone.NT_MODE_WCDMA_PREF + if (!mIsSamsungCdma && response[0] == Phone.NT_MODE_GLOBAL) { + Log.d(LOG_TAG, "Overriding network type response from global to WCDMA preferred"); + response[0] = Phone.NT_MODE_WCDMA_PREF; + } + + return response; + } + + @Override + protected Object + responseSetupDataCall(Parcel p) { + DataCallState dataCall = new DataCallState(); + String strings[] = (String []) responseStrings(p); + + if (strings.length >= 2) { + dataCall.cid = Integer.parseInt(strings[0]); + + if (mIsSamsungCdma) { + // We're responsible for starting/stopping the pppd_cdma service. + if (!startPppdCdmaService(strings[1])) { + // pppd_cdma service didn't respond timely. + dataCall.status = FailCause.ERROR_UNSPECIFIED.getErrorCode(); + return dataCall; + } + + // pppd_cdma service responded, pull network parameters set by ip-up script. + dataCall.ifname = SystemProperties.get("net.cdma.ppp.interface"); + String ifprop = "net." + dataCall.ifname; + + dataCall.addresses = new String[] {SystemProperties.get(ifprop + ".local-ip")}; + dataCall.gateways = new String[] {SystemProperties.get(ifprop + ".remote-ip")}; + dataCall.dnses = new String[] {SystemProperties.get(ifprop + ".dns1"), + SystemProperties.get(ifprop + ".dns2")}; + } else { + dataCall.ifname = strings[1]; + + if (strings.length >= 3) { + dataCall.addresses = strings[2].split(" "); + } + } + } else { + if (mIsSamsungCdma) { + // On rare occasion the pppd_cdma service is left active from a stale + // session, causing the data call setup to fail. Make sure that pppd_cdma + // is stopped now, so that the next setup attempt may succeed. + Log.d(LOG_TAG, "Set ril.cdma.data_state=0 to make sure pppd_cdma is stopped."); + SystemProperties.set("ril.cdma.data_state", "0"); + } + + dataCall.status = FailCause.ERROR_UNSPECIFIED.getErrorCode(); // Who knows? + } + + return dataCall; + } + + private boolean startPppdCdmaService(String ttyname) { + SystemProperties.set("net.cdma.datalinkinterface", ttyname); + + // Connecting: Set ril.cdma.data_state=1 to (re)start pppd_cdma service, + // which responds by setting ril.cdma.data_state=2 once connection is up. + SystemProperties.set("ril.cdma.data_state", "1"); + Log.d(LOG_TAG, "Set ril.cdma.data_state=1, waiting for ril.cdma.data_state=2."); + + // Typically takes < 200 ms on my Epic, so sleep in 100 ms intervals. + for (int i = 0; i < 10; i++) { + try {Thread.sleep(100);} catch (InterruptedException e) {} + + if (SystemProperties.getInt("ril.cdma.data_state", 1) == 2) { + Log.d(LOG_TAG, "Got ril.cdma.data_state=2, connected."); + return true; + } + } + + // Taking > 1 s here, try up to 10 s, which is hopefully long enough. + for (int i = 1; i < 10; i++) { + try {Thread.sleep(1000);} catch (InterruptedException e) {} + + if (SystemProperties.getInt("ril.cdma.data_state", 1) == 2) { + Log.d(LOG_TAG, "Got ril.cdma.data_state=2, connected."); + return true; + } + } + + // Disconnect: Set ril.cdma.data_state=0 to stop pppd_cdma service. + Log.d(LOG_TAG, "Didn't get ril.cdma.data_state=2 timely, aborting."); + SystemProperties.set("ril.cdma.data_state", "0"); + + return false; + } + + @Override + public void + deactivateDataCall(int cid, int reason, Message result) { + if (mIsSamsungCdma) { + // Disconnect: Set ril.cdma.data_state=0 to stop pppd_cdma service. + Log.d(LOG_TAG, "Set ril.cdma.data_state=0."); + SystemProperties.set("ril.cdma.data_state", "0"); + } + + super.deactivateDataCall(cid, reason, result); + } + + protected Object + responseCdmaSubscription(Parcel p) { + String response[] = (String[])responseStrings(p); + + if (/* mIsSamsungCdma && */ response.length == 4) { + // PRL version is missing in subscription parcel, add it from properties. + String prlVersion = SystemProperties.get("ril.prl_ver_1").split(":")[1]; + response = new String[] {response[0], response[1], response[2], + response[3], prlVersion}; + } + + return response; + } + + // 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 (/* mIsSamsungCdma && */ 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); + } + + protected class SamsungDriverCall extends DriverCall { + @Override + public String + toString() { + // Samsung CDMA devices' call parcel is formatted differently + // fake unused data for video calls, and fix formatting + // so that voice calls' information can be correctly parsed + return "id=" + index + "," + + state + "," + + "toa=" + TOA + "," + + (isMpty ? "conf" : "norm") + "," + + (isMT ? "mt" : "mo") + "," + + "als=" + als + "," + + (isVoice ? "voc" : "nonvoc") + "," + + "nonvid" + "," + + number + "," + + "cli=" + numberPresentation + "," + + "name=" + name + "," + + namePresentation; + } + } + + /** + * {@inheritDoc} + */ + @Override + public void setCurrentPreferredNetworkType() { + if (RILJ_LOGD) riljLog("setCurrentPreferredNetworkType IGNORED"); + /* Google added this as a fix for crespo loosing network type after + * taking an OTA. This messes up the data connection state for us + * due to the way we handle network type change (disable data + * then change then re-enable). + */ + } + + @Override + public void setPreferredNetworkType(int networkType , Message response) { + /* Samsung modem implementation does bad things when a datacall is running + * while switching the preferred networktype. + */ + ConnectivityManager cm = + (ConnectivityManager)mContext.getSystemService(Context.CONNECTIVITY_SERVICE); + + if(cm.getMobileDataEnabled()) + { + ConnectivityHandler handler = new ConnectivityHandler(mContext); + handler.setPreferedNetworkType(networkType, response); + } else { + sendPreferedNetworktype(networkType, response); + } + } + + + //Sends the real RIL request to the modem. + private void sendPreferedNetworktype(int networkType, Message response) { + RILRequest rr = RILRequest.obtain( + RILConstants.RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, response); + + rr.mp.writeInt(1); + rr.mp.writeInt(networkType); + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + + " : " + networkType); + + send(rr); + } + /* private class that does the handling for the dataconnection + * dataconnection is done async, so we send the request for disabling it, + * wait for the response, set the prefered networktype and notify the + * real sender with its result. + */ + private class ConnectivityHandler extends Handler{ + + private static final int MESSAGE_SET_PREFERRED_NETWORK_TYPE = 30; + private Context mContext; + private int mDesiredNetworkType; + //the original message, we need it for calling back the original caller when done + private Message mNetworktypeResponse; + private ConnectivityBroadcastReceiver mConnectivityReceiver = new ConnectivityBroadcastReceiver(); + + public ConnectivityHandler(Context context) + { + mContext = context; + } + + private void startListening() { + IntentFilter filter = new IntentFilter(); + filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); + mContext.registerReceiver(mConnectivityReceiver, filter); + } + + private synchronized void stopListening() { + mContext.unregisterReceiver(mConnectivityReceiver); + } + + public void setPreferedNetworkType(int networkType, Message response) + { + Log.d(LOG_TAG, "Mobile Dataconnection is online setting it down"); + mDesiredNetworkType = networkType; + mNetworktypeResponse = response; + ConnectivityManager cm = + (ConnectivityManager)mContext.getSystemService(Context.CONNECTIVITY_SERVICE); + //start listening for the connectivity change broadcast + startListening(); + cm.setMobileDataEnabled(false); + } + + @Override + public void handleMessage(Message msg) { + switch(msg.what) { + //networktype was set, now we can enable the dataconnection again + case MESSAGE_SET_PREFERRED_NETWORK_TYPE: + ConnectivityManager cm = + (ConnectivityManager)mContext.getSystemService(Context.CONNECTIVITY_SERVICE); + + Log.d(LOG_TAG, "preferred NetworkType set upping Mobile Dataconnection"); + + cm.setMobileDataEnabled(true); + //everything done now call back that we have set the networktype + AsyncResult.forMessage(mNetworktypeResponse, null, null); + mNetworktypeResponse.sendToTarget(); + mNetworktypeResponse = null; + break; + default: + throw new RuntimeException("unexpected event not handled"); + } + } + + private class ConnectivityBroadcastReceiver extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (!action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { + Log.w(LOG_TAG, "onReceived() called with " + intent); + return; + } + boolean noConnectivity = + intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false); + + if (noConnectivity) { + //Ok dataconnection is down, now set the networktype + Log.w(LOG_TAG, "Mobile Dataconnection is now down setting preferred NetworkType"); + stopListening(); + sendPreferedNetworktype(mDesiredNetworkType, obtainMessage(MESSAGE_SET_PREFERRED_NETWORK_TYPE)); + mDesiredNetworkType = -1; + } + } + } + } +} diff --git a/telephony/java/com/android/internal/telephony/SemcRIL.java b/telephony/java/com/android/internal/telephony/SemcRIL.java new file mode 100644 index 0000000000000..051a590a5fae4 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/SemcRIL.java @@ -0,0 +1,463 @@ +/* + * Copyright (C) 2011-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.text.TextUtils; +import android.util.Log; + +import java.util.ArrayList; + +/** + * Custom Qualcomm No SimReady RIL for SEMC + * + * {@hide} + */ + +public class SemcRIL extends RIL implements CommandsInterface { + protected String mAid = ""; + protected HandlerThread mIccThread; + protected IccHandler mIccHandler; + boolean RILJ_LOGV = true; + boolean RILJ_LOGD = true; + + private final int RIL_INT_RADIO_OFF = 0; + private final int RIL_INT_RADIO_UNAVALIABLE = 1; + private final int RIL_INT_RADIO_ON = 2; + + public SemcRIL(Context context, int networkMode, int cdmaSubscription) { + super(context, networkMode, cdmaSubscription); + } + + @Override + protected Object + responseIccCardStatus(Parcel p) { + IccCardApplication ca; + + IccCardStatus status = new IccCardStatus(); + status.setCardState(p.readInt()); + status.setUniversalPinState(p.readInt()); + status.setGsmUmtsSubscriptionAppIndex(p.readInt()); + status.setCdmaSubscriptionAppIndex(p.readInt()); + status.setImsSubscriptionAppIndex(p.readInt()); + + int numApplications = p.readInt(); + // limit to maximum allowed applications + if (numApplications > IccCardStatus.CARD_MAX_APPS) { + numApplications = IccCardStatus.CARD_MAX_APPS; + } + status.setNumApplications(numApplications); + + for (int i = 0 ; i < numApplications ; i++) { + ca = new IccCardApplication(); + ca.app_type = ca.AppTypeFromRILInt(p.readInt()); + ca.app_state = ca.AppStateFromRILInt(p.readInt()); + ca.perso_substate = ca.PersoSubstateFromRILInt(p.readInt()); + ca.aid = p.readString(); + ca.app_label = p.readString(); + ca.pin1_replaced = p.readInt(); + ca.pin1 = ca.PinStateFromRILInt(p.readInt()); + ca.pin2 = ca.PinStateFromRILInt(p.readInt()); + status.addApplication(ca); + } + + updateIccType(status); + return status; + } + + private void updateIccType (IccCardStatus status) { + int appType; + if (status.getNumApplications() > 0) { + if (mPhoneType == RILConstants.CDMA_PHONE) + appType = status.getCdmaSubscriptionAppIndex(); + else + appType = status.getGsmUmtsSubscriptionAppIndex(); + + IccCardApplication application = status.getApplication(appType); + mAid = application.aid; + Log.d(LOG_TAG, "Picked default AID: " + mAid); + } + } + + @Override + protected DataCallState getDataCallState(Parcel p, int version) { + DataCallState dataCall = new DataCallState(); + + dataCall.version = version; + if (version < 5) { + dataCall.cid = p.readInt(); + dataCall.active = p.readInt(); + dataCall.type = p.readString(); + String addresses = p.readString(); + if (!TextUtils.isEmpty(addresses)) { + dataCall.addresses = addresses.split(" "); + } + // DataCallState needs an ifname. Since we don't have one use the name from the ThrottleService resource (default=rmnet0). + dataCall.ifname = "rmnet0"; + } else { + dataCall.status = p.readInt(); + dataCall.suggestedRetryTime = p.readInt(); + dataCall.cid = p.readInt(); + dataCall.active = p.readInt(); + dataCall.type = p.readString(); + dataCall.ifname = p.readString(); + if ((dataCall.status == DataConnection.FailCause.NONE.getErrorCode()) && + TextUtils.isEmpty(dataCall.ifname)) { + throw new RuntimeException("getDataCallState, no ifname"); + } + String addresses = p.readString(); + if (!TextUtils.isEmpty(addresses)) { + dataCall.addresses = addresses.split(" "); + } + String dnses = p.readString(); + if (!TextUtils.isEmpty(dnses)) { + dataCall.dnses = dnses.split(" "); + } + String gateways = p.readString(); + if (!TextUtils.isEmpty(gateways)) { + dataCall.gateways = gateways.split(" "); + } + } + return dataCall; + } + + @Override public void + supplyIccPin(String pin, Message result) { + supplyIccPinForApp(pin, mAid, result); + } + + @Override public void + changeIccPin(String oldPin, String newPin, Message result) { + changeIccPinForApp(oldPin, newPin, mAid, result); + } + + @Override public void + supplyIccPin2(String pin, Message result) { + supplyIccPin2ForApp(pin, mAid, result); + } + + @Override public void + changeIccPin2(String oldPin2, String newPin2, Message result) { + changeIccPin2ForApp(oldPin2, newPin2, mAid, result); + } + + @Override public void + supplyIccPuk(String puk, String newPin, Message result) { + supplyIccPukForApp(puk, newPin, mAid, result); + } + + @Override public void + supplyIccPuk2(String puk2, String newPin2, Message result) { + supplyIccPuk2ForApp(puk2, newPin2, mAid, result); + } + + @Override + public void + queryFacilityLock(String facility, String password, int serviceClass, + Message response) { + queryFacilityLockForApp(facility, password, serviceClass, mAid, response); + } + + @Override + public void + setFacilityLock(String facility, boolean lockState, String password, + int serviceClass, Message response) { + setFacilityLockForApp(facility, lockState, password, serviceClass, mAid, response); + } + + @Override + public void + iccIO (int command, int fileid, String path, int p1, int p2, int p3, + String data, String pin2, Message result) { + iccIOForApp(command, fileid, path, p1, p2, p3, data, pin2, mAid, result); + } + + @Override + public void + getIMSI(Message result) { + getIMSIForApp(mAid, result); + } + + @Override + public void + getIMSIForApp(String aid, Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_IMSI, result); + + rr.mp.writeString(aid); + + if (RILJ_LOGD) riljLog(rr.serialString() + + "> getIMSI: " + requestToString(rr.mRequest) + + " aid: " + aid); + + send(rr); + } + + @Override + protected Object + responseOperatorInfos(Parcel p) { + String strings[] = (String [])responseStrings(p); + ArrayList ret; + + if (strings.length % 5 != 0) { + throw new RuntimeException( + "RIL_REQUEST_QUERY_AVAILABLE_NETWORKS: invalid response. Got " + + strings.length + " strings, expected multible of 5"); + } + + ret = new ArrayList(strings.length / 4); + + for (int i = 0 ; i < strings.length ; i += 5) { + ret.add ( + new OperatorInfo( + strings[i+0], + strings[i+1], + strings[i+2], + strings[i+3])); + } + return ret; + } + + @Override + public void + dial(String address, int clirMode, UUSInfo uusInfo, Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_DIAL, result); + + rr.mp.writeString(address); + rr.mp.writeInt(clirMode); + rr.mp.writeInt(0); + + if (uusInfo == null) { + rr.mp.writeInt(0); // UUS information is absent + } else { + rr.mp.writeInt(1); // UUS information is present + rr.mp.writeInt(uusInfo.getType()); + rr.mp.writeInt(uusInfo.getDcs()); + rr.mp.writeByteArray(uusInfo.getUserData()); + } + rr.mp.writeInt(255); + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + + send(rr); + } + + public void + setNetworkSelectionMode(String operatorNumeric, Message response) { + RILRequest rr; + + if (operatorNumeric == null) + rr = RILRequest.obtain(RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC, response); + else + rr = RILRequest.obtain(RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL, response); + + rr.mp.writeString(operatorNumeric); + rr.mp.writeInt(-1); + + send(rr); + } + + @Override + public void + setNetworkSelectionModeAutomatic(Message response) { + setNetworkSelectionMode(null, response); + } + + @Override + public void + setNetworkSelectionModeManual(String operatorNumeric, Message response) { + setNetworkSelectionMode(operatorNumeric, 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_RESPONSE_RADIO_STATE_CHANGED: ret = responseVoid(p); break; + case 1036: ret = responseVoid(p); break; // RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED + + default: + // Rewind the Parcel + p.setDataPosition(dataPosition); + + // Forward responses that we are not overriding to the super class + super.processUnsolicited(p); + return; + } + + switch(response) { + case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED: + int state = p.readInt(); + setRadioStateFromRILInt(state); + break; + case 1036: + break; + } + } + + private void setRadioStateFromRILInt (int stateCode) { + CommandsInterface.RadioState radioState; + HandlerThread handlerThread; + Looper looper; + IccHandler iccHandler; + + switch (stateCode) { + case RIL_INT_RADIO_OFF: + radioState = CommandsInterface.RadioState.RADIO_OFF; + if (mIccHandler != null) { + mIccThread = null; + mIccHandler = null; + } + break; + case RIL_INT_RADIO_UNAVALIABLE: + radioState = CommandsInterface.RadioState.RADIO_UNAVAILABLE; + break; + case RIL_INT_RADIO_ON: + if (mIccHandler == null) { + handlerThread = new HandlerThread("IccHandler"); + mIccThread = handlerThread; + + mIccThread.start(); + + looper = mIccThread.getLooper(); + mIccHandler = new IccHandler(this,looper); + mIccHandler.run(); + } + radioState = CommandsInterface.RadioState.RADIO_ON; + break; + default: + throw new RuntimeException("Unrecognized RIL_RadioState: " + stateCode); + } + + setRadioState (radioState); + } + + class IccHandler extends Handler implements Runnable { + private static final int EVENT_RADIO_ON = 1; + private static final int EVENT_ICC_STATUS_CHANGED = 2; + private static final int EVENT_GET_ICC_STATUS_DONE = 3; + private static final int EVENT_RADIO_OFF_OR_UNAVAILABLE = 4; + + private RIL mRil; + private boolean mRadioOn = false; + + public IccHandler (RIL ril, Looper looper) { + super (looper); + mRil = ril; + } + + public void handleMessage (Message paramMessage) { + switch (paramMessage.what) { + case EVENT_RADIO_ON: + mRadioOn = true; + Log.d(LOG_TAG, "Radio on -> Forcing sim status update"); + sendMessage(obtainMessage(EVENT_ICC_STATUS_CHANGED)); + break; + case EVENT_GET_ICC_STATUS_DONE: + AsyncResult asyncResult = (AsyncResult) paramMessage.obj; + if (asyncResult.exception != null) { + Log.e (LOG_TAG, "IccCardStatusDone shouldn't return exceptions!", asyncResult.exception); + break; + } + IccCardStatus status = (IccCardStatus) asyncResult.result; + if (status.getNumApplications() == 0) { + if (!mRil.getRadioState().isOn()) { + break; + } + + mRil.setRadioState(CommandsInterface.RadioState.RADIO_ON); + } else { + int appIndex = -1; + if (mPhoneType == RILConstants.CDMA_PHONE) { + appIndex = status.getCdmaSubscriptionAppIndex(); + Log.d(LOG_TAG, "This is a CDMA PHONE " + appIndex); + } else { + appIndex = status.getGsmUmtsSubscriptionAppIndex(); + Log.d(LOG_TAG, "This is a GSM PHONE " + appIndex); + } + + IccCardApplication application = status.getApplication(appIndex); + IccCardApplication.AppState app_state = application.app_state; + IccCardApplication.AppType app_type = application.app_type; + switch (app_state) { + case APPSTATE_PIN: + case APPSTATE_PUK: + switch (app_type) { + case APPTYPE_SIM: + case APPTYPE_USIM: + case APPTYPE_RUIM: + mRil.setRadioState(CommandsInterface.RadioState.RADIO_ON); + break; + default: + Log.e(LOG_TAG, "Currently we don't handle SIMs of type: " + app_type); + return; + } + break; + case APPSTATE_READY: + switch (app_type) { + case APPTYPE_SIM: + case APPTYPE_USIM: + case APPTYPE_RUIM: + mRil.setRadioState(CommandsInterface.RadioState.RADIO_ON); + break; + default: + Log.e(LOG_TAG, "Currently we don't handle SIMs of type: " + app_type); + return; + } + break; + default: + return; + } + } + break; + case EVENT_ICC_STATUS_CHANGED: + if (mRadioOn) { + Log.d(LOG_TAG, "Received EVENT_ICC_STATUS_CHANGED, calling getIccCardStatus"); + mRil.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE, paramMessage.obj)); + } else { + Log.d(LOG_TAG, "Received EVENT_ICC_STATUS_CHANGED while radio is not ON. Ignoring"); + } + break; + case EVENT_RADIO_OFF_OR_UNAVAILABLE: + mRadioOn = false; + // disposeCards(); // to be verified; + default: + Log.e(LOG_TAG, " Unknown Event " + paramMessage.what); + break; + } + } + + public void run () { + mRil.registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, null); + Message msg = obtainMessage(EVENT_RADIO_ON); + mRil.getIccCardStatus(msg); + } + } +} diff --git a/telephony/java/com/android/internal/telephony/SimRegionCache.java b/telephony/java/com/android/internal/telephony/SimRegionCache.java new file mode 100644 index 0000000000000..2cf6d25fb0d79 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/SimRegionCache.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2010 The Android Open Source 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; + +public class SimRegionCache { + public static final int MCC_UNSET = Integer.MIN_VALUE; + public static final int MCC_KOREAN = 450; + + private static int regionFromMcc = MCC_UNSET; + + /** + * Returns the region as read from the MCC of the SIM card. + * If the property {@link TelephonyProperties# + * PROPERTY_ICC_OPERATOR_NUMERIC} + * returns null or an empty String, the value is {@link #MCC_UNSET} + * + * @return the cached region, if set. + */ + public static int getRegion() { + if (regionFromMcc == MCC_UNSET) { + String plmn = SystemProperties.get( + TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC, + null); + + if (plmn != null && plmn.length() >= 3) { + try { + regionFromMcc = Integer.parseInt(plmn.substring(0, 3)); + } catch(Exception e) { + // Nothing that can be done here. + } + } + } + return regionFromMcc; + } +} diff --git a/telephony/java/com/android/internal/telephony/Smdk4210RIL.java b/telephony/java/com/android/internal/telephony/Smdk4210RIL.java new file mode 100644 index 0000000000000..3d77349aaa4c8 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/Smdk4210RIL.java @@ -0,0 +1,808 @@ +/* + * Copyright (C) 2011 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 static android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN; +import static android.telephony.TelephonyManager.NETWORK_TYPE_EDGE; +import static android.telephony.TelephonyManager.NETWORK_TYPE_GPRS; +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 android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.res.Resources; +import android.media.AudioManager; +import android.net.ConnectivityManager; +import android.net.LocalSocket; +import android.net.LocalSocketAddress; +import android.net.NetworkInfo; +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.os.PowerManager; +import android.os.SystemProperties; +import android.os.PowerManager.WakeLock; +import android.telephony.NeighboringCellInfo; +import android.telephony.PhoneNumberUtils; +import android.telephony.SmsManager; +import android.telephony.SmsMessage; +import android.text.TextUtils; +import android.util.Log; + +import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo; +import com.android.internal.telephony.gsm.SuppServiceNotification; +import com.android.internal.telephony.cdma.CdmaCallWaitingNotification; +import com.android.internal.telephony.cdma.CdmaInformationRecords; + +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.lang.Runtime; +import java.util.ArrayList; +import java.util.Collections; + +public class Smdk4210RIL extends RIL implements CommandsInterface { + + //SAMSUNG STATES + static final int RIL_REQUEST_GET_CELL_BROADCAST_CONFIG = 10002; + + static final int RIL_REQUEST_SEND_ENCODED_USSD = 10005; + static final int RIL_REQUEST_SET_PDA_MEMORY_STATUS = 10006; + static final int RIL_REQUEST_GET_PHONEBOOK_STORAGE_INFO = 10007; + static final int RIL_REQUEST_GET_PHONEBOOK_ENTRY = 10008; + static final int RIL_REQUEST_ACCESS_PHONEBOOK_ENTRY = 10009; + static final int RIL_REQUEST_DIAL_VIDEO_CALL = 10010; + static final int RIL_REQUEST_CALL_DEFLECTION = 10011; + static final int RIL_REQUEST_READ_SMS_FROM_SIM = 10012; + static final int RIL_REQUEST_USIM_PB_CAPA = 10013; + static final int RIL_REQUEST_LOCK_INFO = 10014; + + static final int RIL_REQUEST_DIAL_EMERGENCY = 10016; + static final int RIL_REQUEST_GET_STOREAD_MSG_COUNT = 10017; + static final int RIL_REQUEST_STK_SIM_INIT_EVENT = 10018; + static final int RIL_REQUEST_GET_LINE_ID = 10019; + static final int RIL_REQUEST_SET_LINE_ID = 10020; + static final int RIL_REQUEST_GET_SERIAL_NUMBER = 10021; + static final int RIL_REQUEST_GET_MANUFACTURE_DATE_NUMBER = 10022; + static final int RIL_REQUEST_GET_BARCODE_NUMBER = 10023; + static final int RIL_REQUEST_UICC_GBA_AUTHENTICATE_BOOTSTRAP = 10024; + static final int RIL_REQUEST_UICC_GBA_AUTHENTICATE_NAF = 10025; + static final int RIL_REQUEST_SIM_TRANSMIT_BASIC = 10026; + static final int RIL_REQUEST_SIM_OPEN_CHANNEL = 10027; + static final int RIL_REQUEST_SIM_CLOSE_CHANNEL = 10028; + static final int RIL_REQUEST_SIM_TRANSMIT_CHANNEL = 10029; + static final int RIL_REQUEST_SIM_AUTH = 10030; + static final int RIL_REQUEST_PS_ATTACH = 10031; + static final int RIL_REQUEST_PS_DETACH = 10032; + static final int RIL_REQUEST_ACTIVATE_DATA_CALL = 10033; + static final int RIL_REQUEST_CHANGE_SIM_PERSO = 10034; + static final int RIL_REQUEST_ENTER_SIM_PERSO = 10035; + static final int RIL_REQUEST_GET_TIME_INFO = 10036; + static final int RIL_REQUEST_OMADM_SETUP_SESSION = 10037; + static final int RIL_REQUEST_OMADM_SERVER_START_SESSION = 10038; + static final int RIL_REQUEST_OMADM_CLIENT_START_SESSION = 10039; + static final int RIL_REQUEST_OMADM_SEND_DATA = 10040; + static final int RIL_REQUEST_CDMA_GET_DATAPROFILE = 10041; + static final int RIL_REQUEST_CDMA_SET_DATAPROFILE = 10042; + static final int RIL_REQUEST_CDMA_GET_SYSTEMPROPERTIES = 10043; + static final int RIL_REQUEST_CDMA_SET_SYSTEMPROPERTIES = 10044; + static final int RIL_REQUEST_SEND_SMS_COUNT = 10045; + static final int RIL_REQUEST_SEND_SMS_MSG = 10046; + static final int RIL_REQUEST_SEND_SMS_MSG_READ_STATUS = 10047; + static final int RIL_REQUEST_MODEM_HANGUP = 10048; + static final int RIL_REQUEST_SET_SIM_POWER = 10049; + static final int RIL_REQUEST_SET_PREFERRED_NETWORK_LIST = 10050; + static final int RIL_REQUEST_GET_PREFERRED_NETWORK_LIST = 10051; + static final int RIL_REQUEST_HANGUP_VT = 10052; + + static final int RIL_UNSOL_RELEASE_COMPLETE_MESSAGE = 11001; + static final int RIL_UNSOL_STK_SEND_SMS_RESULT = 11002; + static final int RIL_UNSOL_STK_CALL_CONTROL_RESULT = 11003; + static final int RIL_UNSOL_DUN_CALL_STATUS = 11004; + + static final int RIL_UNSOL_O2_HOME_ZONE_INFO = 11007; + static final int RIL_UNSOL_DEVICE_READY_NOTI = 11008; + static final int RIL_UNSOL_GPS_NOTI = 11009; + static final int RIL_UNSOL_AM = 11010; + static final int RIL_UNSOL_DUN_PIN_CONTROL_SIGNAL = 11011; + static final int RIL_UNSOL_DATA_SUSPEND_RESUME = 11012; + static final int RIL_UNSOL_SAP = 11013; + + static final int RIL_UNSOL_SIM_SMS_STORAGE_AVAILALE = 11015; + static final int RIL_UNSOL_HSDPA_STATE_CHANGED = 11016; + static final int RIL_UNSOL_WB_AMR_STATE = 11017; + static final int RIL_UNSOL_TWO_MIC_STATE = 11018; + static final int RIL_UNSOL_DHA_STATE = 11019; + static final int RIL_UNSOL_UART = 11020; + static final int RIL_UNSOL_RESPONSE_HANDOVER = 11021; + static final int RIL_UNSOL_IPV6_ADDR = 11022; + static final int RIL_UNSOL_NWK_INIT_DISC_REQUEST = 11023; + static final int RIL_UNSOL_RTS_INDICATION = 11024; + static final int RIL_UNSOL_OMADM_SEND_DATA = 11025; + static final int RIL_UNSOL_DUN = 11026; + static final int RIL_UNSOL_SYSTEM_REBOOT = 11027; + static final int RIL_UNSOL_VOICE_PRIVACY_CHANGED = 11028; + static final int RIL_UNSOL_UTS_GETSMSCOUNT = 11029; + static final int RIL_UNSOL_UTS_GETSMSMSG = 11030; + static final int RIL_UNSOL_UTS_GET_UNREAD_SMS_STATUS = 11031; + static final int RIL_UNSOL_MIP_CONNECT_STATUS = 11032; + + protected HandlerThread mSmdk4210Thread; + protected ConnectivityHandler mSmdk4210Handler; + private AudioManager audioManager; + + public Smdk4210RIL(Context context, int networkMode, int cdmaSubscription) { + super(context, networkMode, cdmaSubscription); + audioManager = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE); + } + + @Override + public void setCurrentPreferredNetworkType() { + if (RILJ_LOGD) riljLog("setCurrentPreferredNetworkType IGNORED"); + /* Google added this as a fix for crespo loosing network type after + * taking an OTA. This messes up the data connection state for us + * due to the way we handle network type change (disable data + * then change then re-enable). + */ + } + + private boolean NeedReconnect() + { + ConnectivityManager cm = + (ConnectivityManager)mContext.getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo ni_active = cm.getActiveNetworkInfo(); + + return ni_active != null && ni_active.getTypeName().equalsIgnoreCase( "mobile" ) && + ni_active.isConnected() && cm.getMobileDataEnabled(); + } + + @Override + public void setPreferredNetworkType(int networkType , Message response) { + /* Samsung modem implementation does bad things when a datacall is running + * while switching the preferred networktype. + */ + HandlerThread handlerThread; + Looper looper; + + if(NeedReconnect()) + { + if (mSmdk4210Handler == null) { + + handlerThread = new HandlerThread("mSmdk4210Thread"); + mSmdk4210Thread = handlerThread; + + mSmdk4210Thread.start(); + + looper = mSmdk4210Thread.getLooper(); + mSmdk4210Handler = new ConnectivityHandler(mContext, looper); + } + mSmdk4210Handler.setPreferedNetworkType(networkType, response); + } else { + if (mSmdk4210Handler != null) { + mSmdk4210Thread = null; + mSmdk4210Handler = null; + } + sendPreferedNetworktype(networkType, response); + } + + } + + //Sends the real RIL request to the modem. + private void sendPreferedNetworktype(int networkType, Message response) { + RILRequest rr = RILRequest.obtain( + RILConstants.RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, response); + + rr.mp.writeInt(1); + rr.mp.writeInt(networkType); + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + + " : " + networkType); + + send(rr); + } + + /* private class that does the handling for the dataconnection + * dataconnection is done async, so we send the request for disabling it, + * wait for the response, set the prefered networktype and notify the + * real sender with its result. + */ + private class ConnectivityHandler extends Handler{ + + private static final int MESSAGE_SET_PREFERRED_NETWORK_TYPE = 30; + private Context mContext; + private int mDesiredNetworkType; + //the original message, we need it for calling back the original caller when done + private Message mNetworktypeResponse; + private ConnectivityBroadcastReceiver mConnectivityReceiver = new ConnectivityBroadcastReceiver(); + + public ConnectivityHandler(Context context, Looper looper) + { + super (looper); + mContext = context; + } + + private void startListening() { + IntentFilter filter = new IntentFilter(); + filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); + mContext.registerReceiver(mConnectivityReceiver, filter); + } + + private synchronized void stopListening() { + mContext.unregisterReceiver(mConnectivityReceiver); + } + + public void setPreferedNetworkType(int networkType, Message response) + { + Log.d(LOG_TAG, "Mobile Dataconnection is online setting it down"); + mDesiredNetworkType = networkType; + mNetworktypeResponse = response; + ConnectivityManager cm = + (ConnectivityManager)mContext.getSystemService(Context.CONNECTIVITY_SERVICE); + //start listening for the connectivity change broadcast + startListening(); + cm.setMobileDataEnabled(false); + } + + @Override + public void handleMessage(Message msg) { + switch(msg.what) { + //networktype was set, now we can enable the dataconnection again + case MESSAGE_SET_PREFERRED_NETWORK_TYPE: + ConnectivityManager cm = + (ConnectivityManager)mContext.getSystemService(Context.CONNECTIVITY_SERVICE); + + Log.d(LOG_TAG, "preferred NetworkType set upping Mobile Dataconnection"); + cm.setMobileDataEnabled(true); + //everything done now call back that we have set the networktype + AsyncResult.forMessage(mNetworktypeResponse, null, null); + mNetworktypeResponse.sendToTarget(); + mNetworktypeResponse = null; + break; + default: + throw new RuntimeException("unexpected event not handled"); + } + } + + private class ConnectivityBroadcastReceiver extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (!action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { + Log.w(LOG_TAG, "onReceived() called with " + intent); + return; + } + boolean noConnectivity = + intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false); + + if (noConnectivity) { + //Ok dataconnection is down, now set the networktype + Log.w(LOG_TAG, "Mobile Dataconnection is now down setting preferred NetworkType"); + stopListening(); + sendPreferedNetworktype(mDesiredNetworkType, obtainMessage(MESSAGE_SET_PREFERRED_NETWORK_TYPE)); + mDesiredNetworkType = -1; + } + } + } + } + + @Override + protected void processSolicited (Parcel p) { + int serial, error; + boolean found = false; + + serial = p.readInt(); + error = p.readInt(); + + RILRequest rr; + + rr = findAndRemoveRequestFromList(serial); + + if (rr == null) { + Log.w(LOG_TAG, "Unexpected solicited response! sn: " + + serial + " error: " + error); + return; + } + + Object ret = null; + + if (error == 0 || p.dataAvail() > 0) { + // either command succeeds or command fails but with data payload + try {switch (rr.mRequest) { + + case RIL_REQUEST_GET_SIM_STATUS: ret = responseIccCardStatus(p); break; + case RIL_REQUEST_ENTER_SIM_PIN: ret = responseInts(p); break; + case RIL_REQUEST_ENTER_SIM_PUK: ret = responseInts(p); break; + case RIL_REQUEST_ENTER_SIM_PIN2: ret = responseInts(p); break; + case RIL_REQUEST_ENTER_SIM_PUK2: ret = responseInts(p); break; + case RIL_REQUEST_CHANGE_SIM_PIN: ret = responseInts(p); break; + case RIL_REQUEST_CHANGE_SIM_PIN2: ret = responseInts(p); break; + case RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION: ret = responseInts(p); break; + case RIL_REQUEST_GET_CURRENT_CALLS: ret = responseCallList(p); break; + case RIL_REQUEST_DIAL: ret = responseVoid(p); break; + case RIL_REQUEST_GET_IMSI: ret = responseString(p); break; + case RIL_REQUEST_HANGUP: ret = responseVoid(p); break; + case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND: ret = responseVoid(p); break; + case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND: ret = responseVoid(p); break; + case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE: ret = responseVoid(p); break; + case RIL_REQUEST_CONFERENCE: ret = responseVoid(p); break; + case RIL_REQUEST_UDUB: ret = responseVoid(p); break; + case RIL_REQUEST_LAST_CALL_FAIL_CAUSE: ret = responseInts(p); break; + case RIL_REQUEST_SIGNAL_STRENGTH: ret = responseSignalStrength(p); break; + case RIL_REQUEST_VOICE_REGISTRATION_STATE: ret = responseStrings(p); break; + case RIL_REQUEST_DATA_REGISTRATION_STATE: ret = responseStrings(p); break; + case RIL_REQUEST_OPERATOR: ret = responseStrings(p); break; + case RIL_REQUEST_RADIO_POWER: ret = responseVoid(p); break; + case RIL_REQUEST_DTMF: ret = responseVoid(p); break; + case RIL_REQUEST_SEND_SMS: ret = responseSMS(p); break; + case RIL_REQUEST_SEND_SMS_EXPECT_MORE: ret = responseSMS(p); break; + case RIL_REQUEST_SETUP_DATA_CALL: ret = responseSetupDataCall(p); break; + case RIL_REQUEST_SIM_IO: ret = responseICC_IO(p); break; + case RIL_REQUEST_SEND_USSD: ret = responseVoid(p); break; + case RIL_REQUEST_CANCEL_USSD: ret = responseVoid(p); break; + case RIL_REQUEST_GET_CLIR: ret = responseInts(p); break; + case RIL_REQUEST_SET_CLIR: ret = responseVoid(p); break; + case RIL_REQUEST_QUERY_CALL_FORWARD_STATUS: ret = responseCallForward(p); break; + case RIL_REQUEST_SET_CALL_FORWARD: ret = responseVoid(p); break; + case RIL_REQUEST_QUERY_CALL_WAITING: ret = responseInts(p); break; + case RIL_REQUEST_SET_CALL_WAITING: ret = responseVoid(p); break; + case RIL_REQUEST_SMS_ACKNOWLEDGE: ret = responseVoid(p); break; + case RIL_REQUEST_GET_IMEI: ret = responseString(p); break; + case RIL_REQUEST_GET_IMEISV: ret = responseString(p); break; + case RIL_REQUEST_ANSWER: ret = responseVoid(p); break; + case RIL_REQUEST_DEACTIVATE_DATA_CALL: ret = responseVoid(p); break; + case RIL_REQUEST_QUERY_FACILITY_LOCK: ret = responseInts(p); break; + case RIL_REQUEST_SET_FACILITY_LOCK: ret = responseInts(p); break; + case RIL_REQUEST_CHANGE_BARRING_PASSWORD: ret = responseVoid(p); break; + case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE: ret = responseInts(p); break; + case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC: ret = responseVoid(p); break; + case RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL: ret = responseVoid(p); break; + case RIL_REQUEST_QUERY_AVAILABLE_NETWORKS : ret = responseOperatorInfos(p); break; + case RIL_REQUEST_DTMF_START: ret = responseVoid(p); break; + case RIL_REQUEST_DTMF_STOP: ret = responseVoid(p); break; + case RIL_REQUEST_BASEBAND_VERSION: ret = responseString(p); break; + case RIL_REQUEST_SEPARATE_CONNECTION: ret = responseVoid(p); break; + case RIL_REQUEST_SET_MUTE: ret = responseVoid(p); break; + case RIL_REQUEST_GET_MUTE: ret = responseInts(p); break; + case RIL_REQUEST_QUERY_CLIP: ret = responseInts(p); break; + case RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE: ret = responseInts(p); break; + case RIL_REQUEST_DATA_CALL_LIST: ret = responseDataCallList(p); break; + case RIL_REQUEST_RESET_RADIO: ret = responseVoid(p); break; + case RIL_REQUEST_OEM_HOOK_RAW: ret = responseRaw(p); break; + case RIL_REQUEST_OEM_HOOK_STRINGS: ret = responseStrings(p); break; + case RIL_REQUEST_SCREEN_STATE: ret = responseVoid(p); break; + case RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION: ret = responseVoid(p); break; + case RIL_REQUEST_WRITE_SMS_TO_SIM: ret = responseInts(p); break; + case RIL_REQUEST_DELETE_SMS_ON_SIM: ret = responseVoid(p); break; + case RIL_REQUEST_SET_BAND_MODE: ret = responseVoid(p); break; + case RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE: ret = responseInts(p); break; + case RIL_REQUEST_STK_GET_PROFILE: ret = responseString(p); break; + case RIL_REQUEST_STK_SET_PROFILE: ret = responseVoid(p); break; + case RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND: ret = responseString(p); break; + case RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE: ret = responseVoid(p); break; + case RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM: ret = responseInts(p); break; + case RIL_REQUEST_EXPLICIT_CALL_TRANSFER: ret = responseVoid(p); break; + case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE: ret = responseVoid(p); break; + case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE: ret = responseGetPreferredNetworkType(p); break; + case RIL_REQUEST_GET_NEIGHBORING_CELL_IDS: ret = responseVoid(p); break; + case RIL_REQUEST_SET_LOCATION_UPDATES: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE: ret = responseInts(p); break; + case RIL_REQUEST_SET_TTY_MODE: ret = responseVoid(p); break; + case RIL_REQUEST_QUERY_TTY_MODE: ret = responseInts(p); break; + case RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE: ret = responseInts(p); break; + case RIL_REQUEST_CDMA_FLASH: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_BURST_DTMF: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_SEND_SMS: ret = responseSMS(p); break; + case RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE: ret = responseVoid(p); break; + case RIL_REQUEST_GSM_GET_BROADCAST_CONFIG: ret = responseGmsBroadcastConfig(p); break; + case RIL_REQUEST_GSM_SET_BROADCAST_CONFIG: ret = responseVoid(p); break; + case RIL_REQUEST_GSM_BROADCAST_ACTIVATION: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_GET_BROADCAST_CONFIG: ret = responseCdmaBroadcastConfig(p); break; + case RIL_REQUEST_CDMA_SET_BROADCAST_CONFIG: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_BROADCAST_ACTIVATION: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_SUBSCRIPTION: ret = responseStrings(p); break; + case RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM: ret = responseInts(p); break; + case RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM: ret = responseVoid(p); break; + case RIL_REQUEST_DEVICE_IDENTITY: ret = responseStrings(p); break; + case RIL_REQUEST_GET_SMSC_ADDRESS: ret = responseString(p); break; + case RIL_REQUEST_SET_SMSC_ADDRESS: ret = responseVoid(p); break; + case RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE: ret = responseVoid(p); break; + case RIL_REQUEST_REPORT_SMS_MEMORY_STATUS: ret = responseVoid(p); break; + case RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE: ret = responseInts(p); break; + case RIL_REQUEST_ISIM_AUTHENTICATION: ret = responseString(p); break; + default: + throw new RuntimeException("Unrecognized solicited response: " + rr.mRequest); + //break; + }} catch (Throwable tr) { + // Exceptions here usually mean invalid RIL responses + + Log.w(LOG_TAG, rr.serialString() + "< " + + requestToString(rr.mRequest) + + " exception, possible invalid RIL response", tr); + + if (rr.mResult != null) { + AsyncResult.forMessage(rr.mResult, null, tr); + rr.mResult.sendToTarget(); + } + rr.release(); + return; + } + } + + if (error != 0) { + //ugly fix for Samsung messing up SMS_SEND request fail in binary RIL + if(!(error == -1 && rr.mRequest == RIL_REQUEST_SEND_SMS)) + { + rr.onError(error, ret); + rr.release(); + return; + } else { + try + { + ret = responseSMS(p); + } catch (Throwable tr) { + Log.w(LOG_TAG, rr.serialString() + "< " + + requestToString(rr.mRequest) + + " exception, Processing Samsung SMS fix ", tr); + rr.onError(error, ret); + rr.release(); + return; + } + } + } + + 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(); + } + + rr.release(); + } + + @Override + protected void + processUnsolicited (Parcel p) { + Object ret; + int dataPosition = p.dataPosition(); + int response = p.readInt(); + + switch (response) { + case RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS: ret = responseString(p); break; + case RIL_UNSOL_RIL_CONNECTED: ret = responseInts(p); break; + // SAMSUNG STATES + case RIL_UNSOL_AM: ret = responseString(p); break; + case RIL_UNSOL_DUN_PIN_CONTROL_SIGNAL: ret = responseVoid(p); break; + case RIL_UNSOL_DATA_SUSPEND_RESUME: ret = responseInts(p); break; + case RIL_UNSOL_STK_CALL_CONTROL_RESULT: ret = responseVoid(p); break; + case RIL_UNSOL_TWO_MIC_STATE: ret = responseInts(p); break; + case RIL_UNSOL_WB_AMR_STATE: 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); + return; + } + + switch (response) { + case RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS: + if (RILJ_LOGD) unsljLogRet(response, ret); + + if (mGsmBroadcastSmsRegistrant != null) { + mGsmBroadcastSmsRegistrant + .notifyRegistrant(new AsyncResult(null, ret, null)); + } + break; + case RIL_UNSOL_RIL_CONNECTED: + if (RILJ_LOGD) unsljLogRet(response, ret); + + // Initial conditions + setRadioPower(false, null); + sendPreferedNetworktype(mPreferredNetworkType, null); + setCdmaSubscriptionSource(mCdmaSubscription, null); + notifyRegistrantsRilConnectionChanged(((int[])ret)[0]); + break; + // SAMSUNG STATES + case RIL_UNSOL_AM: + if (RILJ_LOGD) samsungUnsljLogRet(response, ret); + String amString = (String) ret; + Log.d(LOG_TAG, "Executing AM: " + amString); + + try { + Runtime.getRuntime().exec("am " + amString); + } catch (IOException e) { + e.printStackTrace(); + Log.e(LOG_TAG, "am " + amString + " could not be executed."); + } + break; + case RIL_UNSOL_DUN_PIN_CONTROL_SIGNAL: + if (RILJ_LOGD) samsungUnsljLogRet(response, ret); + break; + case RIL_UNSOL_DATA_SUSPEND_RESUME: + if (RILJ_LOGD) samsungUnsljLogRet(response, ret); + break; + case RIL_UNSOL_STK_CALL_CONTROL_RESULT: + if (RILJ_LOGD) samsungUnsljLogRet(response, ret); + break; + case RIL_UNSOL_TWO_MIC_STATE: + if (RILJ_LOGD) samsungUnsljLogRet(response, ret); + break; + case RIL_UNSOL_WB_AMR_STATE: + if (RILJ_LOGD) samsungUnsljLogRet(response, ret); + setWbAmr(((int[])ret)[0]); + break; + } + } + + static String + samsungResponseToString(int request) + { + switch(request) { + // SAMSUNG STATES + case RIL_UNSOL_AM: return "RIL_UNSOL_AM"; + case RIL_UNSOL_DUN_PIN_CONTROL_SIGNAL: return "RIL_UNSOL_DUN_PIN_CONTROL_SIGNAL"; + case RIL_UNSOL_DATA_SUSPEND_RESUME: return "RIL_UNSOL_DATA_SUSPEND_RESUME"; + case RIL_UNSOL_STK_CALL_CONTROL_RESULT: return "RIL_UNSOL_STK_CALL_CONTROL_RESULT"; + case RIL_UNSOL_TWO_MIC_STATE: return "RIL_UNSOL_TWO_MIC_STATE"; + case RIL_UNSOL_WB_AMR_STATE: return "RIL_UNSOL_WB_AMR_STATE"; + default: return ""; + } + } + + protected void samsungUnsljLog(int response) { + riljLog("[UNSL]< " + samsungResponseToString(response)); + } + + protected void samsungUnsljLogMore(int response, String more) { + riljLog("[UNSL]< " + samsungResponseToString(response) + " " + more); + } + + protected void samsungUnsljLogRet(int response, Object ret) { + riljLog("[UNSL]< " + samsungResponseToString(response) + " " + retToString(response, ret)); + } + + protected void samsungUnsljLogvRet(int response, Object ret) { + riljLogv("[UNSL]< " + samsungResponseToString(response) + " " + retToString(response, ret)); + } + + /** + * Notifiy all registrants that the ril has connected or disconnected. + * + * @param rilVer is the version of the ril or -1 if disconnected. + */ + private void notifyRegistrantsRilConnectionChanged(int rilVer) { + mRilVersion = rilVer; + if (mRilConnectedRegistrants != null) { + mRilConnectedRegistrants.notifyRegistrants( + new AsyncResult (null, new Integer(rilVer), null)); + } + } + + /** + * Set audio parameter "wb_amr" for HD-Voice (Wideband AMR). + * + * @param state: 0 = unsupported, 1 = supported. + */ + private void setWbAmr(int state) { + if (state == 1) { + Log.d(LOG_TAG, "setWbAmr(): setting audio parameter - wb_amr=on"); + audioManager.setParameters("wb_amr=on"); + } else { + Log.d(LOG_TAG, "setWbAmr(): setting audio parameter - wb_amr=off"); + audioManager.setParameters("wb_amr=off"); + } + } + + @Override + protected Object + responseCallList(Parcel p) { + int num; + boolean isVideo; + ArrayList response; + DriverCall dc; + int dataAvail = p.dataAvail(); + int pos = p.dataPosition(); + int size = p.dataSize(); + + Log.d(LOG_TAG, "Parcel size = " + size); + Log.d(LOG_TAG, "Parcel pos = " + pos); + Log.d(LOG_TAG, "Parcel dataAvail = " + dataAvail); + + //Samsung changes + num = p.readInt(); + + Log.d(LOG_TAG, "num = " + num); + response = new ArrayList(num); + + for (int i = 0 ; i < num ; i++) { + + dc = new DriverCall(); + dc.state = DriverCall.stateFromCLCC(p.readInt()); + dc.index = p.readInt(); + dc.TOA = p.readInt(); + dc.isMpty = (0 != p.readInt()); + dc.isMT = (0 != p.readInt()); + dc.als = p.readInt(); + dc.isVoice = (0 != p.readInt()); + isVideo = (0 != p.readInt()); + dc.isVoicePrivacy = (0 != p.readInt()); + 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(); + + Log.d(LOG_TAG, "state = " + dc.state); + Log.d(LOG_TAG, "index = " + dc.index); + Log.d(LOG_TAG, "state = " + dc.TOA); + Log.d(LOG_TAG, "isMpty = " + dc.isMpty); + Log.d(LOG_TAG, "isMT = " + dc.isMT); + Log.d(LOG_TAG, "als = " + dc.als); + Log.d(LOG_TAG, "isVoice = " + dc.isVoice); + Log.d(LOG_TAG, "isVideo = " + isVideo); + Log.d(LOG_TAG, "number = " + dc.number); + Log.d(LOG_TAG, "np = " + np); + Log.d(LOG_TAG, "name = " + dc.name); + Log.d(LOG_TAG, "namePresentation = " + dc.namePresentation); + Log.d(LOG_TAG, "uusInfoPresent = " + uusInfoPresent); + + 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); + Log + .v(LOG_TAG, String.format("Incoming UUS : type=%d, dcs=%d, length=%d", + dc.uusInfo.getType(), dc.uusInfo.getDcs(), + dc.uusInfo.getUserData().length)); + Log.v(LOG_TAG, "Incoming UUS : data (string)=" + + new String(dc.uusInfo.getUserData())); + Log.v(LOG_TAG, "Incoming UUS : data (hex): " + + IccUtils.bytesToHexString(dc.uusInfo.getUserData())); + } else { + Log.v(LOG_TAG, "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(); + Log.d(LOG_TAG, "InCall VoicePrivacy is enabled"); + } else { + mVoicePrivacyOffRegistrants.notifyRegistrants(); + Log.d(LOG_TAG, "InCall VoicePrivacy is disabled"); + } + } + + Collections.sort(response); + + return response; + } + + @Override + protected Object responseGetPreferredNetworkType(Parcel p) { + int [] response = (int[]) responseInts(p); + + if (response.length >= 1) { + // Since this is the response for getPreferredNetworkType + // we'll assume that it should be the value we want the + // vendor ril to take if we reestablish a connection to it. + mPreferredNetworkType = response[0]; + } + + // When the modem responds Phone.NT_MODE_GLOBAL, it means Phone.NT_MODE_WCDMA_PREF + if (response[0] == Phone.NT_MODE_GLOBAL) { + Log.d(LOG_TAG, "Overriding network type response from GLOBAL to WCDMA preferred"); + response[0] = Phone.NT_MODE_WCDMA_PREF; + } + + return response; + } + + @Override + protected Object + responseOperatorInfos(Parcel p) { + String strings[] = (String [])responseStrings(p); + ArrayList ret; + + if (strings.length % 5 != 0) { + throw new RuntimeException( + "RIL_REQUEST_QUERY_AVAILABLE_NETWORKS: invalid response. Got " + + strings.length + " strings, expected multible of 5"); + } + + ret = new ArrayList(strings.length / 5); + + for (int i = 0 ; i < strings.length ; i += 5) { + ret.add ( + new OperatorInfo( + strings[i+0], + strings[i+1], + strings[i+2], + strings[i+3])); + } + + return ret; + } + + @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(); + } + + Log.d(LOG_TAG, "responseSignalStength BEFORE: gsmDbm=" + response[0]); + + //Samsung sends the count of bars that should be displayed instead of + //a real signal strength + int num_bars = (response[0] & 0xff00) >> 8; + + // Translate number of bars into something SignalStrength.java can understand + switch (num_bars) { + case 0 : response[0] = 1; break; // map to 0 bars + case 1 : response[0] = 3; break; // map to 1 bar + case 2 : response[0] = 5; break; // map to 2 bars + case 3 : response[0] = 8; break; // map to 3 bars + case 4 : response[0] = 12; break; // map to 4 bars + case 5 : response[0] = 15; break; // map to 4 bars but give an extra 10 dBm + default : response[0] &= 0xff; break; // no idea; just pass value through + } + + response[1] = -1; //gsmEcio + response[2] = (response[2] < 0)?-120:-response[2]; //cdmaDbm + response[3] = (response[3] < 0)?-160:-response[3]; //cdmaEcio + response[4] = (response[4] < 0)?-120:-response[4]; //evdoRssi + response[5] = (response[5] < 0)?-1:-response[5]; //evdoEcio + if (response[6] < 0 || response[6] > 8) { + response[6] = -1; + } + + Log.d(LOG_TAG, "responseSignalStength AFTER: gsmDbm=" + response[0]); + + return response; + } +} diff --git a/telephony/java/com/android/internal/telephony/SonyQualcommRIL.java b/telephony/java/com/android/internal/telephony/SonyQualcommRIL.java new file mode 100644 index 0000000000000..73ff0b29b9d06 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/SonyQualcommRIL.java @@ -0,0 +1,440 @@ +/* + * 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.text.TextUtils; +import android.util.Log; + +import java.util.ArrayList; + +/** + * Custom Qualcomm No SimReady RIL for Sony + * + * {@hide} + */ + +public class SonyQualcommRIL extends RIL implements CommandsInterface { + protected String mAid = ""; + protected HandlerThread mIccThread; + protected IccHandler mIccHandler; + boolean RILJ_LOGV = true; + boolean RILJ_LOGD = true; + + private final int RIL_INT_RADIO_OFF = 0; + private final int RIL_INT_RADIO_UNAVALIABLE = 1; + private final int RIL_INT_RADIO_ON = 10; + + public SonyQualcommRIL(Context context, int networkMode, int cdmaSubscription) { + super(context, networkMode, cdmaSubscription); + } + + @Override + public void + iccIO (int command, int fileid, String path, int p1, int p2, int p3, + String data, String pin2, Message result) { + iccIOForApp(command, fileid, path, p1, p2, p3, data, pin2, mAid, result); + } + + @Override public void + supplyIccPin(String pin, Message result) { + supplyIccPinForApp(pin, mAid, result); + } + + @Override public void + changeIccPin(String oldPin, String newPin, Message result) { + changeIccPinForApp(oldPin, newPin, mAid, result); + } + + @Override public void + supplyIccPin2(String pin, Message result) { + supplyIccPin2ForApp(pin, mAid, result); + } + + @Override public void + changeIccPin2(String oldPin2, String newPin2, Message result) { + changeIccPin2ForApp(oldPin2, newPin2, mAid, result); + } + + @Override public void + supplyIccPuk(String puk, String newPin, Message result) { + supplyIccPukForApp(puk, newPin, mAid, result); + } + + @Override public void + supplyIccPuk2(String puk2, String newPin2, Message result) { + supplyIccPuk2ForApp(puk2, newPin2, mAid, result); + } + + @Override + public void + queryFacilityLock(String facility, String password, int serviceClass, + Message response) { + queryFacilityLockForApp(facility, password, serviceClass, mAid, response); + } + + @Override + public void + setFacilityLock (String facility, boolean lockState, String password, + int serviceClass, Message response) { + setFacilityLockForApp(facility, lockState, password, serviceClass, mAid, response); + } + + @Override + protected Object + responseIccCardStatus(Parcel p) { + IccCardApplication ca; + + IccCardStatus status = new IccCardStatus(); + status.setCardState(p.readInt()); + status.setUniversalPinState(p.readInt()); + status.setGsmUmtsSubscriptionAppIndex(p.readInt()); + status.setCdmaSubscriptionAppIndex(p.readInt()); + status.setImsSubscriptionAppIndex(p.readInt()); + + int numApplications = p.readInt(); + // limit to maximum allowed applications + if (numApplications > IccCardStatus.CARD_MAX_APPS) { + numApplications = IccCardStatus.CARD_MAX_APPS; + } + status.setNumApplications(numApplications); + + for (int i = 0 ; i < numApplications ; i++) { + ca = new IccCardApplication(); + ca.app_type = ca.AppTypeFromRILInt(p.readInt()); + ca.app_state = ca.AppStateFromRILInt(p.readInt()); + ca.perso_substate = ca.PersoSubstateFromRILInt(p.readInt()); + ca.aid = p.readString(); + ca.app_label = p.readString(); + ca.pin1_replaced = p.readInt(); + ca.pin1 = ca.PinStateFromRILInt(p.readInt()); + ca.pin2 = ca.PinStateFromRILInt(p.readInt()); + status.addApplication(ca); + } + + updateIccType(status); + return status; + } + + private void updateIccType (IccCardStatus status) { + int appType; + if (status.getNumApplications() > 0) { + if (mPhoneType == RILConstants.CDMA_PHONE) + appType = status.getCdmaSubscriptionAppIndex(); + else + appType = status.getGsmUmtsSubscriptionAppIndex(); + + IccCardApplication application = status.getApplication(appType); + mAid = application.aid; + Log.d(LOG_TAG, "Picked default AID: " + mAid); + } + } + + @Override + public void + getIMSI(Message result) { + getIMSIForApp(mAid, result); + } + + @Override + protected Object + responseOperatorInfos(Parcel p) { + String strings[] = (String [])responseStrings(p); + ArrayList ret; + + if (strings.length % 5 != 0) { + throw new RuntimeException( + "RIL_REQUEST_QUERY_AVAILABLE_NETWORKS: invalid response. Got " + + strings.length + " strings, expected multible of 5"); + } + + ret = new ArrayList(strings.length / 4); + + for (int i = 0 ; i < strings.length ; i += 5) { + ret.add ( + new OperatorInfo( + strings[i+0], + strings[i+1], + strings[i+2], + strings[i+3])); + } + return ret; + } + + @Override + public void + dial(String address, int clirMode, UUSInfo uusInfo, Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_DIAL, result); + + rr.mp.writeString(address); + rr.mp.writeInt(clirMode); + + if (uusInfo == null) { + rr.mp.writeInt(0); // UUS information is absent + } else { + rr.mp.writeInt(1); // UUS information is present + rr.mp.writeInt(uusInfo.getType()); + rr.mp.writeInt(uusInfo.getDcs()); + rr.mp.writeByteArray(uusInfo.getUserData()); + } + rr.mp.writeInt(255); + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + + send(rr); + } + + public void + setNetworkSelectionMode(String operatorNumeric, Message response) { + RILRequest rr; + + if (operatorNumeric == null) + rr = RILRequest.obtain(RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC, response); + else + rr = RILRequest.obtain(RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL, response); + + rr.mp.writeString(operatorNumeric); + rr.mp.writeInt(-1); + + send(rr); + } + + @Override + public void + setNetworkSelectionModeAutomatic(Message response) { + setNetworkSelectionMode(null, response); + } + + @Override + public void + setNetworkSelectionModeManual(String operatorNumeric, Message response) { + setNetworkSelectionMode(operatorNumeric, response); + } + + @Override + protected void + switchToRadioState(RadioState newState) { + if (newState.isOn() && !getRadioState().isOn()) + getVoiceRadioTechnology(null); + setRadioState(newState); + } + + + @Override + protected Object + responseSignalStrength(Parcel p) { + int numInts = 12; + int response[]; + + boolean noLte = false; + + /* TODO: Add SignalStrength class to match RIL_SignalStrength */ + response = new int[numInts]; + for (int i = 0 ; i < numInts ; i++) { + if (noLte && i > 6 && i < 12) { + response[i] = -1; + } else { + response[i] = p.readInt(); + } + if (i == 7 && response[i] == 99) { + response[i] = -1; + noLte = true; + } + if (i == 8 && !noLte) { + response[i] *= -1; + } + } + + 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_RESPONSE_RADIO_STATE_CHANGED: ret = responseVoid(p); break; + + default: + // Rewind the Parcel + p.setDataPosition(dataPosition); + + // Forward responses that we are not overriding to the super class + super.processUnsolicited(p); + return; + } + + switch(response) { + case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED: + int state = p.readInt(); + setRadioStateFromRILInt(state); + break; + } + } + + private void setRadioStateFromRILInt (int stateCode) { + CommandsInterface.RadioState radioState; + HandlerThread handlerThread; + Looper looper; + IccHandler iccHandler; + + switch (stateCode) { + case RIL_INT_RADIO_OFF: + radioState = CommandsInterface.RadioState.RADIO_OFF; + if (mIccHandler != null) { + mIccThread = null; + mIccHandler = null; + } + break; + case RIL_INT_RADIO_UNAVALIABLE: + radioState = CommandsInterface.RadioState.RADIO_UNAVAILABLE; + break; + case RIL_INT_RADIO_ON: + if (mIccHandler == null) { + handlerThread = new HandlerThread("IccHandler"); + mIccThread = handlerThread; + + mIccThread.start(); + + looper = mIccThread.getLooper(); + mIccHandler = new IccHandler(this,looper); + mIccHandler.run(); + } + radioState = CommandsInterface.RadioState.RADIO_ON; + break; + default: + throw new RuntimeException("Unrecognized RIL_RadioState: " + stateCode); + } + + switchToRadioState(radioState); + } + + class IccHandler extends Handler implements Runnable { + private static final int EVENT_GET_ICC_STATUS_DONE = 1; + private static final int EVENT_ICC_STATUS_CHANGED = 2; + private static final int EVENT_RADIO_ON = 3; + private static final int EVENT_RADIO_OFF_OR_UNAVAILABLE = 4; + + private RIL mRil; + private boolean mRadioOn = false; + + public IccHandler (RIL ril, Looper looper) { + super (looper); + mRil = ril; + } + + public void handleMessage (Message paramMessage) { + switch (paramMessage.what) { + case EVENT_RADIO_ON: + mRadioOn = true; + Log.d(LOG_TAG, "Radio on -> Forcing sim status update"); + sendMessage(obtainMessage(EVENT_ICC_STATUS_CHANGED)); + break; + case EVENT_GET_ICC_STATUS_DONE: + AsyncResult asyncResult = (AsyncResult) paramMessage.obj; + if (asyncResult.exception != null) { + Log.e (LOG_TAG, "IccCardStatusDone shouldn't return exceptions!", asyncResult.exception); + break; + } + IccCardStatus status = (IccCardStatus) asyncResult.result; + if (status.getNumApplications() == 0) { + if (!mRil.getRadioState().isOn()) { + break; + } + + mRil.setRadioState(CommandsInterface.RadioState.RADIO_ON); + } else { + int appIndex = -1; + if (mPhoneType == RILConstants.CDMA_PHONE) { + appIndex = status.getCdmaSubscriptionAppIndex(); + Log.d(LOG_TAG, "This is a CDMA PHONE " + appIndex); + } else { + appIndex = status.getGsmUmtsSubscriptionAppIndex(); + Log.d(LOG_TAG, "This is a GSM PHONE " + appIndex); + } + + IccCardApplication application = status.getApplication(appIndex); + IccCardApplication.AppState app_state = application.app_state; + IccCardApplication.AppType app_type = application.app_type; + switch (app_state) { + case APPSTATE_PIN: + case APPSTATE_PUK: + switch (app_type) { + case APPTYPE_SIM: + case APPTYPE_USIM: + case APPTYPE_RUIM: + mRil.setRadioState(CommandsInterface.RadioState.RADIO_ON); + break; + default: + Log.e(LOG_TAG, "Currently we don't handle SIMs of type: " + app_type); + return; + } + break; + case APPSTATE_READY: + switch (app_type) { + case APPTYPE_SIM: + case APPTYPE_USIM: + case APPTYPE_RUIM: + mRil.setRadioState(CommandsInterface.RadioState.RADIO_ON); + break; + default: + Log.e(LOG_TAG, "Currently we don't handle SIMs of type: " + app_type); + return; + } + break; + default: + return; + } + } + break; + case EVENT_ICC_STATUS_CHANGED: + if (mRadioOn) { + Log.d(LOG_TAG, "Received EVENT_ICC_STATUS_CHANGED, calling getIccCardStatus"); + mRil.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE, paramMessage.obj)); + } else { + Log.d(LOG_TAG, "Received EVENT_ICC_STATUS_CHANGED while radio is not ON. Ignoring"); + } + break; + case EVENT_RADIO_OFF_OR_UNAVAILABLE: + mRadioOn = false; + // disposeCards(); // to be verified; + default: + Log.e(LOG_TAG, " Unknown Event " + paramMessage.what); + break; + } + } + + public void run () { + mRil.registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, null); + Message msg = obtainMessage(EVENT_RADIO_ON); + mRil.getIccCardStatus(msg); + } + } +} diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java index 0a40c759848e3..7af2fc2e6aea8 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java @@ -176,7 +176,7 @@ protected void pollState() { android.provider.Settings.Secure.PREFERRED_NETWORK_MODE, RILConstants.PREFERRED_NETWORK_MODE); if (DBG) log("pollState: network mode here is = " + networkMode); - if ((networkMode == RILConstants.NETWORK_MODE_GLOBAL) + if ((getSVDO) || (networkMode == RILConstants.NETWORK_MODE_GLOBAL) || (networkMode == RILConstants.NETWORK_MODE_LTE_ONLY)) { pollingContext[0]++; // RIL_REQUEST_DATA_REGISTRATION_STATE diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java index a6b32f9957b8a..e0b2b2c39ab3c 100755 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java @@ -52,6 +52,8 @@ import com.android.internal.telephony.cdma.sms.CdmaSmsAddress; import com.android.internal.telephony.cdma.sms.SmsEnvelope; import com.android.internal.telephony.cdma.sms.UserData; +import com.android.internal.util.BitwiseInputStream; +import com.android.internal.util.HexDump; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; @@ -221,10 +223,78 @@ public int dispatchMessage(SmsMessageBase smsb) { (SmsEnvelope.MESSAGE_TYPE_BROADCAST != sms.getMessageType())) { return Intents.RESULT_SMS_UNSUPPORTED; } - + /* + * Check to see if we have a Virgin Mobile MMS + * If so, do extra processsing for Virgin Mobile's non-standard format. + * Otherwise, dispatch normal message. + */ + if (sms.getOriginatingAddress().equals("9999999999")) { + Log.d(TAG, "Got a suspect SMS from the Virgin MMS originator"); + byte virginMMSPayload[] = null; + try { + int[] ourMessageRef = new int[1]; + virginMMSPayload = getVirginMMS(sms.getUserData(), ourMessageRef); + if (virginMMSPayload == null) { + Log.e(TAG, "Not a virgin MMS like we were expecting"); + throw new Exception("Not a Virgin MMS like we were expecting"); + } else { + Log.d(TAG, "Sending our deflowered MMS to processCdmaWapPdu"); + return processCdmaWapPdu(virginMMSPayload, ourMessageRef[0], "9999999999"); + } + } catch (Exception ourException) { + Log.e(TAG, "Got an exception trying to get VMUS MMS data " + ourException); + } + } return dispatchNormalMessage(smsb); } + private synchronized byte[] getVirginMMS(final byte[] someEncodedMMSData, int[] aMessageRef) throws Exception { + if ((aMessageRef == null) || (aMessageRef.length != 1)) { + throw new Exception("aMessageRef is not usable. Must be an int array with one element."); + } + BitwiseInputStream ourInputStream; + int i1=0; + int desiredBitLength; + Log.d(TAG, "mmsVirginGetMsgId"); + Log.d(TAG, "EncodedMMS: " + someEncodedMMSData); + try { + ourInputStream = new BitwiseInputStream(someEncodedMMSData); + ourInputStream.skip(20); + final int j = ourInputStream.read(8) << 8; + final int k = ourInputStream.read(8); + aMessageRef[0] = j | k; + Log.d(TAG, "MSGREF IS : " + aMessageRef[0]); + ourInputStream.skip(12); + i1 = ourInputStream.read(8) + -2; + ourInputStream.skip(13); + byte abyte1[] = new byte[i1]; + for (int j1 = 0; j1 < i1; j1++) { + abyte1[j1] = 0; + } + desiredBitLength = i1 * 8; + if (ourInputStream.available() < desiredBitLength) { + int availableBitLength = ourInputStream.available(); + Log.e(TAG, "mmsVirginGetMsgId inStream.available() = " + availableBitLength + " wantedBits = " + desiredBitLength); + throw new Exception("insufficient data (wanted " + desiredBitLength + " bits, but only have " + availableBitLength + ")"); + } + } catch (com.android.internal.util.BitwiseInputStream.AccessException ourException) { + final String ourExceptionText = "mmsVirginGetMsgId failed: " + ourException; + Log.e(TAG, ourExceptionText); + throw new Exception(ourExceptionText); + } + byte ret[] = null; + try { + ret = ourInputStream.readByteArray(desiredBitLength); + Log.d(TAG, "mmsVirginGetMsgId user_length = " + i1 + " msgid = " + aMessageRef[0]); + Log.d(TAG, "mmsVirginGetMsgId userdata = " + ret.toString()); + } catch (com.android.internal.util.BitwiseInputStream.AccessException ourException) { + final String ourExceptionText = "mmsVirginGetMsgId failed: " + ourException; + Log.e(TAG, ourExceptionText); + throw new Exception(ourExceptionText); + } + return ret; + } + /** * Processes inbound messages that are in the WAP-WDP PDU format. See * wap-259-wdp-20010614-a section 6.5 for details on the WAP-WDP PDU format. diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java index 5cacd23b8bf65..696fc2d449b7f 100755 --- a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java +++ b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java @@ -959,10 +959,21 @@ private static boolean decodeMessageId(BearerData bData, BitwiseInputStream inSt paramBits -= EXPECTED_PARAM_SIZE; decodeSuccess = true; bData.messageType = inStream.read(4); - bData.messageId = inStream.read(8) << 8; - bData.messageId |= inStream.read(8); - bData.hasUserDataHeader = (inStream.read(1) == 1); - inStream.skip(3); + // Some Samsung CDMAphones parses messageId differently than other devices + // fix it here so that incoming sms works correctly + boolean hasSamsungCDMAAlternateMessageIDEncoding = Resources.getSystem() + .getBoolean(com.android.internal.R.bool.config_smsSamsungCdmaAlternateMessageIDEncoding); + if (hasSamsungCDMAAlternateMessageIDEncoding) { + inStream.skip(4); + bData.messageId = inStream.read(8) << 8; + bData.messageId |= inStream.read(8); + bData.hasUserDataHeader = (inStream.read(8) == 1); + } else { + bData.messageId = inStream.read(8) << 8; + bData.messageId |= inStream.read(8); + bData.hasUserDataHeader = (inStream.read(1) == 1); + inStream.skip(3); + } } if ((! decodeSuccess) || (paramBits > 0)) { Log.d(LOG_TAG, "MESSAGE_IDENTIFIER decode " + diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java index 6e9cd51de5003..9d5d8d30ea4c4 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java +++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java @@ -342,6 +342,10 @@ public DataActivityState getDataActivityState() { case DATAINANDOUT: ret = DataActivityState.DATAINANDOUT; break; + + case DORMANT: + ret = DataActivityState.DORMANT; + break; } } diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java index a971066a6bad9..8d1ae023f0e9e 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java @@ -499,6 +499,12 @@ public synchronized int enableApnType(String apnType) { if (DBG) log("enableApnType: return APN_ALREADY_ACTIVE"); return Phone.APN_ALREADY_ACTIVE; } + if (mPhone.mCM.needsOldRilFeature("singlepdp") && !Phone.APN_TYPE_DEFAULT.equals(apnType)) { + ApnContext defContext = mApnContexts.get(Phone.APN_TYPE_DEFAULT); + if (defContext.isEnabled()) { + setEnabled(apnTypeToId(Phone.APN_TYPE_DEFAULT), false); + } + } setEnabled(apnTypeToId(apnType), true); if (DBG) { log("enableApnType: new apn request for type " + apnType + @@ -533,6 +539,9 @@ public synchronized int disableApnType(String type) { if (apnContext != null) { setEnabled(apnTypeToId(type), false); + if (mPhone.mCM.needsOldRilFeature("singlepdp") && !Phone.APN_TYPE_DEFAULT.equals(type)) { + setEnabled(apnTypeToId(Phone.APN_TYPE_DEFAULT), true); + } if (apnContext.getState() != State.IDLE && apnContext.getState() != State.FAILED) { if (DBG) log("diableApnType: return APN_REQUEST_STARTED"); return Phone.APN_REQUEST_STARTED; @@ -1190,6 +1199,28 @@ private List findApnContextToClean(Collection dcac return list; } + /** + * Clear data call entries with duplicate call ids. + * The function will retain the first found unique call id. + * + * @param dataCalls + * @return unique set of dataCalls. + */ + private ArrayList clearDuplicates( + ArrayList dataCalls) { + // clear duplicate cid's + ArrayList cids = new ArrayList(); + ArrayList uniqueCalls = new ArrayList(); + for (DataCallState dc : dataCalls) { + if (!cids.contains(dc.cid)) { + uniqueCalls.add(dc); + cids.add(dc.cid); + } + } + log("Number of DataCallStates:" + dataCalls.size() + "Unique count:" + uniqueCalls.size()); + return uniqueCalls; + } + /** * @param ar is the result of RIL_REQUEST_DATA_CALL_LIST * or RIL_UNSOL_DATA_CALL_LIST_CHANGED @@ -1209,6 +1240,11 @@ private void onDataStateChanged (AsyncResult ar) { } if (DBG) log("onDataStateChanged(ar): DataCallState size=" + dataCallStates.size()); + dataCallStates = clearDuplicates(dataCallStates); + + boolean isAnyDataCallDormant = false; + boolean isAnyDataCallActive = false; + // Create a hash map to store the dataCallState of each DataConnectionAc HashMap dataCallStateToDcac; dataCallStateToDcac = new HashMap(); @@ -1230,6 +1266,9 @@ private void onDataStateChanged (AsyncResult ar) { continue; } + if (newState.active == DATA_CONNECTION_ACTIVE_PH_LINK_UP) isAnyDataCallActive = true; + if (newState.active == DATA_CONNECTION_ACTIVE_PH_LINK_DOWN) isAnyDataCallDormant = true; + // The list of apn's associated with this DataConnection Collection apns = dcac.getApnListSync(); @@ -1315,6 +1354,32 @@ private void onDataStateChanged (AsyncResult ar) { } } + if (isAnyDataCallDormant && !isAnyDataCallActive) { + // There is no way to indicate link activity per APN right now. So + // Link Activity will be considered dormant only when all data calls + // are dormant. + // If a single data call is in dormant state and none of the data + // calls are active broadcast overall link state as dormant. + mActivity = Activity.DORMANT; + if (DBG) { + log("onDataStateChanged: Data Activity updated to DORMANT. stopNetStatePoll"); + } + stopNetStatPoll(); + stopDataStallAlarm(); + } else { + mActivity = Activity.NONE; + if (DBG) { + log("onDataStateChanged: Data Activity updated to NONE. " + + "isAnyDataCallActive = " + isAnyDataCallActive + + " isAnyDataCallDormant = " + isAnyDataCallDormant); + } + if (isAnyDataCallActive) { + startNetStatPoll(); + startDataStallAlarm(DATA_STALL_NOT_SUSPECTED); + } + } + mPhone.notifyDataActivity(); + if (apnsToCleanup.size() != 0) { // Add an event log when the network drops PDP int cid = getCellLocationId(); @@ -1337,6 +1402,8 @@ private void notifyDefaultData(ApnContext apnContext) { + ", reason:" + apnContext.getReason()); } apnContext.setState(State.CONNECTED); + mActiveApn = apnContext.getApnSetting(); + // setState(State.CONNECTED); mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType()); startNetStatPoll(); @@ -1550,7 +1617,7 @@ private void updateDataActivity() { } else if (sent == 0 && received > 0) { newActivity = Activity.DATAIN; } else { - newActivity = Activity.NONE; + newActivity = (mActivity == Activity.DORMANT) ? mActivity : Activity.NONE; } if (mActivity != newActivity && mIsScreenOn) { @@ -1734,7 +1801,7 @@ private void startDataStallAlarm(boolean suspectedStall) { intent.putExtra(DATA_STALL_ALARM_TAG_EXTRA, mDataStallAlarmTag); mDataStallAlarmIntent = PendingIntent.getBroadcast(mPhone.getContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); - am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, + am.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + delayInMs, mDataStallAlarmIntent); } @@ -2398,13 +2465,37 @@ private ArrayList buildWaitingApns(String requestedApnType) { mPreferredApn = null; } } + + // If the currently active data connect can handle the requested type, try it first + if ((mActiveApn != null) && mActiveApn.canHandleType(requestedApnType)) { + if (DBG) log("buildWaitingApns: X added already active apnList=" + apnList); + apnList.add(mActiveApn); + } + if (mAllApns != null) { + // Use the preferred APN if it can handle the type being requested + if (canSetPreferApn && mPreferredApn != null) { + if (DBG) { + log("buildWaitingApns: Preferred APN:" + operator + ":" + + mPreferredApn.numeric + ":" + mPreferredApn); + } + if ((mPreferredApn.numeric.equals(operator) && mPreferredApn.canHandleType(requestedApnType)) && + (mPreferredApn.bearer == 0 || mPreferredApn.bearer == radioTech) && + !apnList.contains(mPreferredApn)) + { + apnList.add(mPreferredApn); + if (DBG) log("buildWaitingApns: X added preferred apnList=" + apnList); + } + } + + // Add all the rest of the apns that can handle the requested type for (ApnSetting apn : mAllApns) { - if (apn.canHandleType(requestedApnType)) { - if (apn.bearer == 0 || apn.bearer == radioTech) { - if (DBG) log("apn info : " +apn.toString()); - apnList.add(apn); - } + if ((apn.canHandleType(requestedApnType)) && + (apn.bearer == 0 || apn.bearer == radioTech) && + !apnList.contains(apn)) + { + if (DBG) log("apn info : " +apn.toString()); + apnList.add(apn); } } } else { @@ -2629,4 +2720,5 @@ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println(" mApnObserver=" + mApnObserver); pw.println(" getOverallState=" + getOverallState()); } + } diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java index b7569daa84c8f..983fa607fca67 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java @@ -863,9 +863,10 @@ private void pollStateDone() { mGotCountryCode = false; mNitzUpdatedTime = false; } else { + String mcc = "000"; String iso = ""; - String mcc = operatorNumeric.substring(0, 3); try{ + mcc = operatorNumeric.substring(0, 3); iso = MccTable.countryCodeForMcc(Integer.parseInt(mcc)); } catch ( NumberFormatException ex){ loge("pollStateDone: countryCodeForMcc error" + ex); diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java index da605841d4bb7..bef222da3940e 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java +++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java @@ -22,6 +22,7 @@ import com.android.internal.telephony.EncodeException; import com.android.internal.telephony.GsmAlphabet; +import com.android.internal.telephony.SimRegionCache; import com.android.internal.telephony.IccUtils; import com.android.internal.telephony.SmsHeader; import com.android.internal.telephony.SmsMessageBase; @@ -1043,6 +1044,10 @@ private void parseUserData(PduParser p, boolean hasUserDataHeader) { Log.w(LOG_TAG, "1 - Unsupported SMS data coding scheme " + (dataCodingScheme & 0xff)); encodingType = ENCODING_8BIT; + if (SimRegionCache.getRegion() == SimRegionCache.MCC_KOREAN) { + Log.w(LOG_TAG, "Korean SIM, using KSC5601 for decoding."); + encodingType = ENCODING_KSC5601; + } break; } } @@ -1101,6 +1106,10 @@ private void parseUserData(PduParser p, boolean hasUserDataHeader) { } else { Log.w(LOG_TAG, "3 - Unsupported SMS data coding scheme " + (dataCodingScheme & 0xff)); + if (SimRegionCache.getRegion() == SimRegionCache.MCC_KOREAN) { + Log.w(LOG_TAG, "Korean SIM, using KSC5601 for decoding."); + encodingType = ENCODING_KSC5601; + } } // set both the user data and the user data header. diff --git a/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java b/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java index 99f4e0f090531..af12985ef1ea9 100644 --- a/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java +++ b/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java @@ -421,4 +421,6 @@ public void requestIsimAuthentication(String nonce, Message response) { public void getVoiceRadioTechnology(Message result) { } + + public boolean needsOldRilFeature(String feature) { return false; } } diff --git a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java index 4f61509f918d8..49036161e8b0f 100644 --- a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java +++ b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java @@ -1522,4 +1522,6 @@ public void requestIsimAuthentication(String nonce, Message response) { public void getVoiceRadioTechnology(Message response) { unimplemented(response); } + + public boolean needsOldRilFeature(String feature) { return false; } } diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/AdnRecordTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/AdnRecordTest.java index 8a4a285212b1c..5511c09c0acf6 100644 --- a/telephony/tests/telephonytests/src/com/android/internal/telephony/AdnRecordTest.java +++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/AdnRecordTest.java @@ -170,6 +170,18 @@ public void testBasic() throws Exception { assertEquals("Adgjm", adn.getAlphaTag()); assertEquals("+18885551212,12345678", adn.getNumber()); assertFalse(adn.isEmpty()); + + // + // Test that a ADN record with KSC5601 will get converted correctly + // This test will only be run when using a Korean SIM + // + if (SimRegionCache.getRegion() == SimRegionCache.MCC_KOREAN) { + adn = new AdnRecord(IccUtils.hexStringToBytes( + "3030312C20C8AB41B1E6FFFFFFFFFFFF07811010325476F8FFFFFFFFFFFF")); + assertEquals("001, \uD64DA\uAE38", adn.getAlphaTag()); + assertEquals("01012345678", adn.getNumber()); + assertFalse(adn.isEmpty()); + } } } diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/SMSDispatcherTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/SMSDispatcherTest.java index 8a66614af0bdc..f578a8d85270c 100644 --- a/telephony/tests/telephonytests/src/com/android/internal/telephony/SMSDispatcherTest.java +++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/SMSDispatcherTest.java @@ -102,4 +102,25 @@ public void testEfRecord() throws Exception { sms = SmsMessage.createFromEfRecord(1, data); assertNotNull(sms.getMessageBody()); } + + @MediumTest + public void testEfRecordKorean() throws Exception { + if (SimRegionCache.getRegion() == SimRegionCache.MCC_KOREAN) { + SmsMessage sms; + + String s = "01089128010099010259040ba11000000000f00095013091900563008c4142" + + "434445b0a1b3aab4d9b6f3b8b631323334354142434445b0a1b3aab4d9b6f3" + + "b8b631323334354142434445b0a1b3aab4d9b6f3b8b6313233343541424344" + + "45b0a1b3aab4d9b6f3b8b63132333435000000000000000000000000000000" + + "00000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000ffffffffffffff"; + + + byte[] data = IccUtils.hexStringToBytes(s); + + sms = SmsMessage.createFromEfRecord(1, data); + assertNotNull(sms.getMessageBody()); + assertTrue(sms.getMessageBody().startsWith("ABCDE\uAC00\uB098\uB2E4\uB77C\uB9C812345ABCDE")); + } + } } diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/SimUtilsTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/SimUtilsTest.java index ef62d8538d2d8..2e76bd3279251 100644 --- a/telephony/tests/telephonytests/src/com/android/internal/telephony/SimUtilsTest.java +++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/SimUtilsTest.java @@ -86,6 +86,30 @@ public void testBasic() throws Exception { data = IccUtils.hexStringToBytes("820505302D82d32d31"); // Example from 3GPP TS 11.11 V18.1.3.0 annex B assertEquals("-\u0532\u0583-1", IccUtils.adnStringFieldToString(data, 0, data.length)); + + /* + * adnStringFieldToStringKsc5601Support() + * Tests equal the ones above, and will only be run if the SIM is NOT korean. + */ + + if (SimRegionCache.getRegion() != SimRegionCache.MCC_KOREAN) { + data = IccUtils.hexStringToBytes("00566f696365204d61696c07918150367742f3ffffffffffff"); + // Again, skip prepended 0 + // (this is an EF[ADN] record) + assertEquals("Voice Mail", IccUtils.adnStringFieldToStringKsc5601Support(data, 1, data.length - 15)); + + data = IccUtils.hexStringToBytes("809673539A5764002F004DFFFFFFFFFF"); + // (this is from an EF[ADN] record) + assertEquals("\u9673\u539A\u5764/M", IccUtils.adnStringFieldToStringKsc5601Support(data, 0, data.length)); + + data = IccUtils.hexStringToBytes("810A01566fec6365204de0696cFFFFFF"); + // (this is made up to test since I don't have a real one) + assertEquals("Vo\u00ECce M\u00E0il", IccUtils.adnStringFieldToStringKsc5601Support(data, 0, data.length)); + + data = IccUtils.hexStringToBytes("820505302D82d32d31"); + // Example from 3GPP TS 11.11 V18.1.3.0 annex B + assertEquals("-\u0532\u0583-1", IccUtils.adnStringFieldToStringKsc5601Support(data, 0, data.length)); + } } } diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadCommands.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadCommands.java index ea6836decbca6..3c8e614f938c7 100644 --- a/telephony/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadCommands.java +++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadCommands.java @@ -621,4 +621,7 @@ public void getIMSIForApp(String aid, Message result) { public void iccIOForApp(int command, int fileid, String path, int p1, int p2, int p3, String data, String pin2, String aid, Message response) { } + + @Override + public boolean needsOldRilFeature(String feature) { return false; } }