Merge "Remove obsolete getIsimChallengeResponse"
diff --git a/src/java/com/android/internal/telephony/BaseCommands.java b/src/java/com/android/internal/telephony/BaseCommands.java
index b70e800..8a0f918 100644
--- a/src/java/com/android/internal/telephony/BaseCommands.java
+++ b/src/java/com/android/internal/telephony/BaseCommands.java
@@ -74,7 +74,7 @@
protected RegistrantList mCarrierInfoForImsiEncryptionRegistrants = new RegistrantList();
protected RegistrantList mRilNetworkScanResultRegistrants = new RegistrantList();
protected RegistrantList mModemResetRegistrants = new RegistrantList();
-
+ protected RegistrantList mNattKeepaliveStatusRegistrants = new RegistrantList();
protected Registrant mGsmSmsRegistrant;
protected Registrant mCdmaSmsRegistrant;
@@ -939,4 +939,20 @@
public void unregisterForCarrierInfoForImsiEncryption(Handler h) {
mCarrierInfoForImsiEncryptionRegistrants.remove(h);
}
+
+ @Override
+ public void registerForNattKeepaliveStatus(Handler h, int what, Object obj) {
+ Registrant r = new Registrant(h, what, obj);
+
+ synchronized (mStateMonitor) {
+ mNattKeepaliveStatusRegistrants.add(r);
+ }
+ }
+
+ @Override
+ public void unregisterForNattKeepaliveStatus(Handler h) {
+ synchronized (mStateMonitor) {
+ mNattKeepaliveStatusRegistrants.remove(h);
+ }
+ }
}
diff --git a/src/java/com/android/internal/telephony/CommandException.java b/src/java/com/android/internal/telephony/CommandException.java
index 1d2cc3a..fe9fa72 100644
--- a/src/java/com/android/internal/telephony/CommandException.java
+++ b/src/java/com/android/internal/telephony/CommandException.java
@@ -259,6 +259,8 @@
return new CommandException(Error.DEVICE_IN_USE);
case RILConstants.ABORTED:
return new CommandException(Error.ABORTED);
+ case RILConstants.INVALID_RESPONSE:
+ return new CommandException(Error.INVALID_RESPONSE);
case RILConstants.OEM_ERROR_1:
return new CommandException(Error.OEM_ERROR_1);
case RILConstants.OEM_ERROR_2:
diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java
index 483546f..ab12091 100644
--- a/src/java/com/android/internal/telephony/CommandsInterface.java
+++ b/src/java/com/android/internal/telephony/CommandsInterface.java
@@ -16,6 +16,7 @@
package com.android.internal.telephony;
+import android.net.KeepalivePacketData;
import android.os.Handler;
import android.os.Message;
import android.os.WorkSource;
@@ -2061,7 +2062,7 @@
* Register for unsolicited PCO data. This information is carrier-specific,
* opaque binary blobs destined for carrier apps for interpretation.
*
- * @param h Handler for notificaiton message.
+ * @param h Handler for notification message.
* @param what User-defined message code.
* @param obj User object.
*/
@@ -2121,7 +2122,7 @@
/**
* Register for unsolicited Carrier Public Key.
*
- * @param h Handler for notificaiton message.
+ * @param h Handler for notification message.
* @param what User-defined message code.
* @param obj User object.
*/
@@ -2130,14 +2131,14 @@
/**
* DeRegister for unsolicited Carrier Public Key.
*
- * @param h Handler for notificaiton message.
+ * @param h Handler for notification message.
*/
void unregisterForCarrierInfoForImsiEncryption(Handler h);
/**
* Register for unsolicited Network Scan result.
*
- * @param h Handler for notificaiton message.
+ * @param h Handler for notification message.
* @param what User-defined message code.
* @param obj User object.
*/
@@ -2146,10 +2147,45 @@
/**
* DeRegister for unsolicited Network Scan result.
*
- * @param h Handler for notificaiton message.
+ * @param h Handler for notification message.
*/
void unregisterForNetworkScanResult(Handler h);
+ /**
+ * Register for unsolicited NATT Keepalive Status Indications
+ *
+ * @param h Handler for notification message.
+ * @param what User-defined message code.
+ * @param obj User object.
+ */
+ void registerForNattKeepaliveStatus(Handler h, int what, Object obj);
+
+ /**
+ * Deregister for unsolicited NATT Keepalive Status Indications.
+ *
+ * @param h Handler for notification message.
+ */
+ void unregisterForNattKeepaliveStatus(Handler h);
+
+ /**
+ * Start sending NATT Keepalive packets on a specified data connection
+ *
+ * @param contextId cid that identifies the data connection for this keepalive
+ * @param packetData the keepalive packet data description
+ * @param intervalMillis a time interval in ms between keepalive packet transmissions
+ * @param result a Message to return to the requester
+ */
+ void startNattKeepalive(
+ int contextId, KeepalivePacketData packetData, int intervalMillis, Message result);
+
+ /**
+ * Stop sending NATT Keepalive packets on a specified data connection
+ *
+ * @param sessionHandle the keepalive session handle (from the modem) to stop
+ * @param result a Message to return to the requester
+ */
+ void stopNattKeepalive(int sessionHandle, Message result);
+
default public List<ClientRequestStats> getClientRequestStats() {
return null;
}
diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java
index fab8c03..eefcdc8 100644
--- a/src/java/com/android/internal/telephony/RIL.java
+++ b/src/java/com/android/internal/telephony/RIL.java
@@ -53,6 +53,7 @@
import android.hardware.radio.V1_0.SmsWriteArgs;
import android.hardware.radio.V1_0.UusInfo;
import android.net.ConnectivityManager;
+import android.net.KeepalivePacketData;
import android.net.LinkAddress;
import android.net.NetworkUtils;
import android.os.AsyncResult;
@@ -106,6 +107,7 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Inet4Address;
+import java.net.Inet6Address;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Arrays;
@@ -3739,6 +3741,93 @@
}
@Override
+ public void startNattKeepalive(
+ int contextId, KeepalivePacketData packetData, int intervalMillis, Message result) {
+ checkNotNull(packetData, "KeepaliveRequest cannot be null.");
+ IRadio radioProxy = getRadioProxy(result);
+ if (radioProxy == null) {
+ riljLoge("Radio Proxy object is null!");
+ return;
+ }
+
+ android.hardware.radio.V1_1.IRadio radioProxy11 =
+ android.hardware.radio.V1_1.IRadio.castFrom(radioProxy);
+ if (radioProxy11 == null) {
+ if (result != null) {
+ AsyncResult.forMessage(result, null,
+ CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED));
+ result.sendToTarget();
+ }
+ return;
+ }
+
+ RILRequest rr = obtainRequest(
+ RIL_REQUEST_START_KEEPALIVE, result, mRILDefaultWorkSource);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ try {
+ android.hardware.radio.V1_1.KeepaliveRequest req =
+ new android.hardware.radio.V1_1.KeepaliveRequest();
+
+ req.cid = contextId;
+
+ if (packetData.dstAddress instanceof Inet4Address) {
+ req.type = android.hardware.radio.V1_1.KeepaliveType.NATT_IPV4;
+ } else if (packetData.dstAddress instanceof Inet6Address) {
+ req.type = android.hardware.radio.V1_1.KeepaliveType.NATT_IPV6;
+ } else {
+ AsyncResult.forMessage(result, null,
+ CommandException.fromRilErrno(INVALID_ARGUMENTS));
+ result.sendToTarget();
+ return;
+ }
+
+ appendPrimitiveArrayToArrayList(
+ packetData.srcAddress.getAddress(), req.sourceAddress);
+ req.sourcePort = packetData.srcPort;
+ appendPrimitiveArrayToArrayList(
+ packetData.dstAddress.getAddress(), req.destinationAddress);
+ req.destinationPort = packetData.dstPort;
+
+ radioProxy11.startKeepalive(rr.mSerial, req);
+ } catch (RemoteException | RuntimeException e) {
+ handleRadioProxyExceptionForRR(rr, "startNattKeepalive", e);
+ }
+ }
+
+ @Override
+ public void stopNattKeepalive(int sessionHandle, Message result) {
+ IRadio radioProxy = getRadioProxy(result);
+ if (radioProxy == null) {
+ Rlog.e(RIL.RILJ_LOG_TAG, "Radio Proxy object is null!");
+ return;
+ }
+
+ android.hardware.radio.V1_1.IRadio radioProxy11 =
+ android.hardware.radio.V1_1.IRadio.castFrom(radioProxy);
+ if (radioProxy11 == null) {
+ if (result != null) {
+ AsyncResult.forMessage(result, null,
+ CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED));
+ result.sendToTarget();
+ }
+ return;
+ }
+
+ RILRequest rr = obtainRequest(
+ RIL_REQUEST_STOP_KEEPALIVE, result, mRILDefaultWorkSource);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ try {
+ radioProxy11.stopKeepalive(rr.mSerial, sessionHandle);
+ } catch (RemoteException | RuntimeException e) {
+ handleRadioProxyExceptionForRR(rr, "stopNattKeepalive", e);
+ }
+ }
+
+ @Override
public void getIMEI(Message result) {
throw new RuntimeException("getIMEI not expected to be called");
}
@@ -4667,6 +4756,10 @@
return "RIL_REQUEST_GET_SLOT_STATUS";
case RIL_REQUEST_SET_LOGICAL_TO_PHYSICAL_SLOT_MAPPING:
return "RIL_REQUEST_SET_LOGICAL_TO_PHYSICAL_SLOT_MAPPING";
+ case RIL_REQUEST_START_KEEPALIVE:
+ return "RIL_REQUEST_START_KEEPALIVE";
+ case RIL_REQUEST_STOP_KEEPALIVE:
+ return "RIL_REQUEST_STOP_KEEPALIVE";
default: return "<unknown request>";
}
}
@@ -4771,6 +4864,8 @@
return "RIL_UNSOL_NETWORK_SCAN_RESULT";
case RIL_UNSOL_ICC_SLOT_STATUS:
return "RIL_UNSOL_ICC_SLOT_STATUS";
+ case RIL_UNSOL_KEEPALIVE_STATUS:
+ return "RIL_UNSOL_KEEPALIVE_STATUS";
default:
return "<unknown response>";
}
@@ -4851,6 +4946,13 @@
return mClientWakelockTracker.getClientRequestStats();
}
+ /** Append the data to the end of an ArrayList */
+ public static void appendPrimitiveArrayToArrayList(byte[] src, ArrayList<Byte> dst) {
+ for (byte b : src) {
+ dst.add(b);
+ }
+ }
+
public static ArrayList<Byte> primitiveArrayToArrayList(byte[] arr) {
ArrayList<Byte> arrayList = new ArrayList<>(arr.length);
for (byte b : arr) {
@@ -4859,6 +4961,7 @@
return arrayList;
}
+ /** Convert an ArrayList of Bytes to an exactly-sized primitive array */
public static byte[] arrayListToPrimitiveArray(ArrayList<Byte> bytes) {
byte[] ret = new byte[bytes.size()];
for (int i = 0; i < ret.length; i++) {
diff --git a/src/java/com/android/internal/telephony/RadioIndication.java b/src/java/com/android/internal/telephony/RadioIndication.java
index 88382bc..8d77982 100644
--- a/src/java/com/android/internal/telephony/RadioIndication.java
+++ b/src/java/com/android/internal/telephony/RadioIndication.java
@@ -28,6 +28,7 @@
import static com.android.internal.telephony.RILConstants.RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE;
import static com.android.internal.telephony.RILConstants.RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE;
import static com.android.internal.telephony.RILConstants.RIL_UNSOL_HARDWARE_CONFIG_CHANGED;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_KEEPALIVE_STATUS;
import static com.android.internal.telephony.RILConstants.RIL_UNSOL_LCEDATA_RECV;
import static com.android.internal.telephony.RILConstants.RIL_UNSOL_MODEM_RESTART;
import static com.android.internal.telephony.RILConstants.RIL_UNSOL_NETWORK_SCAN_RESULT;
@@ -80,7 +81,6 @@
import android.hardware.radio.V1_0.SsInfoData;
import android.hardware.radio.V1_0.StkCcUnsolSsResult;
import android.hardware.radio.V1_0.SuppSvcNotification;
-import android.hardware.radio.V1_1.KeepaliveStatus;
import android.hardware.radio.V1_2.IRadioIndication;
import android.hardware.radio.V1_2.PhysicalChannelConfig;
import android.os.AsyncResult;
@@ -94,6 +94,7 @@
import com.android.internal.telephony.cdma.CdmaCallWaitingNotification;
import com.android.internal.telephony.cdma.CdmaInformationRecords;
import com.android.internal.telephony.cdma.SmsMessageConverter;
+import com.android.internal.telephony.dataconnection.KeepaliveStatus;
import com.android.internal.telephony.gsm.SsData;
import com.android.internal.telephony.gsm.SuppServiceNotification;
import com.android.internal.telephony.nano.TelephonyProto.SmsSession;
@@ -843,10 +844,19 @@
/**
* Indicates a change in the status of an ongoing Keepalive session
* @param indicationType RadioIndicationType
- * @param keepaliveStatus Status of the ongoing Keepalive session
+ * @param halStatus Status of the ongoing Keepalive session
*/
- public void keepaliveStatus(int indicationType, KeepaliveStatus keepaliveStatus) {
- throw new UnsupportedOperationException("keepaliveStatus Indications are not implemented");
+ public void keepaliveStatus(
+ int indicationType, android.hardware.radio.V1_1.KeepaliveStatus halStatus) {
+ mRil.processIndication(indicationType);
+
+ if (RIL.RILJ_LOGD) {
+ mRil.unsljLogRet(RIL_UNSOL_KEEPALIVE_STATUS,
+ "handle=" + halStatus.sessionHandle + " code=" + halStatus.code);
+ }
+
+ KeepaliveStatus ks = new KeepaliveStatus(halStatus.sessionHandle, halStatus.code);
+ mRil.mNattKeepaliveStatusRegistrants.notifyRegistrants(new AsyncResult(null, ks, null));
}
private CommandsInterface.RadioState getRadioStateFromInt(int stateInt) {
diff --git a/src/java/com/android/internal/telephony/RadioResponse.java b/src/java/com/android/internal/telephony/RadioResponse.java
index c140933..d12e35b 100644
--- a/src/java/com/android/internal/telephony/RadioResponse.java
+++ b/src/java/com/android/internal/telephony/RadioResponse.java
@@ -33,7 +33,6 @@
import android.hardware.radio.V1_0.SendSmsResult;
import android.hardware.radio.V1_0.SetupDataCallResult;
import android.hardware.radio.V1_0.VoiceRegStateResult;
-import android.hardware.radio.V1_1.KeepaliveStatus;
import android.hardware.radio.V1_2.IRadioResponse;
import android.os.AsyncResult;
import android.os.Message;
@@ -49,6 +48,7 @@
import android.telephony.data.DataCallResponse;
import android.text.TextUtils;
+import com.android.internal.telephony.dataconnection.KeepaliveStatus;
import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo;
import com.android.internal.telephony.uicc.IccCardApplicationStatus;
import com.android.internal.telephony.uicc.IccCardStatus;
@@ -1249,20 +1249,78 @@
responseVoid(responseInfo);
}
+
/**
* @param responseInfo Response info struct containing response type, serial no. and error
* @param keepaliveStatus status of the keepalive with a handle for the session
*/
public void startKeepaliveResponse(RadioResponseInfo responseInfo,
- KeepaliveStatus keepaliveStatus) {
- throw new UnsupportedOperationException("startKeepaliveResponse not implemented");
+ android.hardware.radio.V1_1.KeepaliveStatus keepaliveStatus) {
+
+ RILRequest rr = mRil.processResponse(responseInfo);
+
+ if (rr == null) {
+ return;
+ }
+
+ KeepaliveStatus ret = null;
+
+ switch(responseInfo.error) {
+ case RadioError.NONE:
+ int convertedStatus = convertHalKeepaliveStatusCode(keepaliveStatus.code);
+ if (convertedStatus < 0) {
+ ret = new KeepaliveStatus(KeepaliveStatus.ERROR_UNSUPPORTED);
+ } else {
+ ret = new KeepaliveStatus(keepaliveStatus.sessionHandle, convertedStatus);
+ }
+ break;
+ case RadioError.REQUEST_NOT_SUPPORTED:
+ ret = new KeepaliveStatus(KeepaliveStatus.ERROR_UNSUPPORTED);
+ // The request is unsupported, which is ok. We'll report it to the higher
+ // layer and treat it as acceptable in the RIL.
+ responseInfo.error = RadioError.NONE;
+ break;
+ case RadioError.NO_RESOURCES:
+ ret = new KeepaliveStatus(KeepaliveStatus.ERROR_NO_RESOURCES);
+ break;
+ default:
+ ret = new KeepaliveStatus(KeepaliveStatus.ERROR_UNKNOWN);
+ break;
+ }
+ sendMessageResponse(rr.mResult, ret);
+ mRil.processResponseDone(rr, responseInfo, ret);
}
/**
* @param responseInfo Response info struct containing response type, serial no. and error
*/
public void stopKeepaliveResponse(RadioResponseInfo responseInfo) {
- throw new UnsupportedOperationException("stopKeepaliveResponse not implemented");
+ RILRequest rr = mRil.processResponse(responseInfo);
+
+ if (rr == null) {
+ return;
+ }
+
+ if (responseInfo.error == RadioError.NONE) {
+ sendMessageResponse(rr.mResult, null);
+ mRil.processResponseDone(rr, responseInfo, null);
+ } else {
+ //TODO: Error code translation
+ }
+ }
+
+ private int convertHalKeepaliveStatusCode(int halCode) {
+ switch (halCode) {
+ case android.hardware.radio.V1_1.KeepaliveStatusCode.ACTIVE:
+ return KeepaliveStatus.STATUS_ACTIVE;
+ case android.hardware.radio.V1_1.KeepaliveStatusCode.INACTIVE:
+ return KeepaliveStatus.STATUS_INACTIVE;
+ case android.hardware.radio.V1_1.KeepaliveStatusCode.PENDING:
+ return KeepaliveStatus.STATUS_PENDING;
+ default:
+ mRil.riljLog("Invalid Keepalive Status" + halCode);
+ return -1;
+ }
}
private IccCardStatus convertHalCardStatus(CardStatus cardStatus) {
diff --git a/src/java/com/android/internal/telephony/TransportManager.java b/src/java/com/android/internal/telephony/TransportManager.java
new file mode 100644
index 0000000..d81130a
--- /dev/null
+++ b/src/java/com/android/internal/telephony/TransportManager.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2018 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.dataconnection;
+
+import android.telephony.AccessNetworkConstants.TransportType;
+import android.telephony.Rlog;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class represents the transport manager which manages available transports and
+ * route requests to correct transport.
+ */
+public class TransportManager {
+ private static final String TAG = TransportManager.class.getSimpleName();
+
+ private List<Integer> mAvailableTransports = new ArrayList<>();
+
+ public TransportManager() {
+ // TODO: get transpot list from AccessNetworkManager.
+ mAvailableTransports.add(TransportType.WWAN);
+ }
+
+ public List<Integer> getAvailableTransports() {
+ return new ArrayList<>(mAvailableTransports);
+ }
+
+ private void log(String s) {
+ Rlog.d(TAG, s);
+ }
+
+ private void loge(String s) {
+ Rlog.e(TAG, s);
+ }
+}
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
index c7aa0b3..0cc846f 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
@@ -22,6 +22,8 @@
import android.app.PendingIntent;
import android.content.Context;
import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.PacketKeepalive;
+import android.net.KeepalivePacketData;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.NetworkAgent;
@@ -45,6 +47,7 @@
import android.text.TextUtils;
import android.util.LocalLog;
import android.util.Pair;
+import android.util.SparseArray;
import android.util.TimeUtils;
import com.android.internal.annotations.VisibleForTesting;
@@ -179,7 +182,7 @@
private int mRilRat = Integer.MAX_VALUE;
private int mDataRegState = Integer.MAX_VALUE;
private NetworkInfo mNetworkInfo;
- private NetworkAgent mNetworkAgent;
+ private DcNetworkAgent mNetworkAgent;
private LocalLog mNetCapsLocalLog = new LocalLog(50);
int mTag;
@@ -207,9 +210,14 @@
static final int EVENT_DATA_CONNECTION_VOICE_CALL_STARTED = BASE + 15;
static final int EVENT_DATA_CONNECTION_VOICE_CALL_ENDED = BASE + 16;
static final int EVENT_DATA_CONNECTION_OVERRIDE_CHANGED = BASE + 17;
+ static final int EVENT_KEEPALIVE_STATUS = BASE + 18;
+ static final int EVENT_KEEPALIVE_STARTED = BASE + 19;
+ static final int EVENT_KEEPALIVE_STOPPED = BASE + 20;
+ static final int EVENT_KEEPALIVE_START_REQUEST = BASE + 21;
+ static final int EVENT_KEEPALIVE_STOP_REQUEST = BASE + 22;
private static final int CMD_TO_STRING_COUNT =
- EVENT_DATA_CONNECTION_OVERRIDE_CHANGED - BASE + 1;
+ EVENT_KEEPALIVE_STOP_REQUEST - BASE + 1;
private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT];
static {
@@ -235,6 +243,11 @@
"EVENT_DATA_CONNECTION_VOICE_CALL_ENDED";
sCmdToString[EVENT_DATA_CONNECTION_OVERRIDE_CHANGED - BASE] =
"EVENT_DATA_CONNECTION_OVERRIDE_CHANGED";
+ sCmdToString[EVENT_KEEPALIVE_STATUS - BASE] = "EVENT_KEEPALIVE_STATUS";
+ sCmdToString[EVENT_KEEPALIVE_STARTED - BASE] = "EVENT_KEEPALIVE_STARTED";
+ sCmdToString[EVENT_KEEPALIVE_STOPPED - BASE] = "EVENT_KEEPALIVE_STOPPED";
+ sCmdToString[EVENT_KEEPALIVE_START_REQUEST - BASE] = "EVENT_KEEPALIVE_START_REQUEST";
+ sCmdToString[EVENT_KEEPALIVE_STOP_REQUEST - BASE] = "EVENT_KEEPALIVE_STOP_REQUEST";
}
// Convert cmd to string or null if unknown
static String cmdToString(int cmd) {
@@ -1362,6 +1375,14 @@
mNetworkAgent.sendNetworkInfo(mNetworkInfo);
}
break;
+ case EVENT_KEEPALIVE_START_REQUEST:
+ case EVENT_KEEPALIVE_STOP_REQUEST:
+ if (mNetworkAgent != null) {
+ mNetworkAgent.onPacketKeepaliveEvent(
+ msg.arg1,
+ ConnectivityManager.PacketKeepalive.ERROR_INVALID_NETWORK);
+ }
+ break;
default:
if (DBG) {
log("DcDefaultState: shouldn't happen but ignore msg.what="
@@ -1672,6 +1693,7 @@
* The state machine is connected, expecting an EVENT_DISCONNECT.
*/
private class DcActiveState extends State {
+
@Override public void enter() {
if (DBG) log("DcActiveState: enter dc=" + DataConnection.this);
@@ -1707,6 +1729,8 @@
mNetworkAgent = new DcNetworkAgent(getHandler().getLooper(), mPhone.getContext(),
"DcNetworkAgent", mNetworkInfo, getNetworkCapabilities(), mLinkProperties,
50, misc);
+ mPhone.mCi.registerForNattKeepaliveStatus(
+ getHandler(), DataConnection.EVENT_KEEPALIVE_STATUS, null);
}
@Override
@@ -1725,6 +1749,7 @@
mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED,
reason, mNetworkInfo.getExtraInfo());
+ mPhone.mCi.unregisterForNattKeepaliveStatus(getHandler());
if (mNetworkAgent != null) {
mNetworkAgent.sendNetworkInfo(mNetworkInfo);
mNetworkAgent = null;
@@ -1843,6 +1868,85 @@
retVal = HANDLED;
break;
}
+ case EVENT_KEEPALIVE_START_REQUEST: {
+ KeepalivePacketData pkt = (KeepalivePacketData) msg.obj;
+ int slotId = msg.arg1;
+ int intervalMillis = msg.arg2 * 1000;
+ mPhone.mCi.startNattKeepalive(
+ DataConnection.this.mCid, pkt, intervalMillis,
+ DataConnection.this.obtainMessage(
+ EVENT_KEEPALIVE_STARTED, slotId, 0, null));
+ retVal = HANDLED;
+ break;
+ }
+ case EVENT_KEEPALIVE_STOP_REQUEST: {
+ int slotId = msg.arg1;
+ int handle = mNetworkAgent.keepaliveTracker.getHandleForSlot(slotId);
+ if (handle < 0) {
+ loge("No slot found for stopPacketKeepalive! " + slotId);
+ retVal = HANDLED;
+ break;
+ } else {
+ logd("Stopping keepalive with handle: " + handle);
+ }
+
+ mPhone.mCi.stopNattKeepalive(
+ handle, DataConnection.this.obtainMessage(
+ EVENT_KEEPALIVE_STOPPED, handle, slotId, null));
+ retVal = HANDLED;
+ break;
+ }
+ case EVENT_KEEPALIVE_STARTED: {
+ AsyncResult ar = (AsyncResult) msg.obj;
+ final int slot = msg.arg1;
+ if (ar.exception != null || ar.result == null) {
+ loge("EVENT_KEEPALIVE_STARTED: error starting keepalive, e="
+ + ar.exception);
+ mNetworkAgent.onPacketKeepaliveEvent(
+ slot, ConnectivityManager.PacketKeepalive.ERROR_HARDWARE_ERROR);
+ } else {
+ KeepaliveStatus ks = (KeepaliveStatus) ar.result;
+ if (ks == null) {
+ loge("Null KeepaliveStatus received!");
+ } else {
+ mNetworkAgent.keepaliveTracker.handleKeepaliveStarted(slot, ks);
+ }
+ }
+ retVal = HANDLED;
+ break;
+ }
+ case EVENT_KEEPALIVE_STATUS: {
+ AsyncResult ar = (AsyncResult) msg.obj;
+ if (ar.exception != null) {
+ loge("EVENT_KEEPALIVE_STATUS: error in keepalive, e=" + ar.exception);
+ // We have no way to notify connectivity in this case.
+ }
+ if (ar.result != null) {
+ KeepaliveStatus ks = (KeepaliveStatus) ar.result;
+ mNetworkAgent.keepaliveTracker.handleKeepaliveStatus(ks);
+ }
+
+ retVal = HANDLED;
+ break;
+ }
+ case EVENT_KEEPALIVE_STOPPED: {
+ AsyncResult ar = (AsyncResult) msg.obj;
+ final int handle = msg.arg1;
+ final int slotId = msg.arg2;
+
+ if (ar.exception != null) {
+ loge("EVENT_KEEPALIVE_STOPPED: error stopping keepalive for handle="
+ + handle + " e=" + ar.exception);
+ mNetworkAgent.keepaliveTracker.handleKeepaliveStatus(
+ new KeepaliveStatus(KeepaliveStatus.ERROR_UNKNOWN));
+ } else {
+ log("Keepalive Stop Requested for handle=" + handle);
+ mNetworkAgent.keepaliveTracker.handleKeepaliveStatus(
+ new KeepaliveStatus(handle, KeepaliveStatus.STATUS_INACTIVE));
+ }
+ retVal = HANDLED;
+ break;
+ }
default:
if (VDBG) {
log("DcActiveState not handled msg.what=" + getWhatToString(msg.what));
@@ -1956,11 +2060,15 @@
private NetworkCapabilities mNetworkCapabilities;
+ public final DcKeepaliveTracker keepaliveTracker = new DcKeepaliveTracker();
+
public DcNetworkAgent(Looper l, Context c, String TAG, NetworkInfo ni,
NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) {
super(l, c, TAG, ni, nc, lp, score, misc);
mNetCapsLocalLog.log("New network agent created. capabilities=" + nc);
mNetworkCapabilities = nc;
+ mPhone.mCi.registerForNattKeepaliveStatus(
+ getHandler(), EVENT_KEEPALIVE_STATUS, null);
}
@Override
@@ -2018,6 +2126,137 @@
}
super.sendNetworkCapabilities(networkCapabilities);
}
+
+ @Override
+ protected void startPacketKeepalive(Message msg) {
+ DataConnection.this.obtainMessage(EVENT_KEEPALIVE_START_REQUEST,
+ msg.arg1, msg.arg2, msg.obj).sendToTarget();
+ }
+
+ @Override
+ protected void stopPacketKeepalive(Message msg) {
+ DataConnection.this.obtainMessage(EVENT_KEEPALIVE_STOP_REQUEST,
+ msg.arg1, msg.arg2, msg.obj).sendToTarget();
+ }
+
+ private class DcKeepaliveTracker {
+ private class KeepaliveRecord {
+ public int slotId;
+ public int currentStatus;
+
+ KeepaliveRecord(int slotId, int status) {
+ this.slotId = slotId;
+ this.currentStatus = status;
+ }
+ };
+
+ private final SparseArray<KeepaliveRecord> mKeepalives = new SparseArray();
+
+ int getHandleForSlot(int slotId) {
+ for (int i = 0; i < mKeepalives.size(); i++) {
+ KeepaliveRecord kr = mKeepalives.valueAt(i);
+ if (kr.slotId == slotId) return mKeepalives.keyAt(i);
+ }
+ return -1;
+ }
+
+ int keepaliveStatusErrorToPacketKeepaliveError(int error) {
+ switch(error) {
+ case KeepaliveStatus.ERROR_NONE:
+ return PacketKeepalive.SUCCESS;
+ case KeepaliveStatus.ERROR_UNSUPPORTED:
+ return PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED;
+ case KeepaliveStatus.ERROR_NO_RESOURCES:
+ case KeepaliveStatus.ERROR_UNKNOWN:
+ default:
+ return PacketKeepalive.ERROR_HARDWARE_ERROR;
+ }
+ }
+
+ void handleKeepaliveStarted(final int slot, KeepaliveStatus ks) {
+ switch (ks.statusCode) {
+ case KeepaliveStatus.STATUS_INACTIVE:
+ DcNetworkAgent.this.onPacketKeepaliveEvent(slot,
+ keepaliveStatusErrorToPacketKeepaliveError(ks.errorCode));
+ break;
+ case KeepaliveStatus.STATUS_ACTIVE:
+ DcNetworkAgent.this.onPacketKeepaliveEvent(
+ slot, PacketKeepalive.SUCCESS);
+ // fall through to add record
+ case KeepaliveStatus.STATUS_PENDING:
+ log("Adding keepalive handle="
+ + ks.sessionHandle + " slot = " + slot);
+ mKeepalives.put(ks.sessionHandle,
+ new KeepaliveRecord(
+ slot, ks.statusCode));
+ break;
+ default:
+ loge("Invalid KeepaliveStatus Code: " + ks.statusCode);
+ break;
+ }
+ }
+
+ void handleKeepaliveStatus(KeepaliveStatus ks) {
+ final KeepaliveRecord kr;
+ kr = mKeepalives.get(ks.sessionHandle);
+
+ if (kr == null) {
+ // If there is no slot for the session handle, we received an event
+ // for a different data connection. This is not an error because the
+ // keepalive session events are broadcast to all listeners.
+ log("Discarding keepalive event for different data connection:" + ks);
+ return;
+ }
+ // Switch on the current state, to see what we do with the status update
+ switch (kr.currentStatus) {
+ case KeepaliveStatus.STATUS_INACTIVE:
+ loge("Inactive Keepalive received status!");
+ DcNetworkAgent.this.onPacketKeepaliveEvent(
+ kr.slotId, PacketKeepalive.ERROR_HARDWARE_ERROR);
+ break;
+ case KeepaliveStatus.STATUS_PENDING:
+ switch (ks.statusCode) {
+ case KeepaliveStatus.STATUS_INACTIVE:
+ DcNetworkAgent.this.onPacketKeepaliveEvent(kr.slotId,
+ keepaliveStatusErrorToPacketKeepaliveError(ks.errorCode));
+ kr.currentStatus = KeepaliveStatus.STATUS_INACTIVE;
+ mKeepalives.remove(ks.sessionHandle);
+ break;
+ case KeepaliveStatus.STATUS_ACTIVE:
+ log("Pending Keepalive received active status!");
+ kr.currentStatus = KeepaliveStatus.STATUS_ACTIVE;
+ DcNetworkAgent.this.onPacketKeepaliveEvent(
+ kr.slotId, PacketKeepalive.SUCCESS);
+ break;
+ case KeepaliveStatus.STATUS_PENDING:
+ loge("Invalid unsolicied Keepalive Pending Status!");
+ break;
+ default:
+ loge("Invalid Keepalive Status received, " + ks.statusCode);
+ }
+ break;
+ case KeepaliveStatus.STATUS_ACTIVE:
+ switch (ks.statusCode) {
+ case KeepaliveStatus.STATUS_INACTIVE:
+ loge("Keepalive received stopped status!");
+ DcNetworkAgent.this.onPacketKeepaliveEvent(
+ kr.slotId, PacketKeepalive.SUCCESS);
+ kr.currentStatus = KeepaliveStatus.STATUS_INACTIVE;
+ mKeepalives.remove(ks.sessionHandle);
+ break;
+ case KeepaliveStatus.STATUS_PENDING:
+ case KeepaliveStatus.STATUS_ACTIVE:
+ loge("Active Keepalive received invalid status!");
+ break;
+ default:
+ loge("Invalid Keepalive Status received, " + ks.statusCode);
+ }
+ break;
+ default:
+ loge("Invalid Keepalive Status received, " + kr.currentStatus);
+ }
+ }
+ };
}
// ******* "public" interface
diff --git a/src/java/com/android/internal/telephony/dataconnection/KeepaliveStatus.java b/src/java/com/android/internal/telephony/dataconnection/KeepaliveStatus.java
new file mode 100644
index 0000000..8b0ec4f
--- /dev/null
+++ b/src/java/com/android/internal/telephony/dataconnection/KeepaliveStatus.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2017 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.dataconnection;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * This class serves to pass around the parameters of Keepalive session
+ * status within the telephony framework.
+ *
+ * {@hide}
+ */
+public class KeepaliveStatus implements Parcelable {
+ private static final String LOG_TAG = "KeepaliveStatus";
+
+ /** This should match the HAL Radio::1_1::KeepaliveStatusCode */
+ public static final int STATUS_ACTIVE = 0;
+ public static final int STATUS_INACTIVE = 1;
+ public static final int STATUS_PENDING = 2;
+
+ public static final int ERROR_NONE = 0;
+ public static final int ERROR_UNSUPPORTED = 1;
+ public static final int ERROR_NO_RESOURCES = 2;
+ public static final int ERROR_UNKNOWN = 3;
+
+ public static final int INVALID_HANDLE = Integer.MAX_VALUE;
+
+ /** An opaque value that identifies this Keepalive status to the modem */
+ public final int sessionHandle;
+
+ /**
+ * A status code indicating whether this Keepalive session is
+ * active, inactive, or pending activation
+ */
+ public final int statusCode;
+
+ /** An error code indicating a lower layer failure, if any */
+ public final int errorCode;
+
+ public KeepaliveStatus(int error) {
+ sessionHandle = INVALID_HANDLE;
+ statusCode = STATUS_INACTIVE;
+ errorCode = error;
+ }
+
+ public KeepaliveStatus(int handle, int code) {
+ sessionHandle = handle;
+ statusCode = code;
+ errorCode = ERROR_NONE;
+ }
+
+
+ @Override
+ public String toString() {
+ return String.format("{errorCode=%d, sessionHandle=%d, statusCode=%d}",
+ errorCode, sessionHandle, statusCode);
+ }
+
+ // Parcelable Implementation
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(errorCode);
+ dest.writeInt(sessionHandle);
+ dest.writeInt(statusCode);
+ }
+
+ private KeepaliveStatus(Parcel p) {
+ errorCode = p.readInt();
+ sessionHandle = p.readInt();
+ statusCode = p.readInt();
+ }
+
+ public static final Parcelable.Creator<KeepaliveStatus> CREATOR =
+ new Parcelable.Creator<KeepaliveStatus>() {
+ @Override
+ public KeepaliveStatus createFromParcel(Parcel source) {
+ return new KeepaliveStatus(source);
+ }
+
+ @Override
+ public KeepaliveStatus[] newArray(int size) {
+ return new KeepaliveStatus[size];
+ }
+ };
+}
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java
index 4b1e2a0..770fbb1 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java
@@ -17,6 +17,7 @@
package com.android.internal.telephony.imsphone;
import android.content.Context;
+import android.net.KeepalivePacketData;
import android.os.Handler;
import android.os.Message;
import android.service.carrier.CarrierIdentifier;
@@ -644,4 +645,13 @@
@Override
public void setSimCardPower(int state, Message result) {
}
+
+ @Override
+ public void startNattKeepalive(
+ int contextId, KeepalivePacketData packetData, int intervalMillis, Message result) {
+ }
+
+ @Override
+ public void stopNattKeepalive(int sessionHandle, Message result) {
+ }
}
diff --git a/src/java/com/android/internal/telephony/sip/SipCommandInterface.java b/src/java/com/android/internal/telephony/sip/SipCommandInterface.java
index 2bbc65c..9fd22ed 100644
--- a/src/java/com/android/internal/telephony/sip/SipCommandInterface.java
+++ b/src/java/com/android/internal/telephony/sip/SipCommandInterface.java
@@ -17,6 +17,7 @@
package com.android.internal.telephony.sip;
import android.content.Context;
+import android.net.KeepalivePacketData;
import android.os.Handler;
import android.os.Message;
import android.service.carrier.CarrierIdentifier;
@@ -646,4 +647,13 @@
@Override
public void setSimCardPower(int state, Message result) {
}
+
+ @Override
+ public void startNattKeepalive(
+ int contextId, KeepalivePacketData packetData, int intervalMillis, Message result) {
+ }
+
+ @Override
+ public void stopNattKeepalive(int sessionHandle, Message result) {
+ }
}
diff --git a/src/java/com/android/internal/telephony/test/SimulatedCommands.java b/src/java/com/android/internal/telephony/test/SimulatedCommands.java
index 44b7745..277fbd6 100644
--- a/src/java/com/android/internal/telephony/test/SimulatedCommands.java
+++ b/src/java/com/android/internal/telephony/test/SimulatedCommands.java
@@ -18,6 +18,7 @@
import android.hardware.radio.V1_0.DataRegStateResult;
import android.hardware.radio.V1_0.VoiceRegStateResult;
+import android.net.KeepalivePacketData;
import android.net.LinkAddress;
import android.net.NetworkUtils;
import android.os.AsyncResult;
@@ -2200,4 +2201,13 @@
super.unregisterForIccRefresh(h);
SimulatedCommandsVerifier.getInstance().unregisterForIccRefresh(h);
}
+
+ @Override
+ public void startNattKeepalive(
+ int contextId, KeepalivePacketData packetData, int intervalMillis, Message result) {
+ }
+
+ @Override
+ public void stopNattKeepalive(int sessionHandle, Message result) {
+ }
}
diff --git a/src/java/com/android/internal/telephony/test/SimulatedCommandsVerifier.java b/src/java/com/android/internal/telephony/test/SimulatedCommandsVerifier.java
index fb69333..4a3939b 100644
--- a/src/java/com/android/internal/telephony/test/SimulatedCommandsVerifier.java
+++ b/src/java/com/android/internal/telephony/test/SimulatedCommandsVerifier.java
@@ -16,6 +16,7 @@
package com.android.internal.telephony.test;
+import android.net.KeepalivePacketData;
import android.os.Handler;
import android.os.Message;
import android.service.carrier.CarrierIdentifier;
@@ -1401,4 +1402,21 @@
@Override
public void unregisterForCarrierInfoForImsiEncryption(Handler h) {
}
+
+ @Override
+ public void registerForNattKeepaliveStatus(Handler h, int what, Object obj) {
+ }
+
+ @Override
+ public void unregisterForNattKeepaliveStatus(Handler h) {
+ }
+
+ @Override
+ public void startNattKeepalive(
+ int contextId, KeepalivePacketData packetData, int intervalMillis, Message result) {
+ }
+
+ @Override
+ public void stopNattKeepalive(int sessionHandle, Message result) {
+ }
}
diff --git a/src/java/com/android/internal/telephony/uicc/UiccProfile.java b/src/java/com/android/internal/telephony/uicc/UiccProfile.java
index 7e59e9f..a425d9e 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccProfile.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccProfile.java
@@ -222,56 +222,15 @@
return;
}
switch (msg.what) {
- case EVENT_RADIO_OFF_OR_UNAVAILABLE:
- updateExternalState();
- break;
-
- case EVENT_ICC_LOCKED:
- processLockedState();
- break;
-
- case EVENT_APP_READY:
- if (VDBG) log("EVENT_APP_READY");
- if (areAllApplicationsReady()) {
- if (areAllRecordsLoaded() && areCarrierPriviligeRulesLoaded()) {
- setExternalState(IccCardConstants.State.LOADED);
- } else {
- setExternalState(IccCardConstants.State.READY);
- }
- }
- break;
-
- case EVENT_RECORDS_LOADED:
- if (VDBG) log("EVENT_RECORDS_LOADED");
- if (!areAllRecordsLoaded()) {
- break;
- }
- // Update the MCC/MNC.
- if (mIccRecords != null) {
- String operator = mIccRecords.getOperatorNumeric();
- log("operator=" + operator + " mPhoneId=" + mPhoneId);
-
- if (!TextUtils.isEmpty(operator)) {
- mTelephonyManager.setSimOperatorNumericForPhone(mPhoneId, operator);
- String countryCode = operator.substring(0, 3);
- if (countryCode != null) {
- mTelephonyManager.setSimCountryIsoForPhone(mPhoneId,
- MccTable.countryCodeForMcc(Integer.parseInt(countryCode)));
- } else {
- loge("EVENT_RECORDS_LOADED Country code is null");
- }
- } else {
- loge("EVENT_RECORDS_LOADED Operator name is null");
- }
- }
- if (areCarrierPriviligeRulesLoaded()) {
- setExternalState(IccCardConstants.State.LOADED);
- }
- break;
-
case EVENT_NETWORK_LOCKED:
mNetworkLockedRegistrants.notifyRegistrants();
- setExternalState(IccCardConstants.State.NETWORK_LOCKED);
+ // intentional fall through
+ case EVENT_RADIO_OFF_OR_UNAVAILABLE:
+ case EVENT_ICC_LOCKED:
+ case EVENT_APP_READY:
+ case EVENT_RECORDS_LOADED:
+ if (VDBG) log("handleMessage: Received " + msg.what);
+ updateExternalState();
break;
case EVENT_ICC_RECORD_EVENTS:
@@ -288,9 +247,7 @@
case EVENT_CARRIER_PRIVILEGES_LOADED:
if (VDBG) log("EVENT_CARRIER_PRIVILEGES_LOADED");
onCarrierPriviligesLoadedMessage();
- if (areAllRecordsLoaded()) {
- setExternalState(IccCardConstants.State.LOADED);
- }
+ updateExternalState();
break;
case EVENT_OPEN_LOGICAL_CHANNEL_DONE:
@@ -348,7 +305,7 @@
}
private void updateExternalState() {
-
+ // First check if card state is IO_ERROR or RESTRICTED
if (mUiccCard.getCardState() == IccCardStatus.CardState.CARDSTATE_ERROR) {
setExternalState(IccCardConstants.State.CARD_IO_ERROR);
return;
@@ -359,13 +316,65 @@
return;
}
- if (mUiccApplication == null || !areAllApplicationsReady()) {
+ // By process of elimination, the UICC Card State = PRESENT and state needs to be decided
+ // based on apps
+ if (mUiccApplication == null) {
+ loge("updateExternalState: setting state to NOT_READY because mUiccApplication is "
+ + "null");
setExternalState(IccCardConstants.State.NOT_READY);
return;
}
- // By process of elimination, the UICC Card State = PRESENT
- switch (mUiccApplication.getState()) {
+ // Check if SIM is locked
+ boolean cardLocked = false;
+ IccCardConstants.State lockedState = null;
+ IccCardApplicationStatus.AppState appState = mUiccApplication.getState();
+
+ PinState pin1State = mUiccApplication.getPin1State();
+ if (pin1State == PinState.PINSTATE_ENABLED_PERM_BLOCKED) {
+ if (VDBG) log("updateExternalState: PERM_DISABLED");
+ cardLocked = true;
+ lockedState = IccCardConstants.State.PERM_DISABLED;
+ } else {
+ if (appState == IccCardApplicationStatus.AppState.APPSTATE_PIN) {
+ if (VDBG) log("updateExternalState: PIN_REQUIRED");
+ cardLocked = true;
+ lockedState = IccCardConstants.State.PIN_REQUIRED;
+ } else if (appState == IccCardApplicationStatus.AppState.APPSTATE_PUK) {
+ if (VDBG) log("updateExternalState: PUK_REQUIRED");
+ cardLocked = true;
+ lockedState = IccCardConstants.State.PUK_REQUIRED;
+ } else if (appState == IccCardApplicationStatus.AppState.APPSTATE_SUBSCRIPTION_PERSO) {
+ if (mUiccApplication.getPersoSubState()
+ == IccCardApplicationStatus.PersoSubState.PERSOSUBSTATE_SIM_NETWORK) {
+ if (VDBG) log("updateExternalState: PERSOSUBSTATE_SIM_NETWORK");
+ cardLocked = true;
+ lockedState = IccCardConstants.State.NETWORK_LOCKED;
+ }
+ }
+ }
+
+ // If SIM is locked, broadcast state as NOT_READY/LOCKED depending on if records are loaded
+ if (cardLocked) {
+ if (mIccRecords != null && (mIccRecords.getLockedRecordsLoaded()
+ || mIccRecords.getNetworkLockedRecordsLoaded())) { // locked records loaded
+ if (VDBG) {
+ log("updateExternalState: card locked and records loaded; "
+ + "setting state to locked");
+ }
+ setExternalState(lockedState);
+ } else {
+ if (VDBG) {
+ log("updateExternalState: card locked but records not loaded; "
+ + "setting state to NOT_READY");
+ }
+ setExternalState(IccCardConstants.State.NOT_READY);
+ }
+ return;
+ }
+
+ // Check for remaining app states
+ switch (appState) {
case APPSTATE_UNKNOWN:
/*
* APPSTATE_UNKNOWN is a catch-all state reported whenever the app
@@ -377,23 +386,29 @@
* 2) There is no valid App on the SIM to load, which can be the case with an
* eSIM/soft SIM.
*/
- setExternalState(IccCardConstants.State.NOT_READY);
- break;
- case APPSTATE_SUBSCRIPTION_PERSO:
- if (mUiccApplication.getPersoSubState()
- == IccCardApplicationStatus.PersoSubState.PERSOSUBSTATE_SIM_NETWORK) {
- setExternalState(IccCardConstants.State.NETWORK_LOCKED);
+ if (VDBG) {
+ log("updateExternalState: app state is unknown; setting state to NOT_READY");
}
- // Otherwise don't change external SIM state.
+ setExternalState(IccCardConstants.State.NOT_READY);
break;
case APPSTATE_READY:
if (areAllApplicationsReady()) {
if (areAllRecordsLoaded() && areCarrierPriviligeRulesLoaded()) {
+ if (VDBG) log("updateExternalState: setting state to LOADED");
setExternalState(IccCardConstants.State.LOADED);
} else {
+ if (VDBG) {
+ log("updateExternalState: setting state to READY; records loaded "
+ + areAllRecordsLoaded() + ", carrier privilige rules loaded "
+ + areCarrierPriviligeRulesLoaded());
+ }
setExternalState(IccCardConstants.State.READY);
}
} else {
+ if (VDBG) {
+ log("updateExternalState: app state is READY but not for all apps; "
+ + "setting state to NOT_READY");
+ }
setExternalState(IccCardConstants.State.NOT_READY);
}
break;
@@ -444,19 +459,17 @@
}
}
- private void broadcastInternalIccStateChangedIntent(String value, String reason) {
- synchronized (mLock) {
- Intent intent = new Intent(ACTION_INTERNAL_SIM_STATE_CHANGED);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
- | Intent.FLAG_RECEIVER_FOREGROUND);
- intent.putExtra(PhoneConstants.PHONE_NAME_KEY, "Phone");
- intent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, value);
- intent.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, reason);
- intent.putExtra(PhoneConstants.PHONE_KEY, mPhoneId); // SubId may not be valid.
- log("Sending intent ACTION_INTERNAL_SIM_STATE_CHANGED value=" + value
- + " for mPhoneId : " + mPhoneId);
- ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL);
- }
+ static void broadcastInternalIccStateChangedIntent(String value, String reason, int phoneId) {
+ Intent intent = new Intent(ACTION_INTERNAL_SIM_STATE_CHANGED);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
+ | Intent.FLAG_RECEIVER_FOREGROUND);
+ intent.putExtra(PhoneConstants.PHONE_NAME_KEY, "Phone");
+ intent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, value);
+ intent.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, reason);
+ intent.putExtra(PhoneConstants.PHONE_KEY, phoneId); // SubId may not be valid.
+ log("Sending intent ACTION_INTERNAL_SIM_STATE_CHANGED value=" + value
+ + " for mPhoneId : " + phoneId);
+ ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL);
}
private void setExternalState(IccCardConstants.State newState, boolean override) {
@@ -471,41 +484,31 @@
return;
}
mExternalState = newState;
+ if (mExternalState == IccCardConstants.State.LOADED) {
+ // Update the MCC/MNC.
+ if (mIccRecords != null) {
+ String operator = mIccRecords.getOperatorNumeric();
+ log("operator=" + operator + " mPhoneId=" + mPhoneId);
+
+ if (!TextUtils.isEmpty(operator)) {
+ mTelephonyManager.setSimOperatorNumericForPhone(mPhoneId, operator);
+ String countryCode = operator.substring(0, 3);
+ if (countryCode != null) {
+ mTelephonyManager.setSimCountryIsoForPhone(mPhoneId,
+ MccTable.countryCodeForMcc(Integer.parseInt(countryCode)));
+ } else {
+ loge("EVENT_RECORDS_LOADED Country code is null");
+ }
+ } else {
+ loge("EVENT_RECORDS_LOADED Operator name is null");
+ }
+ }
+ }
log("setExternalState: set mPhoneId=" + mPhoneId + " mExternalState=" + mExternalState);
mTelephonyManager.setSimStateForPhone(mPhoneId, getState().toString());
broadcastInternalIccStateChangedIntent(getIccStateIntentString(mExternalState),
- getIccStateReason(mExternalState));
- }
- }
-
- private void processLockedState() {
- synchronized (mLock) {
- if (mUiccApplication == null) {
- //Don't need to do anything if non-existent application is locked
- return;
- }
- PinState pin1State = mUiccApplication.getPin1State();
- if (pin1State == PinState.PINSTATE_ENABLED_PERM_BLOCKED) {
- setExternalState(IccCardConstants.State.PERM_DISABLED);
- return;
- }
-
- IccCardApplicationStatus.AppState appState = mUiccApplication.getState();
- switch (appState) {
- case APPSTATE_PIN:
- setExternalState(IccCardConstants.State.PIN_REQUIRED);
- break;
- case APPSTATE_PUK:
- setExternalState(IccCardConstants.State.PUK_REQUIRED);
- break;
- case APPSTATE_DETECTED:
- case APPSTATE_READY:
- case APPSTATE_SUBSCRIPTION_PERSO:
- case APPSTATE_UNKNOWN:
- // Neither required
- break;
- }
+ getIccStateReason(mExternalState), mPhoneId);
}
}
@@ -1361,7 +1364,7 @@
return null;
}
- private void log(String msg) {
+ private static void log(String msg) {
Rlog.d(LOG_TAG, msg);
}
diff --git a/src/java/com/android/internal/telephony/uicc/UiccSlot.java b/src/java/com/android/internal/telephony/uicc/UiccSlot.java
index 9319b4b..4fabf0b 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccSlot.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccSlot.java
@@ -35,6 +35,7 @@
import com.android.internal.R;
import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.CommandsInterface.RadioState;
+import com.android.internal.telephony.IccCardConstants;
import com.android.internal.telephony.uicc.IccCardStatus.CardState;
import java.io.FileDescriptor;
@@ -59,7 +60,9 @@
private RadioState mLastRadioState = RadioState.RADIO_UNAVAILABLE;
private boolean mIsEuicc;
private String mIccId;
+ private Integer mPhoneId = null;
+ // todo: remove if this is not needed
private RegistrantList mAbsentRegistrants = new RegistrantList();
private static final int EVENT_CARD_REMOVED = 13;
@@ -81,6 +84,7 @@
synchronized (mLock) {
CardState oldState = mCardState;
mCardState = ics.mCardState;
+ mPhoneId = phoneId;
parseAtr(ics.atr);
mCi = ci;
@@ -98,7 +102,8 @@
sendMessage(obtainMessage(EVENT_CARD_REMOVED, null));
}
- // todo: broadcast sim state changed for absent/unknown when IccCardProxy is removed
+ UiccProfile.broadcastInternalIccStateChangedIntent(
+ IccCardConstants.INTENT_VALUE_ICC_ABSENT, null, mPhoneId);
// no card present in the slot now; dispose card and make mUiccCard null
mUiccCard.dispose();
@@ -118,7 +123,7 @@
}
if (!mIsEuicc) {
- mUiccCard = new UiccCard(mContext, mCi, ics, phoneId);
+ mUiccCard = new UiccCard(mContext, mCi, ics, mPhoneId);
} else {
// todo: initialize new EuiccCard object here
//mUiccCard = new EuiccCard();
@@ -144,6 +149,9 @@
mActive = false;
// treat as radio state unavailable
onRadioStateUnavailable();
+ // set mPhoneId to null only after sim state changed broadcast is sent as it
+ // needs the phoneId. The broadcast is sent from onRadioStateUnavailable()
+ mPhoneId = null;
}
parseAtr(iss.atr);
mCardState = iss.cardState;
@@ -304,7 +312,10 @@
}
mUiccCard = null;
- // todo: broadcast sim state changed for absent/unknown when IccCardProxy is removed
+ if (mPhoneId != null) {
+ UiccProfile.broadcastInternalIccStateChangedIntent(
+ IccCardConstants.INTENT_VALUE_ICC_UNKNOWN, null, mPhoneId);
+ }
mCardState = CardState.CARDSTATE_ABSENT;
mLastRadioState = RadioState.RADIO_UNAVAILABLE;
diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
index 41ff61d..443e427 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
@@ -27,6 +27,7 @@
import android.app.ActivityManager;
import android.app.IActivityManager;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.IIntentSender;
import android.content.Intent;
@@ -41,6 +42,7 @@
import android.os.RegistrantList;
import android.os.ServiceManager;
import android.provider.BlockedNumberContract;
+import android.provider.Settings;
import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
@@ -208,7 +210,7 @@
private Object mLock = new Object();
private boolean mReady;
protected HashMap<String, IBinder> mServiceManagerMockedServices = new HashMap<>();
- private Phone[] mPhones = new Phone[] {mPhone};
+ private Phone[] mPhones;
protected HashMap<Integer, ImsManager> mImsManagerInstances = new HashMap<>();
@@ -307,6 +309,7 @@
TAG = tag;
MockitoAnnotations.initMocks(this);
+ mPhones = new Phone[] {mPhone};
mSimulatedCommands = new SimulatedCommands();
mContextFixture = new ContextFixture();
mContext = mContextFixture.getTestDouble();
@@ -459,6 +462,15 @@
//SIM
doReturn(1).when(mTelephonyManager).getSimCount();
+ doReturn(1).when(mTelephonyManager).getPhoneCount();
+
+ //Data
+ //Initial state is: userData enabled, provisioned.
+ ContentResolver resolver = mContext.getContentResolver();
+ Settings.Global.putInt(resolver, Settings.Global.MOBILE_DATA, 1);
+ Settings.Global.putInt(resolver, Settings.Global.DEVICE_PROVISIONED, 1);
+ Settings.Global.putInt(resolver,
+ Settings.Global.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED, 1);
//Use reflection to mock singletons
replaceInstance(CallManager.class, "INSTANCE", null, mCallManager);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
index d733e02..7434abf 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
@@ -1247,12 +1247,7 @@
@Test
@SmallTest
public void testDataEnableInProvisioning() throws Exception {
- // Initial state is: userData enabled, provisioned.
ContentResolver resolver = mContext.getContentResolver();
- Settings.Global.putInt(resolver, Settings.Global.MOBILE_DATA, 1);
- Settings.Global.putInt(resolver, Settings.Global.DEVICE_PROVISIONED, 1);
- Settings.Global.putInt(resolver,
- Settings.Global.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED, 1);
assertEquals(1, Settings.Global.getInt(resolver, Settings.Global.MOBILE_DATA));
assertTrue(mDct.isDataEnabled());
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccProfileTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccProfileTest.java
index 01c807d..bbe2ce9 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccProfileTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccProfileTest.java
@@ -16,7 +16,6 @@
package com.android.internal.telephony.uicc;
import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
@@ -33,7 +32,6 @@
import android.os.Message;
import android.test.suitebuilder.annotation.SmallTest;
-import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.IccCardConstants.State;
import com.android.internal.telephony.TelephonyTest;
import com.android.internal.telephony.cat.CatService;
@@ -52,8 +50,6 @@
}
private IccIoResult mIccIoResult;
- // Must match UiccProfile.EVENT_RADIO_ON
- private static final int EVENT_RADIO_ON = 2;
// Must match UiccProfile.EVENT_APP_READY
private static final int EVENT_APP_READY = 6;
private static final int SCARY_SLEEP_MS = 200;
@@ -254,18 +250,7 @@
@Test
@SmallTest
- public void testPowerOn() {
- mSimulatedCommands.setRadioPower(true, null);
- mUiccProfile.sendMessage(mUiccProfile.obtainMessage(EVENT_RADIO_ON));
- waitForMs(SCARY_SLEEP_MS);
- assertEquals(CommandsInterface.RadioState.RADIO_ON, mSimulatedCommands.getRadioState());
- assertEquals(mUiccProfile.getState(), State.NOT_READY);
- }
-
- @Test
- @SmallTest
public void testUpdateUiccProfileApplicationNotReady() {
- mUiccProfile.sendMessage(mUiccProfile.obtainMessage(EVENT_RADIO_ON));
/* update app status and index */
IccCardApplicationStatus cdmaApp = composeUiccApplicationStatus(
IccCardApplicationStatus.AppType.APPTYPE_CSIM,
@@ -298,7 +283,6 @@
@Test
@SmallTest
public void testUpdateUiccProfileApplicationAllReady() {
- mUiccProfile.sendMessage(mUiccProfile.obtainMessage(EVENT_RADIO_ON));
/* update app status and index */
IccCardApplicationStatus cdmaApp = composeUiccApplicationStatus(
IccCardApplicationStatus.AppType.APPTYPE_CSIM,
@@ -333,21 +317,20 @@
@Test
@SmallTest
public void testUpdateUiccProfileApplicationAllSupportedAppsReady() {
- mUiccProfile.sendMessage(mUiccProfile.obtainMessage(EVENT_RADIO_ON));
/* update app status and index */
- IccCardApplicationStatus cdmaApp = composeUiccApplicationStatus(
- IccCardApplicationStatus.AppType.APPTYPE_CSIM,
- IccCardApplicationStatus.AppState.APPSTATE_READY, "0xA0");
+ IccCardApplicationStatus umtsApp = composeUiccApplicationStatus(
+ IccCardApplicationStatus.AppType.APPTYPE_USIM,
+ IccCardApplicationStatus.AppState.APPSTATE_READY, "0xA2");
IccCardApplicationStatus imsApp = composeUiccApplicationStatus(
IccCardApplicationStatus.AppType.APPTYPE_ISIM,
IccCardApplicationStatus.AppState.APPSTATE_READY, "0xA1");
- IccCardApplicationStatus umtsApp = composeUiccApplicationStatus(
+ IccCardApplicationStatus unknownApp = composeUiccApplicationStatus(
IccCardApplicationStatus.AppType.APPTYPE_UNKNOWN,
IccCardApplicationStatus.AppState.APPSTATE_UNKNOWN, "0xA2");
- mIccCardStatus.mApplications = new IccCardApplicationStatus[]{cdmaApp, imsApp, umtsApp};
- mIccCardStatus.mCdmaSubscriptionAppIndex = 0;
- mIccCardStatus.mImsSubscriptionAppIndex = 1;
- mIccCardStatus.mGsmUmtsSubscriptionAppIndex = 2;
+ mIccCardStatus.mApplications = new IccCardApplicationStatus[]{imsApp, umtsApp, unknownApp};
+ mIccCardStatus.mCdmaSubscriptionAppIndex = -1;
+ mIccCardStatus.mImsSubscriptionAppIndex = 0;
+ mIccCardStatus.mGsmUmtsSubscriptionAppIndex = 1;
Message mProfileUpdate = mHandler.obtainMessage(UICCPROFILE_UPDATE_APPLICATION_EVENT);
setReady(false);
mProfileUpdate.sendToTarget();