/*
* 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);
mQANElements = 5;
}
@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
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);
}
}
}