blob: 8e886bb9fec063a6dd59eea3496e28ea30de1e8f [file] [log] [blame]
/*
* Copyright (C) 2006 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.test;
import android.os.AsyncResult;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.telephony.Rlog;
import com.android.internal.telephony.BaseCommands;
import com.android.internal.telephony.CommandException;
import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.cdma.CdmaSmsBroadcastConfigInfo;
import com.android.internal.telephony.dataconnection.DataCallResponse;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.UUSInfo;
import com.android.internal.telephony.gsm.CallFailCause;
import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo;
import com.android.internal.telephony.gsm.SuppServiceNotification;
import java.util.ArrayList;
public final class SimulatedCommands extends BaseCommands
implements CommandsInterface, SimulatedRadioControl {
private final static String LOG_TAG = "SimulatedCommands";
private enum SimLockState {
NONE,
REQUIRE_PIN,
REQUIRE_PUK,
SIM_PERM_LOCKED
}
private enum SimFdnState {
NONE,
REQUIRE_PIN2,
REQUIRE_PUK2,
SIM_PERM_LOCKED
}
private final static SimLockState INITIAL_LOCK_STATE = SimLockState.NONE;
private final static String DEFAULT_SIM_PIN_CODE = "1234";
private final static String SIM_PUK_CODE = "12345678";
private final static SimFdnState INITIAL_FDN_STATE = SimFdnState.NONE;
private final static String DEFAULT_SIM_PIN2_CODE = "5678";
private final static String SIM_PUK2_CODE = "87654321";
//***** Instance Variables
SimulatedGsmCallState simulatedCallState;
HandlerThread mHandlerThread;
SimLockState mSimLockedState;
boolean mSimLockEnabled;
int mPinUnlockAttempts;
int mPukUnlockAttempts;
String mPinCode;
SimFdnState mSimFdnEnabledState;
boolean mSimFdnEnabled;
int mPin2UnlockAttempts;
int mPuk2UnlockAttempts;
int mNetworkType;
String mPin2Code;
boolean mSsnNotifyOn = false;
int mPausedResponseCount;
ArrayList<Message> mPausedResponses = new ArrayList<Message>();
int mNextCallFailCause = CallFailCause.NORMAL_CLEARING;
//***** Constructor
public
SimulatedCommands() {
super(null); // Don't log statistics
mHandlerThread = new HandlerThread("SimulatedCommands");
mHandlerThread.start();
Looper looper = mHandlerThread.getLooper();
simulatedCallState = new SimulatedGsmCallState(looper);
setRadioState(RadioState.RADIO_OFF);
mSimLockedState = INITIAL_LOCK_STATE;
mSimLockEnabled = (mSimLockedState != SimLockState.NONE);
mPinCode = DEFAULT_SIM_PIN_CODE;
mSimFdnEnabledState = INITIAL_FDN_STATE;
mSimFdnEnabled = (mSimFdnEnabledState != SimFdnState.NONE);
mPin2Code = DEFAULT_SIM_PIN2_CODE;
}
//***** CommandsInterface implementation
@Override
public void getIccCardStatus(Message result) {
unimplemented(result);
}
@Override
public void supplyIccPin(String pin, Message result) {
if (mSimLockedState != SimLockState.REQUIRE_PIN) {
Rlog.i(LOG_TAG, "[SimCmd] supplyIccPin: wrong state, state=" +
mSimLockedState);
CommandException ex = new CommandException(
CommandException.Error.PASSWORD_INCORRECT);
AsyncResult.forMessage(result, null, ex);
result.sendToTarget();
return;
}
if (pin != null && pin.equals(mPinCode)) {
Rlog.i(LOG_TAG, "[SimCmd] supplyIccPin: success!");
mPinUnlockAttempts = 0;
mSimLockedState = SimLockState.NONE;
mIccStatusChangedRegistrants.notifyRegistrants();
if (result != null) {
AsyncResult.forMessage(result, null, null);
result.sendToTarget();
}
return;
}
if (result != null) {
mPinUnlockAttempts ++;
Rlog.i(LOG_TAG, "[SimCmd] supplyIccPin: failed! attempt=" +
mPinUnlockAttempts);
if (mPinUnlockAttempts >= 3) {
Rlog.i(LOG_TAG, "[SimCmd] supplyIccPin: set state to REQUIRE_PUK");
mSimLockedState = SimLockState.REQUIRE_PUK;
}
CommandException ex = new CommandException(
CommandException.Error.PASSWORD_INCORRECT);
AsyncResult.forMessage(result, null, ex);
result.sendToTarget();
}
}
@Override
public void supplyIccPuk(String puk, String newPin, Message result) {
if (mSimLockedState != SimLockState.REQUIRE_PUK) {
Rlog.i(LOG_TAG, "[SimCmd] supplyIccPuk: wrong state, state=" +
mSimLockedState);
CommandException ex = new CommandException(
CommandException.Error.PASSWORD_INCORRECT);
AsyncResult.forMessage(result, null, ex);
result.sendToTarget();
return;
}
if (puk != null && puk.equals(SIM_PUK_CODE)) {
Rlog.i(LOG_TAG, "[SimCmd] supplyIccPuk: success!");
mSimLockedState = SimLockState.NONE;
mPukUnlockAttempts = 0;
mIccStatusChangedRegistrants.notifyRegistrants();
if (result != null) {
AsyncResult.forMessage(result, null, null);
result.sendToTarget();
}
return;
}
if (result != null) {
mPukUnlockAttempts ++;
Rlog.i(LOG_TAG, "[SimCmd] supplyIccPuk: failed! attempt=" +
mPukUnlockAttempts);
if (mPukUnlockAttempts >= 10) {
Rlog.i(LOG_TAG, "[SimCmd] supplyIccPuk: set state to SIM_PERM_LOCKED");
mSimLockedState = SimLockState.SIM_PERM_LOCKED;
}
CommandException ex = new CommandException(
CommandException.Error.PASSWORD_INCORRECT);
AsyncResult.forMessage(result, null, ex);
result.sendToTarget();
}
}
@Override
public void supplyIccPin2(String pin2, Message result) {
if (mSimFdnEnabledState != SimFdnState.REQUIRE_PIN2) {
Rlog.i(LOG_TAG, "[SimCmd] supplyIccPin2: wrong state, state=" +
mSimFdnEnabledState);
CommandException ex = new CommandException(
CommandException.Error.PASSWORD_INCORRECT);
AsyncResult.forMessage(result, null, ex);
result.sendToTarget();
return;
}
if (pin2 != null && pin2.equals(mPin2Code)) {
Rlog.i(LOG_TAG, "[SimCmd] supplyIccPin2: success!");
mPin2UnlockAttempts = 0;
mSimFdnEnabledState = SimFdnState.NONE;
if (result != null) {
AsyncResult.forMessage(result, null, null);
result.sendToTarget();
}
return;
}
if (result != null) {
mPin2UnlockAttempts ++;
Rlog.i(LOG_TAG, "[SimCmd] supplyIccPin2: failed! attempt=" +
mPin2UnlockAttempts);
if (mPin2UnlockAttempts >= 3) {
Rlog.i(LOG_TAG, "[SimCmd] supplyIccPin2: set state to REQUIRE_PUK2");
mSimFdnEnabledState = SimFdnState.REQUIRE_PUK2;
}
CommandException ex = new CommandException(
CommandException.Error.PASSWORD_INCORRECT);
AsyncResult.forMessage(result, null, ex);
result.sendToTarget();
}
}
@Override
public void supplyIccPuk2(String puk2, String newPin2, Message result) {
if (mSimFdnEnabledState != SimFdnState.REQUIRE_PUK2) {
Rlog.i(LOG_TAG, "[SimCmd] supplyIccPuk2: wrong state, state=" +
mSimLockedState);
CommandException ex = new CommandException(
CommandException.Error.PASSWORD_INCORRECT);
AsyncResult.forMessage(result, null, ex);
result.sendToTarget();
return;
}
if (puk2 != null && puk2.equals(SIM_PUK2_CODE)) {
Rlog.i(LOG_TAG, "[SimCmd] supplyIccPuk2: success!");
mSimFdnEnabledState = SimFdnState.NONE;
mPuk2UnlockAttempts = 0;
if (result != null) {
AsyncResult.forMessage(result, null, null);
result.sendToTarget();
}
return;
}
if (result != null) {
mPuk2UnlockAttempts ++;
Rlog.i(LOG_TAG, "[SimCmd] supplyIccPuk2: failed! attempt=" +
mPuk2UnlockAttempts);
if (mPuk2UnlockAttempts >= 10) {
Rlog.i(LOG_TAG, "[SimCmd] supplyIccPuk2: set state to SIM_PERM_LOCKED");
mSimFdnEnabledState = SimFdnState.SIM_PERM_LOCKED;
}
CommandException ex = new CommandException(
CommandException.Error.PASSWORD_INCORRECT);
AsyncResult.forMessage(result, null, ex);
result.sendToTarget();
}
}
@Override
public void changeIccPin(String oldPin, String newPin, Message result) {
if (oldPin != null && oldPin.equals(mPinCode)) {
mPinCode = newPin;
if (result != null) {
AsyncResult.forMessage(result, null, null);
result.sendToTarget();
}
return;
}
if (result != null) {
Rlog.i(LOG_TAG, "[SimCmd] changeIccPin: pin failed!");
CommandException ex = new CommandException(
CommandException.Error.PASSWORD_INCORRECT);
AsyncResult.forMessage(result, null, ex);
result.sendToTarget();
}
}
@Override
public void changeIccPin2(String oldPin2, String newPin2, Message result) {
if (oldPin2 != null && oldPin2.equals(mPin2Code)) {
mPin2Code = newPin2;
if (result != null) {
AsyncResult.forMessage(result, null, null);
result.sendToTarget();
}
return;
}
if (result != null) {
Rlog.i(LOG_TAG, "[SimCmd] changeIccPin2: pin2 failed!");
CommandException ex = new CommandException(
CommandException.Error.PASSWORD_INCORRECT);
AsyncResult.forMessage(result, null, ex);
result.sendToTarget();
}
}
@Override
public void
changeBarringPassword(String facility, String oldPwd, String newPwd, Message result) {
unimplemented(result);
}
@Override
public void
setSuppServiceNotifications(boolean enable, Message result) {
resultSuccess(result, null);
if (enable && mSsnNotifyOn) {
Rlog.w(LOG_TAG, "Supp Service Notifications already enabled!");
}
mSsnNotifyOn = enable;
}
@Override
public void queryFacilityLock(String facility, String pin,
int serviceClass, Message result) {
queryFacilityLockForApp(facility, pin, serviceClass, null, result);
}
@Override
public void queryFacilityLockForApp(String facility, String pin, int serviceClass,
String appId, Message result) {
if (facility != null && facility.equals(CommandsInterface.CB_FACILITY_BA_SIM)) {
if (result != null) {
int[] r = new int[1];
r[0] = (mSimLockEnabled ? 1 : 0);
Rlog.i(LOG_TAG, "[SimCmd] queryFacilityLock: SIM is "
+ (r[0] == 0 ? "unlocked" : "locked"));
AsyncResult.forMessage(result, r, null);
result.sendToTarget();
}
return;
} else if (facility != null && facility.equals(CommandsInterface.CB_FACILITY_BA_FD)) {
if (result != null) {
int[] r = new int[1];
r[0] = (mSimFdnEnabled ? 1 : 0);
Rlog.i(LOG_TAG, "[SimCmd] queryFacilityLock: FDN is "
+ (r[0] == 0 ? "disabled" : "enabled"));
AsyncResult.forMessage(result, r, null);
result.sendToTarget();
}
return;
}
unimplemented(result);
}
@Override
public void setFacilityLock(String facility, boolean lockEnabled, String pin, int serviceClass,
Message result) {
setFacilityLockForApp(facility, lockEnabled, pin, serviceClass, null, result);
}
@Override
public void setFacilityLockForApp(String facility, boolean lockEnabled,
String pin, int serviceClass, String appId,
Message result) {
if (facility != null &&
facility.equals(CommandsInterface.CB_FACILITY_BA_SIM)) {
if (pin != null && pin.equals(mPinCode)) {
Rlog.i(LOG_TAG, "[SimCmd] setFacilityLock: pin is valid");
mSimLockEnabled = lockEnabled;
if (result != null) {
AsyncResult.forMessage(result, null, null);
result.sendToTarget();
}
return;
}
if (result != null) {
Rlog.i(LOG_TAG, "[SimCmd] setFacilityLock: pin failed!");
CommandException ex = new CommandException(
CommandException.Error.GENERIC_FAILURE);
AsyncResult.forMessage(result, null, ex);
result.sendToTarget();
}
return;
} else if (facility != null &&
facility.equals(CommandsInterface.CB_FACILITY_BA_FD)) {
if (pin != null && pin.equals(mPin2Code)) {
Rlog.i(LOG_TAG, "[SimCmd] setFacilityLock: pin2 is valid");
mSimFdnEnabled = lockEnabled;
if (result != null) {
AsyncResult.forMessage(result, null, null);
result.sendToTarget();
}
return;
}
if (result != null) {
Rlog.i(LOG_TAG, "[SimCmd] setFacilityLock: pin2 failed!");
CommandException ex = new CommandException(
CommandException.Error.GENERIC_FAILURE);
AsyncResult.forMessage(result, null, ex);
result.sendToTarget();
}
return;
}
unimplemented(result);
}
@Override
public void supplyNetworkDepersonalization(String netpin, Message result) {
unimplemented(result);
}
/**
* returned message
* retMsg.obj = AsyncResult ar
* ar.exception carries exception on failure
* ar.userObject contains the original value of result.obj
* ar.result contains a List of DriverCall
* The ar.result List is sorted by DriverCall.index
*/
@Override
public void getCurrentCalls (Message result) {
if ((mState == RadioState.RADIO_ON) && !isSimLocked()) {
//Rlog.i("GSM", "[SimCmds] getCurrentCalls");
resultSuccess(result, simulatedCallState.getDriverCalls());
} else {
//Rlog.i("GSM", "[SimCmds] getCurrentCalls: RADIO_OFF or SIM not ready!");
resultFail(result,
new CommandException(
CommandException.Error.RADIO_NOT_AVAILABLE));
}
}
/**
* @deprecated
*/
@Deprecated
@Override
public void getPDPContextList(Message result) {
getDataCallList(result);
}
/**
* returned message
* retMsg.obj = AsyncResult ar
* ar.exception carries exception on failure
* ar.userObject contains the original value of result.obj
* ar.result contains a List of DataCallResponse
*/
@Override
public void getDataCallList(Message result) {
resultSuccess(result, new ArrayList<DataCallResponse>(0));
}
/**
* returned message
* retMsg.obj = AsyncResult ar
* ar.exception carries exception on failure
* ar.userObject contains the original value of result.obj
* ar.result is null on success and failure
*
* CLIR_DEFAULT == on "use subscription default value"
* CLIR_SUPPRESSION == on "CLIR suppression" (allow CLI presentation)
* CLIR_INVOCATION == on "CLIR invocation" (restrict CLI presentation)
*/
@Override
public void dial (String address, int clirMode, Message result) {
simulatedCallState.onDial(address);
resultSuccess(result, null);
}
/**
* returned message
* retMsg.obj = AsyncResult ar
* ar.exception carries exception on failure
* ar.userObject contains the original value of result.obj
* ar.result is null on success and failure
*
* CLIR_DEFAULT == on "use subscription default value"
* CLIR_SUPPRESSION == on "CLIR suppression" (allow CLI presentation)
* CLIR_INVOCATION == on "CLIR invocation" (restrict CLI presentation)
*/
@Override
public void dial(String address, int clirMode, UUSInfo uusInfo, Message result) {
simulatedCallState.onDial(address);
resultSuccess(result, null);
}
@Override
public void getIMSI(Message result) {
getIMSIForApp(null, result);
}
/**
* returned message
* retMsg.obj = AsyncResult ar
* ar.exception carries exception on failure
* ar.userObject contains the original value of result.obj
* ar.result is String containing IMSI on success
*/
@Override
public void getIMSIForApp(String aid, Message result) {
resultSuccess(result, "012345678901234");
}
/**
* returned message
* retMsg.obj = AsyncResult ar
* ar.exception carries exception on failure
* ar.userObject contains the original value of result.obj
* ar.result is String containing IMEI on success
*/
@Override
public void getIMEI(Message result) {
resultSuccess(result, "012345678901234");
}
/**
* returned message
* retMsg.obj = AsyncResult ar
* ar.exception carries exception on failure
* ar.userObject contains the original value of result.obj
* ar.result is String containing IMEISV on success
*/
@Override
public void getIMEISV(Message result) {
resultSuccess(result, "99");
}
/**
* Hang up one individual connection.
* returned message
* retMsg.obj = AsyncResult ar
* ar.exception carries exception on failure
* ar.userObject contains the original value of result.obj
* ar.result is null on success and failure
*
* 3GPP 22.030 6.5.5
* "Releases a specific active call X"
*/
@Override
public void hangupConnection (int gsmIndex, Message result) {
boolean success;
success = simulatedCallState.onChld('1', (char)('0'+gsmIndex));
if (!success){
Rlog.i("GSM", "[SimCmd] hangupConnection: resultFail");
resultFail(result, new RuntimeException("Hangup Error"));
} else {
Rlog.i("GSM", "[SimCmd] hangupConnection: resultSuccess");
resultSuccess(result, null);
}
}
/**
* 3GPP 22.030 6.5.5
* "Releases all held calls or sets User Determined User Busy (UDUB)
* for a waiting call."
* ar.exception carries exception on failure
* ar.userObject contains the original value of result.obj
* ar.result is null on success and failure
*/
@Override
public void hangupWaitingOrBackground (Message result) {
boolean success;
success = simulatedCallState.onChld('0', '\0');
if (!success){
resultFail(result, new RuntimeException("Hangup Error"));
} else {
resultSuccess(result, null);
}
}
/**
* 3GPP 22.030 6.5.5
* "Releases all active calls (if any exist) and accepts
* the other (held or waiting) call."
*
* ar.exception carries exception on failure
* ar.userObject contains the original value of result.obj
* ar.result is null on success and failure
*/
@Override
public void hangupForegroundResumeBackground (Message result) {
boolean success;
success = simulatedCallState.onChld('1', '\0');
if (!success){
resultFail(result, new RuntimeException("Hangup Error"));
} else {
resultSuccess(result, null);
}
}
/**
* 3GPP 22.030 6.5.5
* "Places all active calls (if any exist) on hold and accepts
* the other (held or waiting) call."
*
* ar.exception carries exception on failure
* ar.userObject contains the original value of result.obj
* ar.result is null on success and failure
*/
@Override
public void switchWaitingOrHoldingAndActive (Message result) {
boolean success;
success = simulatedCallState.onChld('2', '\0');
if (!success){
resultFail(result, new RuntimeException("Hangup Error"));
} else {
resultSuccess(result, null);
}
}
/**
* 3GPP 22.030 6.5.5
* "Adds a held call to the conversation"
*
* ar.exception carries exception on failure
* ar.userObject contains the original value of result.obj
* ar.result is null on success and failure
*/
@Override
public void conference (Message result) {
boolean success;
success = simulatedCallState.onChld('3', '\0');
if (!success){
resultFail(result, new RuntimeException("Hangup Error"));
} else {
resultSuccess(result, null);
}
}
/**
* 3GPP 22.030 6.5.5
* "Connects the two calls and disconnects the subscriber from both calls"
*
* ar.exception carries exception on failure
* ar.userObject contains the original value of result.obj
* ar.result is null on success and failure
*/
@Override
public void explicitCallTransfer (Message result) {
boolean success;
success = simulatedCallState.onChld('4', '\0');
if (!success){
resultFail(result, new RuntimeException("Hangup Error"));
} else {
resultSuccess(result, null);
}
}
/**
* 3GPP 22.030 6.5.5
* "Places all active calls on hold except call X with which
* communication shall be supported."
*/
@Override
public void separateConnection (int gsmIndex, Message result) {
boolean success;
char ch = (char)(gsmIndex + '0');
success = simulatedCallState.onChld('2', ch);
if (!success){
resultFail(result, new RuntimeException("Hangup Error"));
} else {
resultSuccess(result, null);
}
}
/**
*
* ar.exception carries exception on failure
* ar.userObject contains the original value of result.obj
* ar.result is null on success and failure
*/
@Override
public void acceptCall (Message result) {
boolean success;
success = simulatedCallState.onAnswer();
if (!success){
resultFail(result, new RuntimeException("Hangup Error"));
} else {
resultSuccess(result, null);
}
}
/**
* also known as UDUB
* ar.exception carries exception on failure
* ar.userObject contains the original value of result.obj
* ar.result is null on success and failure
*/
@Override
public void rejectCall (Message result) {
boolean success;
success = simulatedCallState.onChld('0', '\0');
if (!success){
resultFail(result, new RuntimeException("Hangup Error"));
} else {
resultSuccess(result, null);
}
}
/**
* cause code returned as Integer in Message.obj.response
* Returns integer cause code defined in TS 24.008
* Annex H or closest approximation.
* Most significant codes:
* - Any defined in 22.001 F.4 (for generating busy/congestion)
* - Cause 68: ACM >= ACMMax
*/
@Override
public void getLastCallFailCause (Message result) {
int[] ret = new int[1];
ret[0] = mNextCallFailCause;
resultSuccess(result, ret);
}
/**
* @deprecated
*/
@Deprecated
@Override
public void getLastPdpFailCause (Message result) {
unimplemented(result);
}
@Override
public void getLastDataCallFailCause(Message result) {
//
unimplemented(result);
}
@Override
public void setMute (boolean enableMute, Message result) {unimplemented(result);}
@Override
public void getMute (Message result) {unimplemented(result);}
/**
* response.obj is an AsyncResult
* response.obj.result is an int[2]
* response.obj.result[0] is received signal strength (0-31, 99)
* response.obj.result[1] is bit error rate (0-7, 99)
* as defined in TS 27.007 8.5
*/
@Override
public void getSignalStrength (Message result) {
int ret[] = new int[2];
ret[0] = 23;
ret[1] = 0;
resultSuccess(result, ret);
}
/**
* Assign a specified band for RF configuration.
*
* @param bandMode one of BM_*_BAND
* @param result is callback message
*/
@Override
public void setBandMode (int bandMode, Message result) {
resultSuccess(result, null);
}
/**
* Query the list of band mode supported by RF.
*
* @param result is callback message
* ((AsyncResult)response.obj).result is an int[] with every
* element representing one available BM_*_BAND
*/
@Override
public void queryAvailableBandMode (Message result) {
int ret[] = new int [4];
ret[0] = 4;
ret[1] = Phone.BM_US_BAND;
ret[2] = Phone.BM_JPN_BAND;
ret[3] = Phone.BM_AUS_BAND;
resultSuccess(result, ret);
}
/**
* {@inheritDoc}
*/
@Override
public void sendTerminalResponse(String contents, Message response) {
resultSuccess(response, null);
}
/**
* {@inheritDoc}
*/
@Override
public void sendEnvelope(String contents, Message response) {
resultSuccess(response, null);
}
/**
* {@inheritDoc}
*/
@Override
public void sendEnvelopeWithStatus(String contents, Message response) {
resultSuccess(response, null);
}
/**
* {@inheritDoc}
*/
@Override
public void handleCallSetupRequestFromSim(
boolean accept, Message response) {
resultSuccess(response, null);
}
/**
* response.obj.result is an String[14]
* See ril.h for details
*
* Please note that registration state 4 ("unknown") is treated
* as "out of service" above
*/
@Override
public void getVoiceRegistrationState (Message result) {
String ret[] = new String[14];
ret[0] = "5"; // registered roam
ret[1] = null;
ret[2] = null;
ret[3] = null;
ret[4] = null;
ret[5] = null;
ret[6] = null;
ret[7] = null;
ret[8] = null;
ret[9] = null;
ret[10] = null;
ret[11] = null;
ret[12] = null;
ret[13] = null;
resultSuccess(result, ret);
}
/**
* response.obj.result is an String[4]
* response.obj.result[0] is registration state 0-5 from TS 27.007 7.2
* response.obj.result[1] is LAC if registered or NULL if not
* response.obj.result[2] is CID if registered or NULL if not
* response.obj.result[3] indicates the available radio technology, where:
* 0 == unknown
* 1 == GPRS only
* 2 == EDGE
* 3 == UMTS
*
* valid LAC are 0x0000 - 0xffff
* valid CID are 0x00000000 - 0xffffffff
*
* Please note that registration state 4 ("unknown") is treated
* as "out of service" in the Android telephony system
*/
@Override
public void getDataRegistrationState (Message result) {
String ret[] = new String[4];
ret[0] = "5"; // registered roam
ret[1] = null;
ret[2] = null;
ret[3] = "2";
resultSuccess(result, ret);
}
/**
* response.obj.result is a String[3]
* response.obj.result[0] is long alpha or null if unregistered
* response.obj.result[1] is short alpha or null if unregistered
* response.obj.result[2] is numeric or null if unregistered
*/
@Override
public void getOperator(Message result) {
String[] ret = new String[3];
ret[0] = "El Telco Loco";
ret[1] = "Telco Loco";
ret[2] = "001001";
resultSuccess(result, ret);
}
/**
* ar.exception carries exception on failure
* ar.userObject contains the original value of result.obj
* ar.result is null on success and failure
*/
@Override
public void sendDtmf(char c, Message result) {
resultSuccess(result, null);
}
/**
* ar.exception carries exception on failure
* ar.userObject contains the original value of result.obj
* ar.result is null on success and failure
*/
@Override
public void startDtmf(char c, Message result) {
resultSuccess(result, null);
}
/**
* ar.exception carries exception on failure
* ar.userObject contains the original value of result.obj
* ar.result is null on success and failure
*/
@Override
public void stopDtmf(Message result) {
resultSuccess(result, null);
}
/**
* ar.exception carries exception on failure
* ar.userObject contains the original value of result.obj
* ar.result is null on success and failure
*/
@Override
public void sendBurstDtmf(String dtmfString, int on, int off, Message result) {
resultSuccess(result, null);
}
/**
* smscPDU is smsc address in PDU form GSM BCD format prefixed
* by a length byte (as expected by TS 27.005) or NULL for default SMSC
* pdu is SMS in PDU format as an ASCII hex string
* less the SMSC address
*/
@Override
public void sendSMS (String smscPDU, String pdu, Message result) {unimplemented(result);}
@Override
public void deleteSmsOnSim(int index, Message response) {
Rlog.d(LOG_TAG, "Delete message at index " + index);
unimplemented(response);
}
@Override
public void deleteSmsOnRuim(int index, Message response) {
Rlog.d(LOG_TAG, "Delete RUIM message at index " + index);
unimplemented(response);
}
@Override
public void writeSmsToSim(int status, String smsc, String pdu, Message response) {
Rlog.d(LOG_TAG, "Write SMS to SIM with status " + status);
unimplemented(response);
}
@Override
public void writeSmsToRuim(int status, String pdu, Message response) {
Rlog.d(LOG_TAG, "Write SMS to RUIM with status " + status);
unimplemented(response);
}
@Override
public void setupDataCall(String radioTechnology, String profile,
String apn, String user, String password, String authType,
String protocol, Message result) {
unimplemented(result);
}
@Override
public void deactivateDataCall(int cid, int reason, Message result) {unimplemented(result);}
@Override
public void setPreferredNetworkType(int networkType , Message result) {
mNetworkType = networkType;
resultSuccess(result, null);
}
@Override
public void getPreferredNetworkType(Message result) {
int ret[] = new int[1];
ret[0] = mNetworkType;
resultSuccess(result, ret);
}
@Override
public void getNeighboringCids(Message result) {
int ret[] = new int[7];
ret[0] = 6;
for (int i = 1; i<7; i++) {
ret[i] = i;
}
resultSuccess(result, ret);
}
@Override
public void setLocationUpdates(boolean enable, Message response) {
unimplemented(response);
}
@Override
public void getSmscAddress(Message result) {
unimplemented(result);
}
@Override
public void setSmscAddress(String address, Message result) {
unimplemented(result);
}
@Override
public void reportSmsMemoryStatus(boolean available, Message result) {
unimplemented(result);
}
@Override
public void reportStkServiceIsRunning(Message result) {
resultSuccess(result, null);
}
@Override
public void getCdmaSubscriptionSource(Message result) {
unimplemented(result);
}
private boolean isSimLocked() {
if (mSimLockedState != SimLockState.NONE) {
return true;
}
return false;
}
@Override
public void setRadioPower(boolean on, Message result) {
if(on) {
setRadioState(RadioState.RADIO_ON);
} else {
setRadioState(RadioState.RADIO_OFF);
}
}
@Override
public void acknowledgeLastIncomingGsmSms(boolean success, int cause, Message result) {
unimplemented(result);
}
@Override
public void acknowledgeLastIncomingCdmaSms(boolean success, int cause, Message result) {
unimplemented(result);
}
@Override
public void acknowledgeIncomingGsmSmsWithPdu(boolean success, String ackPdu,
Message result) {
unimplemented(result);
}
@Override
public void iccIO(int command, int fileid, String path, int p1, int p2, int p3, String data,
String pin2, Message response) {
iccIOForApp(command, fileid, path, p1, p2, p3, data,pin2, null, response);
}
/**
* parameters equivalent to 27.007 AT+CRSM command
* response.obj will be an AsyncResult
* response.obj.userObj will be a SimIoResult on success
*/
@Override
public void iccIOForApp (int command, int fileid, String path, int p1, int p2,
int p3, String data, String pin2, String aid, Message result) {
unimplemented(result);
}
/**
* (AsyncResult)response.obj).result is an int[] with element [0] set to
* 1 for "CLIP is provisioned", and 0 for "CLIP is not provisioned".
*
* @param response is callback message
*/
@Override
public void queryCLIP(Message response) { unimplemented(response); }
/**
* response.obj will be a an int[2]
*
* response.obj[0] will be TS 27.007 +CLIR parameter 'n'
* 0 presentation indicator is used according to the subscription of the CLIR service
* 1 CLIR invocation
* 2 CLIR suppression
*
* response.obj[1] will be TS 27.007 +CLIR parameter 'm'
* 0 CLIR not provisioned
* 1 CLIR provisioned in permanent mode
* 2 unknown (e.g. no network, etc.)
* 3 CLIR temporary mode presentation restricted
* 4 CLIR temporary mode presentation allowed
*/
@Override
public void getCLIR(Message result) {unimplemented(result);}
/**
* clirMode is one of the CLIR_* constants above
*
* response.obj is null
*/
@Override
public void setCLIR(int clirMode, Message result) {unimplemented(result);}
/**
* (AsyncResult)response.obj).result is an int[] with element [0] set to
* 0 for disabled, 1 for enabled.
*
* @param serviceClass is a sum of SERVICE_CLASS_*
* @param response is callback message
*/
@Override
public void queryCallWaiting(int serviceClass, Message response) {
unimplemented(response);
}
/**
* @param enable is true to enable, false to disable
* @param serviceClass is a sum of SERVICE_CLASS_*
* @param response is callback message
*/
@Override
public void setCallWaiting(boolean enable, int serviceClass,
Message response) {
unimplemented(response);
}
/**
* @param action is one of CF_ACTION_*
* @param cfReason is one of CF_REASON_*
* @param serviceClass is a sum of SERVICE_CLASSS_*
*/
@Override
public void setCallForward(int action, int cfReason, int serviceClass,
String number, int timeSeconds, Message result) {unimplemented(result);}
/**
* cfReason is one of CF_REASON_*
*
* ((AsyncResult)response.obj).result will be an array of
* CallForwardInfo's
*
* An array of length 0 means "disabled for all codes"
*/
@Override
public void queryCallForwardStatus(int cfReason, int serviceClass,
String number, Message result) {unimplemented(result);}
@Override
public void setNetworkSelectionModeAutomatic(Message result) {unimplemented(result);}
@Override
public void exitEmergencyCallbackMode(Message result) {unimplemented(result);}
@Override
public void setNetworkSelectionModeManual(
String operatorNumeric, Message result) {unimplemented(result);}
/**
* Queries whether the current network selection mode is automatic
* or manual
*
* ((AsyncResult)response.obj).result is an int[] with element [0] being
* a 0 for automatic selection and a 1 for manual selection
*/
@Override
public void getNetworkSelectionMode(Message result) {
int ret[] = new int[1];
ret[0] = 0;
resultSuccess(result, ret);
}
/**
* Queries the currently available networks
*
* ((AsyncResult)response.obj).result is a List of NetworkInfo objects
*/
@Override
public void getAvailableNetworks(Message result) {unimplemented(result);}
@Override
public void getBasebandVersion (Message result) {
resultSuccess(result, "SimulatedCommands");
}
/**
* Simulates an incoming USSD message
* @param statusCode Status code string. See <code>setOnUSSD</code>
* in CommandsInterface.java
* @param message Message text to send or null if none
*/
@Override
public void triggerIncomingUssd(String statusCode, String message) {
if (mUSSDRegistrant != null) {
String[] result = {statusCode, message};
mUSSDRegistrant.notifyResult(result);
}
}
@Override
public void sendUSSD (String ussdString, Message result) {
// We simulate this particular sequence
if (ussdString.equals("#646#")) {
resultSuccess(result, null);
// 0 == USSD-Notify
triggerIncomingUssd("0", "You have NNN minutes remaining.");
} else {
resultSuccess(result, null);
triggerIncomingUssd("0", "All Done");
}
}
// inherited javadoc suffices
@Override
public void cancelPendingUssd (Message response) {
resultSuccess(response, null);
}
@Override
public void resetRadio(Message result) {
unimplemented(result);
}
@Override
public void invokeOemRilRequestRaw(byte[] data, Message response) {
// Just echo back data
if (response != null) {
AsyncResult.forMessage(response).result = data;
response.sendToTarget();
}
}
@Override
public void invokeOemRilRequestStrings(String[] strings, Message response) {
// Just echo back data
if (response != null) {
AsyncResult.forMessage(response).result = strings;
response.sendToTarget();
}
}
//***** SimulatedRadioControl
/** Start the simulated phone ringing */
@Override
public void
triggerRing(String number) {
simulatedCallState.triggerRing(number);
mCallStateRegistrants.notifyRegistrants();
}
@Override
public void
progressConnectingCallState() {
simulatedCallState.progressConnectingCallState();
mCallStateRegistrants.notifyRegistrants();
}
/** If a call is DIALING or ALERTING, progress it all the way to ACTIVE */
@Override
public void
progressConnectingToActive() {
simulatedCallState.progressConnectingToActive();
mCallStateRegistrants.notifyRegistrants();
}
/** automatically progress mobile originated calls to ACTIVE.
* default to true
*/
@Override
public void
setAutoProgressConnectingCall(boolean b) {
simulatedCallState.setAutoProgressConnectingCall(b);
}
@Override
public void
setNextDialFailImmediately(boolean b) {
simulatedCallState.setNextDialFailImmediately(b);
}
@Override
public void
setNextCallFailCause(int gsmCause) {
mNextCallFailCause = gsmCause;
}
@Override
public void
triggerHangupForeground() {
simulatedCallState.triggerHangupForeground();
mCallStateRegistrants.notifyRegistrants();
}
/** hangup holding calls */
@Override
public void
triggerHangupBackground() {
simulatedCallState.triggerHangupBackground();
mCallStateRegistrants.notifyRegistrants();
}
@Override
public void triggerSsn(int type, int code) {
SuppServiceNotification not = new SuppServiceNotification();
not.notificationType = type;
not.code = code;
mSsnRegistrant.notifyRegistrant(new AsyncResult(null, not, null));
}
@Override
public void
shutdown() {
setRadioState(RadioState.RADIO_UNAVAILABLE);
Looper looper = mHandlerThread.getLooper();
if (looper != null) {
looper.quit();
}
}
/** hangup all */
@Override
public void
triggerHangupAll() {
simulatedCallState.triggerHangupAll();
mCallStateRegistrants.notifyRegistrants();
}
@Override
public void
triggerIncomingSMS(String message) {
//TODO
}
@Override
public void
pauseResponses() {
mPausedResponseCount++;
}
@Override
public void
resumeResponses() {
mPausedResponseCount--;
if (mPausedResponseCount == 0) {
for (int i = 0, s = mPausedResponses.size(); i < s ; i++) {
mPausedResponses.get(i).sendToTarget();
}
mPausedResponses.clear();
} else {
Rlog.e("GSM", "SimulatedCommands.resumeResponses < 0");
}
}
//***** Private Methods
private void unimplemented(Message result) {
if (result != null) {
AsyncResult.forMessage(result).exception
= new RuntimeException("Unimplemented");
if (mPausedResponseCount > 0) {
mPausedResponses.add(result);
} else {
result.sendToTarget();
}
}
}
private void resultSuccess(Message result, Object ret) {
if (result != null) {
AsyncResult.forMessage(result).result = ret;
if (mPausedResponseCount > 0) {
mPausedResponses.add(result);
} else {
result.sendToTarget();
}
}
}
private void resultFail(Message result, Throwable tr) {
if (result != null) {
AsyncResult.forMessage(result).exception = tr;
if (mPausedResponseCount > 0) {
mPausedResponses.add(result);
} else {
result.sendToTarget();
}
}
}
// ***** Methods for CDMA support
@Override
public void
getDeviceIdentity(Message response) {
Rlog.w(LOG_TAG, "CDMA not implemented in SimulatedCommands");
unimplemented(response);
}
@Override
public void
getCDMASubscription(Message response) {
Rlog.w(LOG_TAG, "CDMA not implemented in SimulatedCommands");
unimplemented(response);
}
@Override
public void
setCdmaSubscriptionSource(int cdmaSubscriptionType, Message response) {
Rlog.w(LOG_TAG, "CDMA not implemented in SimulatedCommands");
unimplemented(response);
}
@Override
public void queryCdmaRoamingPreference(Message response) {
Rlog.w(LOG_TAG, "CDMA not implemented in SimulatedCommands");
unimplemented(response);
}
@Override
public void setCdmaRoamingPreference(int cdmaRoamingType, Message response) {
Rlog.w(LOG_TAG, "CDMA not implemented in SimulatedCommands");
unimplemented(response);
}
@Override
public void
setPhoneType(int phoneType) {
Rlog.w(LOG_TAG, "CDMA not implemented in SimulatedCommands");
}
@Override
public void getPreferredVoicePrivacy(Message result) {
Rlog.w(LOG_TAG, "CDMA not implemented in SimulatedCommands");
unimplemented(result);
}
@Override
public void setPreferredVoicePrivacy(boolean enable, Message result) {
Rlog.w(LOG_TAG, "CDMA not implemented in SimulatedCommands");
unimplemented(result);
}
/**
* Set the TTY mode
*
* @param ttyMode is one of the following:
* - {@link com.android.internal.telephony.Phone#TTY_MODE_OFF}
* - {@link com.android.internal.telephony.Phone#TTY_MODE_FULL}
* - {@link com.android.internal.telephony.Phone#TTY_MODE_HCO}
* - {@link com.android.internal.telephony.Phone#TTY_MODE_VCO}
* @param response is callback message
*/
@Override
public void setTTYMode(int ttyMode, Message response) {
Rlog.w(LOG_TAG, "Not implemented in SimulatedCommands");
unimplemented(response);
}
/**
* Query the TTY mode
* (AsyncResult)response.obj).result is an int[] with element [0] set to
* tty mode:
* - {@link com.android.internal.telephony.Phone#TTY_MODE_OFF}
* - {@link com.android.internal.telephony.Phone#TTY_MODE_FULL}
* - {@link com.android.internal.telephony.Phone#TTY_MODE_HCO}
* - {@link com.android.internal.telephony.Phone#TTY_MODE_VCO}
* @param response is callback message
*/
@Override
public void queryTTYMode(Message response) {
Rlog.w(LOG_TAG, "CDMA not implemented in SimulatedCommands");
unimplemented(response);
}
/**
* {@inheritDoc}
*/
@Override
public void sendCDMAFeatureCode(String FeatureCode, Message response) {
Rlog.w(LOG_TAG, "CDMA not implemented in SimulatedCommands");
unimplemented(response);
}
/**
* {@inheritDoc}
*/
@Override
public void sendCdmaSms(byte[] pdu, Message response){
Rlog.w(LOG_TAG, "CDMA not implemented in SimulatedCommands");
}
@Override
public void setCdmaBroadcastActivation(boolean activate, Message response) {
unimplemented(response);
}
@Override
public void getCdmaBroadcastConfig(Message response) {
unimplemented(response);
}
@Override
public void setCdmaBroadcastConfig(CdmaSmsBroadcastConfigInfo[] configs, Message response) {
unimplemented(response);
}
public void forceDataDormancy(Message response) {
unimplemented(response);
}
@Override
public void setGsmBroadcastActivation(boolean activate, Message response) {
unimplemented(response);
}
@Override
public void setGsmBroadcastConfig(SmsBroadcastConfigInfo[] config, Message response) {
unimplemented(response);
}
@Override
public void getGsmBroadcastConfig(Message response) {
unimplemented(response);
}
@Override
public void supplyIccPinForApp(String pin, String aid, Message response) {
unimplemented(response);
}
@Override
public void supplyIccPukForApp(String puk, String newPin, String aid, Message response) {
unimplemented(response);
}
@Override
public void supplyIccPin2ForApp(String pin2, String aid, Message response) {
unimplemented(response);
}
@Override
public void supplyIccPuk2ForApp(String puk2, String newPin2, String aid, Message response) {
unimplemented(response);
}
@Override
public void changeIccPinForApp(String oldPin, String newPin, String aidPtr, Message response) {
unimplemented(response);
}
@Override
public void changeIccPin2ForApp(String oldPin2, String newPin2, String aidPtr,
Message response) {
unimplemented(response);
}
@Override
public void requestIsimAuthentication(String nonce, Message response) {
unimplemented(response);
}
@Override
public void getVoiceRadioTechnology(Message response) {
unimplemented(response);
}
@Override
public void getCellInfoList(Message response) {
unimplemented(response);
}
@Override
public void setCellInfoListRate(int rateInMillis, Message response) {
unimplemented(response);
}
@Override
public void setInitialAttachApn(String apn, String protocol, int authType, String username,
String password, Message result) {
}
@Override
public void getImsRegistrationState(Message response) {
unimplemented(response);
}
@Override
public void sendImsCdmaSms(byte[] pdu, int retry, int messageRef,
Message response){
unimplemented(response);
}
@Override
public void sendImsGsmSms(String smscPDU, String pdu,
int retry, int messageRef, Message response){
unimplemented(response);
}
}